From ccdaeb2b176f7db491a6f8e8b1c51f9393525f7d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 27 Feb 2015 09:58:26 +0100 Subject: at86rf230: add support for external xtal trim This patch adds support for setting the xtal trim register. Some at86rf2xx transceiver boards needs fine tuning the xtal capacitor. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt index d3bbdded4cbe..1ae5100fea14 100644 --- a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt +++ b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt @@ -11,6 +11,8 @@ Required properties: Optional properties: - reset-gpio: GPIO spec for the rstn pin - sleep-gpio: GPIO spec for the slp_tr pin + - xtal-trim: u8 value for fine tuning the internal capacitance + arrays of xtal pins: 0 = +0 pF, 0xf = +4.5 pF Example: @@ -20,4 +22,5 @@ Example: reg = <0>; interrupts = <19 1>; interrupt-parent = <&gpio3>; + xtal-trim = /bits/ 8 <0x06>; }; -- cgit v1.2.3 From c91799c50a14137ecee6d60d2f1d9ab8bc895e52 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Fri, 27 Feb 2015 09:58:30 +0100 Subject: at86rf230: add warning if edge-triggered irq While testing I experience a deadlock while using the at86rf233 on a raspberry pi. The reason was an edge triggered gpio irq because the irq triggered while irq was disabled. This issue doesn't happend on a level triggered irq because the irq will hit after calling enable_irq. This patch adds a warning that it's not recommended to use a edge-triggered irq type. Also change the examples to high-level irqtype. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt | 5 +++-- drivers/net/ieee802154/at86rf230.c | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt index 1ae5100fea14..168f1be50912 100644 --- a/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt +++ b/Documentation/devicetree/bindings/net/ieee802154/at86rf230.txt @@ -6,7 +6,8 @@ Required properties: - spi-max-frequency: maximal bus speed, should be set to 7500000 depends sync or async operation mode - reg: the chipselect index - - interrupts: the interrupt generated by the device + - interrupts: the interrupt generated by the device. Non high-level + can occur deadlocks while handling isr. Optional properties: - reset-gpio: GPIO spec for the rstn pin @@ -20,7 +21,7 @@ Example: compatible = "atmel,at86rf231"; spi-max-frequency = <7500000>; reg = <0>; - interrupts = <19 1>; + interrupts = <19 4>; interrupt-parent = <&gpio3>; xtal-trim = /bits/ 8 <0x06>; }; diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index c7a30ce71dcf..1d438bc54189 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1321,6 +1321,10 @@ static int at86rf230_hw_init(struct at86rf230_local *lp, u8 xtal_trim) return rc; irq_type = irq_get_trigger_type(lp->spi->irq); + if (irq_type == IRQ_TYPE_EDGE_RISING || + irq_type == IRQ_TYPE_EDGE_FALLING) + dev_warn(&lp->spi->dev, + "Using edge triggered irq's are not recommended!\n"); if (irq_type == IRQ_TYPE_EDGE_FALLING || irq_type == IRQ_TYPE_LEVEL_LOW) irq_pol = IRQ_ACTIVE_LOW; -- cgit v1.2.3 From fc6c6c2b8a2e1fbaa9e864af62c873dae15420ea Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Sat, 7 Mar 2015 07:37:06 +0100 Subject: net/macb: Update DT bindings documentation Add missing "cdns,at91sam9260-macb", "atmel,sama5d3-gem" and "atmel,sama5d4-gem" compatible strings. Signed-off-by: Boris Brezillon Reviewed-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/macb.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/macb.txt b/Documentation/devicetree/bindings/net/macb.txt index aaa696414f57..ba19d671e808 100644 --- a/Documentation/devicetree/bindings/net/macb.txt +++ b/Documentation/devicetree/bindings/net/macb.txt @@ -2,10 +2,13 @@ Required properties: - compatible: Should be "cdns,[-]{macb|gem}" - Use "cdns,at91sam9260-macb" Atmel at91sam9260 and at91sam9263 SoCs. + Use "cdns,at91sam9260-macb" for Atmel at91sam9 SoCs or the 10/100Mbit IP + available on sama5d3 SoCs. Use "cdns,at32ap7000-macb" for other 10/100 usage or use the generic form: "cdns,macb". Use "cdns,pc302-gem" for Picochip picoXcell pc302 and later devices based on the Cadence GEM, or the generic form: "cdns,gem". + Use "cdns,sama5d3-gem" for the Gigabit IP available on Atmel sama5d3 SoCs. + Use "cdns,sama5d4-gem" for the Gigabit IP available on Atmel sama5d4 SoCs. - reg: Address and length of the register set for the device - interrupts: Should contain macb interrupt - phy-mode: See ethernet.txt file in the same directory. -- cgit v1.2.3 From c2bc6e11bb945e3b10f07bf4b00525ccdc9fc440 Mon Sep 17 00:00:00 2001 From: Keyur Chudgar Date: Tue, 17 Mar 2015 11:27:11 -0700 Subject: Documentation: dtb: Add port-id field for APM X-Gene ethernet Signed-off-by: Keyur Chudgar Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/apm-xgene-enet.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt index 6151999c5dca..dc7961b33076 100644 --- a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt +++ b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt @@ -15,6 +15,7 @@ Required properties for all the ethernet interfaces: - "ring_csr": Descriptor ring control and status register address space - "ring_cmd": Descriptor ring command register address space - interrupts: Ethernet main interrupt +- port-id: Port number (0 or 1) - clocks: Reference to the clock entry. - local-mac-address: MAC address assigned to this device - phy-connection-type: Interface type between ethernet device and PHY device @@ -49,6 +50,7 @@ Example: <0x0 0X10000000 0x0 0X200>; reg-names = "enet_csr", "ring_csr", "ring_cmd"; interrupts = <0x0 0x3c 0x4>; + port-id = <0>; clocks = <&menetclk 0>; local-mac-address = [00 01 73 00 00 01]; phy-connection-type = "rgmii"; -- cgit v1.2.3 From f0b7d43c8a28155f50adb087a563cfc97566e477 Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Tue, 17 Mar 2015 16:25:46 -0400 Subject: cc2520: Add support for CC2591 amplifier. The TI CC2521 is an RF power amplifier that is designed to interface with the CC2520. Conveniently, it directly interfaces with the CC2520 and does not require any pins to be connected to a microcontroller/processor. Adding a CC2591 increases the CC2520's range, which is useful for border router and other wall-powered applications. Using the CC2591 with the CC2520 requires configuring the CC2520 GPIOs that are connected to the CC2591 to correctly set the CC2591 into TX and RX modes. Further, TI recommends that the CC2520_TXPOWER and CC2520_AGCCTRL1 registers are set differently to maximize the CC2591's performance. These settings are covered in TI Application Note AN065. This patch adds an optional `amplified` field to the cc2520 entry in the device tree. If present, the CC2520 will be configured to operate with a CC2591. The expected pin mapping is: CC2520 GPIO0 --> CC2591 EN CC2520 GPIO5 --> CC2591 PAEN Signed-off-by: Brad Campbell Acked-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- .../devicetree/bindings/net/ieee802154/cc2520.txt | 4 ++ drivers/net/ieee802154/cc2520.c | 55 ++++++++++++++++++---- include/linux/spi/cc2520.h | 1 + 3 files changed, 52 insertions(+), 8 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt b/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt index 0071883c08d8..fb6d49f184ed 100644 --- a/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt +++ b/Documentation/devicetree/bindings/net/ieee802154/cc2520.txt @@ -13,11 +13,15 @@ Required properties: - cca-gpio: GPIO spec for the CCA pin - vreg-gpio: GPIO spec for the VREG pin - reset-gpio: GPIO spec for the RESET pin +Optional properties: + - amplified: include if the CC2520 is connected to a CC2591 amplifier + Example: cc2520@0 { compatible = "ti,cc2520"; reg = <0>; spi-max-frequency = <4000000>; + amplified; pinctrl-names = "default"; pinctrl-0 = <&cc2520_cape_pins>; fifo-gpio = <&gpio1 18 0>; diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index 233b6c6017d4..f833b8bb6663 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -738,6 +738,8 @@ static int cc2520_get_platform_data(struct spi_device *spi, pdata->vreg = of_get_named_gpio(np, "vreg-gpio", 0); pdata->reset = of_get_named_gpio(np, "reset-gpio", 0); + pdata->amplified = of_property_read_bool(np, "amplified"); + return 0; } @@ -746,6 +748,11 @@ static int cc2520_hw_init(struct cc2520_private *priv) u8 status = 0, state = 0xff; int ret; int timeout = 100; + struct cc2520_platform_data pdata; + + ret = cc2520_get_platform_data(priv->spi, &pdata); + if (ret) + goto err_ret; ret = cc2520_read_register(priv, CC2520_FSMSTAT1, &state); if (ret) @@ -768,11 +775,47 @@ static int cc2520_hw_init(struct cc2520_private *priv) dev_vdbg(&priv->spi->dev, "oscillator brought up\n"); - /* Registers default value: section 28.1 in Datasheet */ - ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF7); - if (ret) - goto err_ret; + /* If the CC2520 is connected to a CC2591 amplifier, we must both + * configure GPIOs on the CC2520 to correctly configure the CC2591 + * and change a couple settings of the CC2520 to work with the + * amplifier. See section 8 page 17 of TI application note AN065. + * http://www.ti.com/lit/an/swra229a/swra229a.pdf + */ + if (pdata.amplified) { + ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF9); + if (ret) + goto err_ret; + ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x16); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_GPIOCTRL0, 0x46); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_GPIOCTRL5, 0x47); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_GPIOPOLARITY, 0x1e); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_TXCTRL, 0xc1); + if (ret) + goto err_ret; + } else { + ret = cc2520_write_register(priv, CC2520_TXPOWER, 0xF7); + if (ret) + goto err_ret; + + ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11); + if (ret) + goto err_ret; + } + + /* Registers default value: section 28.1 in Datasheet */ ret = cc2520_write_register(priv, CC2520_CCACTRL0, 0x1A); if (ret) goto err_ret; @@ -797,10 +840,6 @@ static int cc2520_hw_init(struct cc2520_private *priv) if (ret) goto err_ret; - ret = cc2520_write_register(priv, CC2520_AGCCTRL1, 0x11); - if (ret) - goto err_ret; - ret = cc2520_write_register(priv, CC2520_ADCTEST0, 0x10); if (ret) goto err_ret; diff --git a/include/linux/spi/cc2520.h b/include/linux/spi/cc2520.h index 85b8ee67e937..e741e8baad92 100644 --- a/include/linux/spi/cc2520.h +++ b/include/linux/spi/cc2520.h @@ -21,6 +21,7 @@ struct cc2520_platform_data { int sfd; int reset; int vreg; + bool amplified; }; #endif -- cgit v1.2.3 From 21e0e0ddda5be2905ca163cab2da5bb1880a790c Mon Sep 17 00:00:00 2001 From: "Karicheri, Muralidharan" Date: Fri, 20 Mar 2015 16:11:22 -0400 Subject: net: netcp: use separate reg region for individual ethss modules Ethss has multiple modules within the sub system - switch sub system - sgmii - mdio - switch module NetCP driver re-uses existing davinci mdio driver. It requires to have its own register region to map the reg space. So restructure the code to use separate reg region for the individual modules it manages. Use range property to define register space of NetCP and use reg property to define individual reg spaces. So MDIO will have its own reg space to map. This is a pre-requisite to enable MDIO driver for NetCP. Signed-off-by: Murali Karicheri Signed-off-by: WingMan Kwok CC: "David S. Miller" CC: Mugunthan V N CC: "Lad, Prabhakar" CC: Grygorii Strashko CC: Christoph Jaeger CC: Lokesh Vutla CC: Markus Pargmann CC: Kumar Gala CC: Ian Campbell CC: Mark Rutland CC: Pawel Moll CC: Rob Herring Signed-off-by: David S. Miller --- .../devicetree/bindings/net/keystone-netcp.txt | 16 +-- drivers/net/ethernet/ti/netcp_ethss.c | 130 +++++++++++++++------ 2 files changed, 102 insertions(+), 44 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/keystone-netcp.txt b/Documentation/devicetree/bindings/net/keystone-netcp.txt index f9c07710478d..8368abdd5a34 100644 --- a/Documentation/devicetree/bindings/net/keystone-netcp.txt +++ b/Documentation/devicetree/bindings/net/keystone-netcp.txt @@ -49,6 +49,7 @@ Required properties: - compatible: Should be "ti,netcp-1.0" - clocks: phandle to the reference clocks for the subsystem. - dma-id: Navigator packet dma instance id. +- ranges: address range of NetCP (includes, Ethernet SS, PA and SA) Optional properties: - reg: register location and the size for the following register @@ -66,8 +67,10 @@ Required properties: - label: Must be "netcp-gbe" for 1Gb & "netcp-xgbe" for 10Gb. - reg: register location and the size for the following register regions in the specified order. - - subsystem registers - - serdes registers + - switch subsystem registers + - sgmii port3/4 module registers (only for NetCP 1.4) + - switch module registers + - serdes registers (only for 10G) - tx-channel: the navigator packet dma channel name for tx. - tx-queue: the navigator queue number associated with the tx dma channel. - interfaces: specification for each of the switch port to be registered as a @@ -120,14 +123,13 @@ Optional properties: Example binding: -netcp: netcp@2090000 { +netcp: netcp@2000000 { reg = <0x2620110 0x8>; reg-names = "efuse"; compatible = "ti,netcp-1.0"; #address-cells = <1>; #size-cells = <1>; - ranges; - + ranges = <0 0x2000000 0xfffff>; clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>; dma-coherent; /* big-endian; */ @@ -137,9 +139,9 @@ netcp: netcp@2090000 { #address-cells = <1>; #size-cells = <1>; ranges; - gbe@0x2090000 { + gbe@90000 { label = "netcp-gbe"; - reg = <0x2090000 0xf00>; + reg = <0x90000 0x300>, <0x90400 0x400>, <0x90800 0x700>; /* enable-ale; */ tx-queue = <648>; tx-channel = <8>; diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 2be90a57b595..42592b8fc344 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -40,15 +40,18 @@ #define GBE_MODULE_NAME "netcp-gbe" #define GBE_SS_VERSION_14 0x4ed21104 +#define GBE_SS_REG_INDEX 0 +#define GBE_SGMII34_REG_INDEX 1 +#define GBE_SM_REG_INDEX 2 +/* offset relative to base of GBE_SS_REG_INDEX */ #define GBE13_SGMII_MODULE_OFFSET 0x100 -#define GBE13_SGMII34_MODULE_OFFSET 0x400 -#define GBE13_SWITCH_MODULE_OFFSET 0x800 -#define GBE13_HOST_PORT_OFFSET 0x834 -#define GBE13_SLAVE_PORT_OFFSET 0x860 -#define GBE13_EMAC_OFFSET 0x900 -#define GBE13_SLAVE_PORT2_OFFSET 0xa00 -#define GBE13_HW_STATS_OFFSET 0xb00 -#define GBE13_ALE_OFFSET 0xe00 +/* offset relative to base of GBE_SM_REG_INDEX */ +#define GBE13_HOST_PORT_OFFSET 0x34 +#define GBE13_SLAVE_PORT_OFFSET 0x60 +#define GBE13_EMAC_OFFSET 0x100 +#define GBE13_SLAVE_PORT2_OFFSET 0x200 +#define GBE13_HW_STATS_OFFSET 0x300 +#define GBE13_ALE_OFFSET 0x600 #define GBE13_HOST_PORT_NUM 0 #define GBE13_NUM_SLAVES 4 #define GBE13_NUM_ALE_PORTS (GBE13_NUM_SLAVES + 1) @@ -58,14 +61,18 @@ #define XGBE_MODULE_NAME "netcp-xgbe" #define XGBE_SS_VERSION_10 0x4ee42100 -#define XGBE_SERDES_REG_INDEX 1 +#define XGBE_SS_REG_INDEX 0 +#define XGBE_SM_REG_INDEX 1 +#define XGBE_SERDES_REG_INDEX 2 + +/* offset relative to base of XGBE_SS_REG_INDEX */ #define XGBE10_SGMII_MODULE_OFFSET 0x100 -#define XGBE10_SWITCH_MODULE_OFFSET 0x1000 -#define XGBE10_HOST_PORT_OFFSET 0x1034 -#define XGBE10_SLAVE_PORT_OFFSET 0x1064 -#define XGBE10_EMAC_OFFSET 0x1400 -#define XGBE10_ALE_OFFSET 0x1700 -#define XGBE10_HW_STATS_OFFSET 0x1800 +/* offset relative to base of XGBE_SM_REG_INDEX */ +#define XGBE10_HOST_PORT_OFFSET 0x34 +#define XGBE10_SLAVE_PORT_OFFSET 0x64 +#define XGBE10_EMAC_OFFSET 0x400 +#define XGBE10_ALE_OFFSET 0x700 +#define XGBE10_HW_STATS_OFFSET 0x800 #define XGBE10_HOST_PORT_NUM 0 #define XGBE10_NUM_SLAVES 2 #define XGBE10_NUM_ALE_PORTS (XGBE10_NUM_SLAVES + 1) @@ -1579,9 +1586,9 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) emac_reg_ofs = XGBE10_EMAC_OFFSET; - slave->port_regs = gbe_dev->ss_regs + port_reg_ofs + + slave->port_regs = gbe_dev->switch_regs + port_reg_ofs + (0x30 * port_reg_num); - slave->emac_regs = gbe_dev->ss_regs + emac_reg_ofs + + slave->emac_regs = gbe_dev->switch_regs + emac_reg_ofs + (0x40 * slave->slave_num); if (gbe_dev->ss_version == GBE_SS_VERSION_14) { @@ -1732,22 +1739,39 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, ret = of_address_to_resource(node, 0, &res); if (ret) { - dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe subsystem regs\n", - node->name); + dev_err(gbe_dev->dev, + "Can't xlate xgbe of node(%s) ss address at %d\n", + node->name, XGBE_SS_REG_INDEX); return ret; } regs = devm_ioremap_resource(gbe_dev->dev, &res); if (IS_ERR(regs)) { - dev_err(gbe_dev->dev, "Failed to map xgbe register base\n"); + dev_err(gbe_dev->dev, "Failed to map xgbe ss register base\n"); return PTR_ERR(regs); } gbe_dev->ss_regs = regs; + ret = of_address_to_resource(node, XGBE_SM_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, + "Can't xlate xgbe of node(%s) sm address at %d\n", + node->name, XGBE_SM_REG_INDEX); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, "Failed to map xgbe sm register base\n"); + return PTR_ERR(regs); + } + gbe_dev->switch_regs = regs; + ret = of_address_to_resource(node, XGBE_SERDES_REG_INDEX, &res); if (ret) { - dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe serdes regs\n", - node->name); + dev_err(gbe_dev->dev, + "Can't xlate xgbe serdes of node(%s) address at %d\n", + node->name, XGBE_SERDES_REG_INDEX); return ret; } @@ -1770,11 +1794,10 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, gbe_dev->ss_version = XGBE_SS_VERSION_10; gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + XGBE10_SGMII_MODULE_OFFSET; - gbe_dev->switch_regs = gbe_dev->ss_regs + XGBE10_SWITCH_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->ss_regs + XGBE10_HOST_PORT_OFFSET; for (i = 0; i < XGBE10_NUM_HW_STATS_MOD; i++) - gbe_dev->hw_stats_regs[i] = gbe_dev->ss_regs + + gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i); gbe_dev->ale_reg = gbe_dev->ss_regs + XGBE10_ALE_OFFSET; @@ -1809,10 +1832,11 @@ static int get_gbe_resource_version(struct gbe_priv *gbe_dev, void __iomem *regs; int ret; - ret = of_address_to_resource(node, 0, &res); + ret = of_address_to_resource(node, GBE_SS_REG_INDEX, &res); if (ret) { - dev_err(gbe_dev->dev, "Can't translate of node(%s) address\n", - node->name); + dev_err(gbe_dev->dev, + "Can't translate of node(%s) of gbe ss address at %d\n", + node->name, GBE_SS_REG_INDEX); return ret; } @@ -1829,8 +1853,41 @@ static int get_gbe_resource_version(struct gbe_priv *gbe_dev, static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, struct device_node *node) { + struct resource res; void __iomem *regs; - int i; + int i, ret; + + ret = of_address_to_resource(node, GBE_SGMII34_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, + "Can't translate of gbe node(%s) address at index %d\n", + node->name, GBE_SGMII34_REG_INDEX); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, + "Failed to map gbe sgmii port34 register base\n"); + return PTR_ERR(regs); + } + gbe_dev->sgmii_port34_regs = regs; + + ret = of_address_to_resource(node, GBE_SM_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, + "Can't translate of gbe node(%s) address at index %d\n", + node->name, GBE_SM_REG_INDEX); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, + "Failed to map gbe switch module register base\n"); + return PTR_ERR(regs); + } + gbe_dev->switch_regs = regs; gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, GBE13_NUM_HW_STAT_ENTRIES * @@ -1841,17 +1898,16 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, return -ENOMEM; } - regs = gbe_dev->ss_regs; - gbe_dev->sgmii_port_regs = regs + GBE13_SGMII_MODULE_OFFSET; - gbe_dev->sgmii_port34_regs = regs + GBE13_SGMII34_MODULE_OFFSET; - gbe_dev->switch_regs = regs + GBE13_SWITCH_MODULE_OFFSET; - gbe_dev->host_port_regs = regs + GBE13_HOST_PORT_OFFSET; + gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBE13_SGMII_MODULE_OFFSET; + gbe_dev->host_port_regs = gbe_dev->switch_regs + GBE13_HOST_PORT_OFFSET; - for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++) - gbe_dev->hw_stats_regs[i] = regs + GBE13_HW_STATS_OFFSET + - (GBE_HW_STATS_REG_MAP_SZ * i); + for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++) { + gbe_dev->hw_stats_regs[i] = + gbe_dev->switch_regs + GBE13_HW_STATS_OFFSET + + (GBE_HW_STATS_REG_MAP_SZ * i); + } - gbe_dev->ale_reg = regs + GBE13_ALE_OFFSET; + gbe_dev->ale_reg = gbe_dev->switch_regs + GBE13_ALE_OFFSET; gbe_dev->ale_ports = GBE13_NUM_ALE_PORTS; gbe_dev->host_port = GBE13_HOST_PORT_NUM; gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; -- cgit v1.2.3 From 9a391c7ba7dcfc64754140ce13d5fc55d149531a Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Fri, 20 Mar 2015 16:11:25 -0400 Subject: net: netcp: ethss: enhancement to support NetCP 1.5 ethss NetCP 1.5 available on newer K2 SoCs such as K2E and K2L introduced 3 variants of the ethss subsystem, 9 port, 5 port and 2 port. These have one host port towards the CPU and N external slave ports. To customize the driver for these new ethss sub systems, multiple compatibility strings are introduced. Currently some of parameters that are different on different variants such as number of ALE ports, stats modules and number of ports are defined through constants. These are now changed to variables in gbe_priv data that get set based on the compatibility string. This is required as there are no hardware identification registers available to distinguish among the variants of NetCP 1.5 ethss. However there is identification register available to differentiate between NetCP 1.4 vs NetCP 1.5 and the same is made use of in the code to differentiate them. For more reading on the details of this peripheral, please refer to the User Guide available at http://www.ti.com/lit/pdf/spruhz3 Signed-off-by: Murali Karicheri Signed-off-by: WingMan Kwok CC: "David S. Miller" CC: Mugunthan V N CC: "Lad, Prabhakar" CC: Grygorii Strashko CC: Christoph Jaeger CC: Lokesh Vutla CC: Markus Pargmann CC: Kumar Gala CC: Ian Campbell CC: Mark Rutland CC: Pawel Moll CC: Rob Herring Signed-off-by: David S. Miller --- .../devicetree/bindings/net/keystone-netcp.txt | 18 + drivers/net/ethernet/ti/netcp_ethss.c | 920 ++++++++++++++++++++- 2 files changed, 902 insertions(+), 36 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/keystone-netcp.txt b/Documentation/devicetree/bindings/net/keystone-netcp.txt index 8368abdd5a34..d0e6fa38f335 100644 --- a/Documentation/devicetree/bindings/net/keystone-netcp.txt +++ b/Documentation/devicetree/bindings/net/keystone-netcp.txt @@ -65,12 +65,30 @@ NetCP device properties: Device specification for NetCP sub-modules. 1Gb/10Gb (gbe/xgbe) ethernet switch sub-module specifications. Required properties: - label: Must be "netcp-gbe" for 1Gb & "netcp-xgbe" for 10Gb. +- compatible: Must be one of below:- + "ti,netcp-gbe" for 1GbE on NetCP 1.4 + "ti,netcp-gbe-5" for 1GbE N NetCP 1.5 (N=5) + "ti,netcp-gbe-9" for 1GbE N NetCP 1.5 (N=9) + "ti,netcp-gbe-2" for 1GbE N NetCP 1.5 (N=2) + "ti,netcp-xgbe" for 10 GbE + - reg: register location and the size for the following register regions in the specified order. - switch subsystem registers - sgmii port3/4 module registers (only for NetCP 1.4) - switch module registers - serdes registers (only for 10G) + + NetCP 1.4 ethss, here is the order + index #0 - switch subsystem registers + index #1 - sgmii port3/4 module registers + index #2 - switch module registers + + NetCP 1.5 ethss 9 port, 5 port and 2 port + index #0 - switch subsystem registers + index #1 - switch module registers + index #2 - serdes registers + - tx-channel: the navigator packet dma channel name for tx. - tx-queue: the navigator queue number associated with the tx dma channel. - interfaces: specification for each of the switch port to be registered as a diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index f8f3be3fd59f..2bef655279f3 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -53,10 +53,31 @@ #define GBE13_HW_STATS_OFFSET 0x300 #define GBE13_ALE_OFFSET 0x600 #define GBE13_HOST_PORT_NUM 0 -#define GBE13_NUM_SLAVES 4 -#define GBE13_NUM_ALE_PORTS (GBE13_NUM_SLAVES + 1) #define GBE13_NUM_ALE_ENTRIES 1024 +/* 1G Ethernet NU SS defines */ +#define GBENU_MODULE_NAME "netcp-gbenu" +#define GBE_SS_ID_NU 0x4ee6 +#define GBE_SS_ID_2U 0x4ee8 + +#define IS_SS_ID_MU(d) \ + ((GBE_IDENT((d)->ss_version) == GBE_SS_ID_NU) || \ + (GBE_IDENT((d)->ss_version) == GBE_SS_ID_2U)) + +#define IS_SS_ID_NU(d) \ + (GBE_IDENT((d)->ss_version) == GBE_SS_ID_NU) + +#define GBENU_SS_REG_INDEX 0 +#define GBENU_SM_REG_INDEX 1 +#define GBENU_SGMII_MODULE_OFFSET 0x100 +#define GBENU_HOST_PORT_OFFSET 0x1000 +#define GBENU_SLAVE_PORT_OFFSET 0x2000 +#define GBENU_EMAC_OFFSET 0x2330 +#define GBENU_HW_STATS_OFFSET 0x1a000 +#define GBENU_ALE_OFFSET 0x1e000 +#define GBENU_HOST_PORT_NUM 0 +#define GBENU_NUM_ALE_ENTRIES 1024 + /* 10G Ethernet SS defines */ #define XGBE_MODULE_NAME "netcp-xgbe" #define XGBE_SS_VERSION_10 0x4ee42100 @@ -74,8 +95,6 @@ #define XGBE10_ALE_OFFSET 0x700 #define XGBE10_HW_STATS_OFFSET 0x800 #define XGBE10_HOST_PORT_NUM 0 -#define XGBE10_NUM_SLAVES 2 -#define XGBE10_NUM_ALE_PORTS (XGBE10_NUM_SLAVES + 1) #define XGBE10_NUM_ALE_ENTRIES 1024 #define GBE_TIMER_INTERVAL (HZ / 2) @@ -95,7 +114,7 @@ #define MACSL_FULLDUPLEX BIT(0) #define GBE_CTL_P0_ENABLE BIT(2) -#define GBE_REG_VAL_STAT_ENABLE_ALL 0xff +#define GBE13_REG_VAL_STAT_ENABLE_ALL 0xff #define XGBE_REG_VAL_STAT_ENABLE_ALL 0xf #define GBE_STATS_CD_SEL BIT(28) @@ -115,11 +134,20 @@ #define GBE_STATSC_MODULE 2 #define GBE_STATSD_MODULE 3 +#define GBENU_STATS0_MODULE 0 +#define GBENU_STATS1_MODULE 1 +#define GBENU_STATS2_MODULE 2 +#define GBENU_STATS3_MODULE 3 +#define GBENU_STATS4_MODULE 4 +#define GBENU_STATS5_MODULE 5 +#define GBENU_STATS6_MODULE 6 +#define GBENU_STATS7_MODULE 7 +#define GBENU_STATS8_MODULE 8 + #define XGBE_STATS0_MODULE 0 #define XGBE_STATS1_MODULE 1 #define XGBE_STATS2_MODULE 2 -#define MAX_SLAVES GBE13_NUM_SLAVES /* s: 0-based slave_port */ #define SGMII_BASE(s) \ (((s) < 2) ? gbe_dev->sgmii_port_regs : gbe_dev->sgmii_port34_regs) @@ -132,10 +160,14 @@ #define GBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ offsetof(struct gbe##_##rb, rn) +#define GBENU_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ + offsetof(struct gbenu##_##rb, rn) #define XGBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \ offsetof(struct xgbe##_##rb, rn) #define GBE_REG_ADDR(p, rb, rn) (p->rb + p->rb##_ofs.rn) +#define HOST_TX_PRI_MAP_DEFAULT 0x00000000 + struct xgbe_ss_regs { u32 id_ver; u32 synce_count; @@ -265,6 +297,192 @@ struct xgbe_hw_stats { #define XGBE10_NUM_STAT_ENTRIES (sizeof(struct xgbe_hw_stats)/sizeof(u32)) +struct gbenu_ss_regs { + u32 id_ver; + u32 synce_count; /* NU */ + u32 synce_mux; /* NU */ + u32 control; /* 2U */ + u32 __rsvd_0[2]; /* 2U */ + u32 rgmii_status; /* 2U */ + u32 ss_status; /* 2U */ +}; + +struct gbenu_switch_regs { + u32 id_ver; + u32 control; + u32 __rsvd_0[2]; + u32 emcontrol; + u32 stat_port_en; + u32 ptype; /* NU */ + u32 soft_idle; + u32 thru_rate; /* NU */ + u32 gap_thresh; /* NU */ + u32 tx_start_wds; /* NU */ + u32 eee_prescale; /* 2U */ + u32 tx_g_oflow_thresh_set; /* NU */ + u32 tx_g_oflow_thresh_clr; /* NU */ + u32 tx_g_buf_thresh_set_l; /* NU */ + u32 tx_g_buf_thresh_set_h; /* NU */ + u32 tx_g_buf_thresh_clr_l; /* NU */ + u32 tx_g_buf_thresh_clr_h; /* NU */ +}; + +struct gbenu_port_regs { + u32 __rsvd_0; + u32 control; + u32 max_blks; /* 2U */ + u32 mem_align1; + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; /* NU */ + u32 pri_ctl; /* 2U */ + u32 rx_pri_map; + u32 rx_maxlen; + u32 tx_blks_pri; /* NU */ + u32 __rsvd_1; + u32 idle2lpi; /* 2U */ + u32 lpi2idle; /* 2U */ + u32 eee_status; /* 2U */ + u32 __rsvd_2; + u32 __rsvd_3[176]; /* NU: more to add */ + u32 __rsvd_4[2]; + u32 sa_lo; + u32 sa_hi; + u32 ts_ctl; + u32 ts_seq_ltype; + u32 ts_vlan; + u32 ts_ctl_ltype2; + u32 ts_ctl2; +}; + +struct gbenu_host_port_regs { + u32 __rsvd_0; + u32 control; + u32 flow_id_offset; /* 2U */ + u32 __rsvd_1; + u32 blk_cnt; + u32 port_vlan; + u32 tx_pri_map; /* NU */ + u32 pri_ctl; + u32 rx_pri_map; + u32 rx_maxlen; + u32 tx_blks_pri; /* NU */ + u32 __rsvd_2; + u32 idle2lpi; /* 2U */ + u32 lpi2wake; /* 2U */ + u32 eee_status; /* 2U */ + u32 __rsvd_3; + u32 __rsvd_4[184]; /* NU */ + u32 host_blks_pri; /* NU */ +}; + +struct gbenu_emac_regs { + u32 mac_control; + u32 mac_status; + u32 soft_reset; + u32 boff_test; + u32 rx_pause; + u32 __rsvd_0[11]; /* NU */ + u32 tx_pause; + u32 __rsvd_1[11]; /* NU */ + u32 em_control; + u32 tx_gap; +}; + +/* Some hw stat regs are applicable to slave port only. + * This is handled by gbenu_et_stats struct. Also some + * are for SS version NU and some are for 2U. + */ +struct gbenu_hw_stats { + u32 rx_good_frames; + u32 rx_broadcast_frames; + u32 rx_multicast_frames; + u32 rx_pause_frames; /* slave */ + u32 rx_crc_errors; + u32 rx_align_code_errors; /* slave */ + u32 rx_oversized_frames; + u32 rx_jabber_frames; /* slave */ + u32 rx_undersized_frames; + u32 rx_fragments; /* slave */ + u32 ale_drop; + u32 ale_overrun_drop; + u32 rx_bytes; + u32 tx_good_frames; + u32 tx_broadcast_frames; + u32 tx_multicast_frames; + u32 tx_pause_frames; /* slave */ + u32 tx_deferred_frames; /* slave */ + u32 tx_collision_frames; /* slave */ + u32 tx_single_coll_frames; /* slave */ + u32 tx_mult_coll_frames; /* slave */ + u32 tx_excessive_collisions; /* slave */ + u32 tx_late_collisions; /* slave */ + u32 rx_ipg_error; /* slave 10G only */ + u32 tx_carrier_sense_errors; /* slave */ + u32 tx_bytes; + u32 tx_64B_frames; + u32 tx_65_to_127B_frames; + u32 tx_128_to_255B_frames; + u32 tx_256_to_511B_frames; + u32 tx_512_to_1023B_frames; + u32 tx_1024B_frames; + u32 net_bytes; + u32 rx_bottom_fifo_drop; + u32 rx_port_mask_drop; + u32 rx_top_fifo_drop; + u32 ale_rate_limit_drop; + u32 ale_vid_ingress_drop; + u32 ale_da_eq_sa_drop; + u32 __rsvd_0[3]; + u32 ale_unknown_ucast; + u32 ale_unknown_ucast_bytes; + u32 ale_unknown_mcast; + u32 ale_unknown_mcast_bytes; + u32 ale_unknown_bcast; + u32 ale_unknown_bcast_bytes; + u32 ale_pol_match; + u32 ale_pol_match_red; /* NU */ + u32 ale_pol_match_yellow; /* NU */ + u32 __rsvd_1[44]; + u32 tx_mem_protect_err; + /* following NU only */ + u32 tx_pri0; + u32 tx_pri1; + u32 tx_pri2; + u32 tx_pri3; + u32 tx_pri4; + u32 tx_pri5; + u32 tx_pri6; + u32 tx_pri7; + u32 tx_pri0_bcnt; + u32 tx_pri1_bcnt; + u32 tx_pri2_bcnt; + u32 tx_pri3_bcnt; + u32 tx_pri4_bcnt; + u32 tx_pri5_bcnt; + u32 tx_pri6_bcnt; + u32 tx_pri7_bcnt; + u32 tx_pri0_drop; + u32 tx_pri1_drop; + u32 tx_pri2_drop; + u32 tx_pri3_drop; + u32 tx_pri4_drop; + u32 tx_pri5_drop; + u32 tx_pri6_drop; + u32 tx_pri7_drop; + u32 tx_pri0_drop_bcnt; + u32 tx_pri1_drop_bcnt; + u32 tx_pri2_drop_bcnt; + u32 tx_pri3_drop_bcnt; + u32 tx_pri4_drop_bcnt; + u32 tx_pri5_drop_bcnt; + u32 tx_pri6_drop_bcnt; + u32 tx_pri7_drop_bcnt; +}; + +#define GBENU_NUM_HW_STAT_ENTRIES (sizeof(struct gbenu_hw_stats) / sizeof(u32)) +#define GBENU_HW_STATS_REG_MAP_SZ 0x200 + struct gbe_ss_regs { u32 id_ver; u32 synce_count; @@ -323,6 +541,7 @@ struct gbe_port_regs_ofs { u16 ts_vlan; u16 ts_ctl_ltype2; u16 ts_ctl2; + u16 rx_maxlen; /* 2U, NU */ }; struct gbe_host_port_regs { @@ -397,9 +616,7 @@ struct gbe_hw_stats { }; #define GBE13_NUM_HW_STAT_ENTRIES (sizeof(struct gbe_hw_stats)/sizeof(u32)) -#define GBE13_NUM_HW_STATS_MOD 2 -#define XGBE10_NUM_HW_STATS_MOD 3 -#define GBE_MAX_HW_STAT_MODS 3 +#define GBE_MAX_HW_STAT_MODS 9 #define GBE_HW_STATS_REG_MAP_SZ 0x100 struct gbe_slave { @@ -427,11 +644,14 @@ struct gbe_priv { u32 ale_entries; u32 ale_ports; bool enable_ale; + u8 max_num_slaves; + u8 max_num_ports; /* max_num_slaves + 1 */ struct netcp_tx_pipe tx_pipe; int host_port; u32 rx_packet_max; u32 ss_version; + u32 stats_en_mask; void __iomem *ss_regs; void __iomem *switch_regs; @@ -653,6 +873,488 @@ static const struct netcp_ethtool_stat gbe13_et_stats[] = { GBE_STATSD_INFO(rx_dma_overruns), }; +/* This is the size of entries in GBENU_STATS_HOST */ +#define GBENU_ET_STATS_HOST_SIZE 33 + +#define GBENU_STATS_HOST(field) \ +{ \ + "GBE_HOST:"#field, GBENU_STATS0_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +/* This is the size of entries in GBENU_STATS_HOST */ +#define GBENU_ET_STATS_PORT_SIZE 46 + +#define GBENU_STATS_P1(field) \ +{ \ + "GBE_P1:"#field, GBENU_STATS1_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P2(field) \ +{ \ + "GBE_P2:"#field, GBENU_STATS2_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P3(field) \ +{ \ + "GBE_P3:"#field, GBENU_STATS3_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P4(field) \ +{ \ + "GBE_P4:"#field, GBENU_STATS4_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P5(field) \ +{ \ + "GBE_P5:"#field, GBENU_STATS5_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P6(field) \ +{ \ + "GBE_P6:"#field, GBENU_STATS6_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P7(field) \ +{ \ + "GBE_P7:"#field, GBENU_STATS7_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +#define GBENU_STATS_P8(field) \ +{ \ + "GBE_P8:"#field, GBENU_STATS8_MODULE, \ + FIELD_SIZEOF(struct gbenu_hw_stats, field), \ + offsetof(struct gbenu_hw_stats, field) \ +} + +static const struct netcp_ethtool_stat gbenu_et_stats[] = { + /* GBENU Host Module */ + GBENU_STATS_HOST(rx_good_frames), + GBENU_STATS_HOST(rx_broadcast_frames), + GBENU_STATS_HOST(rx_multicast_frames), + GBENU_STATS_HOST(rx_crc_errors), + GBENU_STATS_HOST(rx_oversized_frames), + GBENU_STATS_HOST(rx_undersized_frames), + GBENU_STATS_HOST(ale_drop), + GBENU_STATS_HOST(ale_overrun_drop), + GBENU_STATS_HOST(rx_bytes), + GBENU_STATS_HOST(tx_good_frames), + GBENU_STATS_HOST(tx_broadcast_frames), + GBENU_STATS_HOST(tx_multicast_frames), + GBENU_STATS_HOST(tx_bytes), + GBENU_STATS_HOST(tx_64B_frames), + GBENU_STATS_HOST(tx_65_to_127B_frames), + GBENU_STATS_HOST(tx_128_to_255B_frames), + GBENU_STATS_HOST(tx_256_to_511B_frames), + GBENU_STATS_HOST(tx_512_to_1023B_frames), + GBENU_STATS_HOST(tx_1024B_frames), + GBENU_STATS_HOST(net_bytes), + GBENU_STATS_HOST(rx_bottom_fifo_drop), + GBENU_STATS_HOST(rx_port_mask_drop), + GBENU_STATS_HOST(rx_top_fifo_drop), + GBENU_STATS_HOST(ale_rate_limit_drop), + GBENU_STATS_HOST(ale_vid_ingress_drop), + GBENU_STATS_HOST(ale_da_eq_sa_drop), + GBENU_STATS_HOST(ale_unknown_ucast), + GBENU_STATS_HOST(ale_unknown_ucast_bytes), + GBENU_STATS_HOST(ale_unknown_mcast), + GBENU_STATS_HOST(ale_unknown_mcast_bytes), + GBENU_STATS_HOST(ale_unknown_bcast), + GBENU_STATS_HOST(ale_unknown_bcast_bytes), + GBENU_STATS_HOST(tx_mem_protect_err), + /* GBENU Module 1 */ + GBENU_STATS_P1(rx_good_frames), + GBENU_STATS_P1(rx_broadcast_frames), + GBENU_STATS_P1(rx_multicast_frames), + GBENU_STATS_P1(rx_pause_frames), + GBENU_STATS_P1(rx_crc_errors), + GBENU_STATS_P1(rx_align_code_errors), + GBENU_STATS_P1(rx_oversized_frames), + GBENU_STATS_P1(rx_jabber_frames), + GBENU_STATS_P1(rx_undersized_frames), + GBENU_STATS_P1(rx_fragments), + GBENU_STATS_P1(ale_drop), + GBENU_STATS_P1(ale_overrun_drop), + GBENU_STATS_P1(rx_bytes), + GBENU_STATS_P1(tx_good_frames), + GBENU_STATS_P1(tx_broadcast_frames), + GBENU_STATS_P1(tx_multicast_frames), + GBENU_STATS_P1(tx_pause_frames), + GBENU_STATS_P1(tx_deferred_frames), + GBENU_STATS_P1(tx_collision_frames), + GBENU_STATS_P1(tx_single_coll_frames), + GBENU_STATS_P1(tx_mult_coll_frames), + GBENU_STATS_P1(tx_excessive_collisions), + GBENU_STATS_P1(tx_late_collisions), + GBENU_STATS_P1(rx_ipg_error), + GBENU_STATS_P1(tx_carrier_sense_errors), + GBENU_STATS_P1(tx_bytes), + GBENU_STATS_P1(tx_64B_frames), + GBENU_STATS_P1(tx_65_to_127B_frames), + GBENU_STATS_P1(tx_128_to_255B_frames), + GBENU_STATS_P1(tx_256_to_511B_frames), + GBENU_STATS_P1(tx_512_to_1023B_frames), + GBENU_STATS_P1(tx_1024B_frames), + GBENU_STATS_P1(net_bytes), + GBENU_STATS_P1(rx_bottom_fifo_drop), + GBENU_STATS_P1(rx_port_mask_drop), + GBENU_STATS_P1(rx_top_fifo_drop), + GBENU_STATS_P1(ale_rate_limit_drop), + GBENU_STATS_P1(ale_vid_ingress_drop), + GBENU_STATS_P1(ale_da_eq_sa_drop), + GBENU_STATS_P1(ale_unknown_ucast), + GBENU_STATS_P1(ale_unknown_ucast_bytes), + GBENU_STATS_P1(ale_unknown_mcast), + GBENU_STATS_P1(ale_unknown_mcast_bytes), + GBENU_STATS_P1(ale_unknown_bcast), + GBENU_STATS_P1(ale_unknown_bcast_bytes), + GBENU_STATS_P1(tx_mem_protect_err), + /* GBENU Module 2 */ + GBENU_STATS_P2(rx_good_frames), + GBENU_STATS_P2(rx_broadcast_frames), + GBENU_STATS_P2(rx_multicast_frames), + GBENU_STATS_P2(rx_pause_frames), + GBENU_STATS_P2(rx_crc_errors), + GBENU_STATS_P2(rx_align_code_errors), + GBENU_STATS_P2(rx_oversized_frames), + GBENU_STATS_P2(rx_jabber_frames), + GBENU_STATS_P2(rx_undersized_frames), + GBENU_STATS_P2(rx_fragments), + GBENU_STATS_P2(ale_drop), + GBENU_STATS_P2(ale_overrun_drop), + GBENU_STATS_P2(rx_bytes), + GBENU_STATS_P2(tx_good_frames), + GBENU_STATS_P2(tx_broadcast_frames), + GBENU_STATS_P2(tx_multicast_frames), + GBENU_STATS_P2(tx_pause_frames), + GBENU_STATS_P2(tx_deferred_frames), + GBENU_STATS_P2(tx_collision_frames), + GBENU_STATS_P2(tx_single_coll_frames), + GBENU_STATS_P2(tx_mult_coll_frames), + GBENU_STATS_P2(tx_excessive_collisions), + GBENU_STATS_P2(tx_late_collisions), + GBENU_STATS_P2(rx_ipg_error), + GBENU_STATS_P2(tx_carrier_sense_errors), + GBENU_STATS_P2(tx_bytes), + GBENU_STATS_P2(tx_64B_frames), + GBENU_STATS_P2(tx_65_to_127B_frames), + GBENU_STATS_P2(tx_128_to_255B_frames), + GBENU_STATS_P2(tx_256_to_511B_frames), + GBENU_STATS_P2(tx_512_to_1023B_frames), + GBENU_STATS_P2(tx_1024B_frames), + GBENU_STATS_P2(net_bytes), + GBENU_STATS_P2(rx_bottom_fifo_drop), + GBENU_STATS_P2(rx_port_mask_drop), + GBENU_STATS_P2(rx_top_fifo_drop), + GBENU_STATS_P2(ale_rate_limit_drop), + GBENU_STATS_P2(ale_vid_ingress_drop), + GBENU_STATS_P2(ale_da_eq_sa_drop), + GBENU_STATS_P2(ale_unknown_ucast), + GBENU_STATS_P2(ale_unknown_ucast_bytes), + GBENU_STATS_P2(ale_unknown_mcast), + GBENU_STATS_P2(ale_unknown_mcast_bytes), + GBENU_STATS_P2(ale_unknown_bcast), + GBENU_STATS_P2(ale_unknown_bcast_bytes), + GBENU_STATS_P2(tx_mem_protect_err), + /* GBENU Module 3 */ + GBENU_STATS_P3(rx_good_frames), + GBENU_STATS_P3(rx_broadcast_frames), + GBENU_STATS_P3(rx_multicast_frames), + GBENU_STATS_P3(rx_pause_frames), + GBENU_STATS_P3(rx_crc_errors), + GBENU_STATS_P3(rx_align_code_errors), + GBENU_STATS_P3(rx_oversized_frames), + GBENU_STATS_P3(rx_jabber_frames), + GBENU_STATS_P3(rx_undersized_frames), + GBENU_STATS_P3(rx_fragments), + GBENU_STATS_P3(ale_drop), + GBENU_STATS_P3(ale_overrun_drop), + GBENU_STATS_P3(rx_bytes), + GBENU_STATS_P3(tx_good_frames), + GBENU_STATS_P3(tx_broadcast_frames), + GBENU_STATS_P3(tx_multicast_frames), + GBENU_STATS_P3(tx_pause_frames), + GBENU_STATS_P3(tx_deferred_frames), + GBENU_STATS_P3(tx_collision_frames), + GBENU_STATS_P3(tx_single_coll_frames), + GBENU_STATS_P3(tx_mult_coll_frames), + GBENU_STATS_P3(tx_excessive_collisions), + GBENU_STATS_P3(tx_late_collisions), + GBENU_STATS_P3(rx_ipg_error), + GBENU_STATS_P3(tx_carrier_sense_errors), + GBENU_STATS_P3(tx_bytes), + GBENU_STATS_P3(tx_64B_frames), + GBENU_STATS_P3(tx_65_to_127B_frames), + GBENU_STATS_P3(tx_128_to_255B_frames), + GBENU_STATS_P3(tx_256_to_511B_frames), + GBENU_STATS_P3(tx_512_to_1023B_frames), + GBENU_STATS_P3(tx_1024B_frames), + GBENU_STATS_P3(net_bytes), + GBENU_STATS_P3(rx_bottom_fifo_drop), + GBENU_STATS_P3(rx_port_mask_drop), + GBENU_STATS_P3(rx_top_fifo_drop), + GBENU_STATS_P3(ale_rate_limit_drop), + GBENU_STATS_P3(ale_vid_ingress_drop), + GBENU_STATS_P3(ale_da_eq_sa_drop), + GBENU_STATS_P3(ale_unknown_ucast), + GBENU_STATS_P3(ale_unknown_ucast_bytes), + GBENU_STATS_P3(ale_unknown_mcast), + GBENU_STATS_P3(ale_unknown_mcast_bytes), + GBENU_STATS_P3(ale_unknown_bcast), + GBENU_STATS_P3(ale_unknown_bcast_bytes), + GBENU_STATS_P3(tx_mem_protect_err), + /* GBENU Module 4 */ + GBENU_STATS_P4(rx_good_frames), + GBENU_STATS_P4(rx_broadcast_frames), + GBENU_STATS_P4(rx_multicast_frames), + GBENU_STATS_P4(rx_pause_frames), + GBENU_STATS_P4(rx_crc_errors), + GBENU_STATS_P4(rx_align_code_errors), + GBENU_STATS_P4(rx_oversized_frames), + GBENU_STATS_P4(rx_jabber_frames), + GBENU_STATS_P4(rx_undersized_frames), + GBENU_STATS_P4(rx_fragments), + GBENU_STATS_P4(ale_drop), + GBENU_STATS_P4(ale_overrun_drop), + GBENU_STATS_P4(rx_bytes), + GBENU_STATS_P4(tx_good_frames), + GBENU_STATS_P4(tx_broadcast_frames), + GBENU_STATS_P4(tx_multicast_frames), + GBENU_STATS_P4(tx_pause_frames), + GBENU_STATS_P4(tx_deferred_frames), + GBENU_STATS_P4(tx_collision_frames), + GBENU_STATS_P4(tx_single_coll_frames), + GBENU_STATS_P4(tx_mult_coll_frames), + GBENU_STATS_P4(tx_excessive_collisions), + GBENU_STATS_P4(tx_late_collisions), + GBENU_STATS_P4(rx_ipg_error), + GBENU_STATS_P4(tx_carrier_sense_errors), + GBENU_STATS_P4(tx_bytes), + GBENU_STATS_P4(tx_64B_frames), + GBENU_STATS_P4(tx_65_to_127B_frames), + GBENU_STATS_P4(tx_128_to_255B_frames), + GBENU_STATS_P4(tx_256_to_511B_frames), + GBENU_STATS_P4(tx_512_to_1023B_frames), + GBENU_STATS_P4(tx_1024B_frames), + GBENU_STATS_P4(net_bytes), + GBENU_STATS_P4(rx_bottom_fifo_drop), + GBENU_STATS_P4(rx_port_mask_drop), + GBENU_STATS_P4(rx_top_fifo_drop), + GBENU_STATS_P4(ale_rate_limit_drop), + GBENU_STATS_P4(ale_vid_ingress_drop), + GBENU_STATS_P4(ale_da_eq_sa_drop), + GBENU_STATS_P4(ale_unknown_ucast), + GBENU_STATS_P4(ale_unknown_ucast_bytes), + GBENU_STATS_P4(ale_unknown_mcast), + GBENU_STATS_P4(ale_unknown_mcast_bytes), + GBENU_STATS_P4(ale_unknown_bcast), + GBENU_STATS_P4(ale_unknown_bcast_bytes), + GBENU_STATS_P4(tx_mem_protect_err), + /* GBENU Module 5 */ + GBENU_STATS_P5(rx_good_frames), + GBENU_STATS_P5(rx_broadcast_frames), + GBENU_STATS_P5(rx_multicast_frames), + GBENU_STATS_P5(rx_pause_frames), + GBENU_STATS_P5(rx_crc_errors), + GBENU_STATS_P5(rx_align_code_errors), + GBENU_STATS_P5(rx_oversized_frames), + GBENU_STATS_P5(rx_jabber_frames), + GBENU_STATS_P5(rx_undersized_frames), + GBENU_STATS_P5(rx_fragments), + GBENU_STATS_P5(ale_drop), + GBENU_STATS_P5(ale_overrun_drop), + GBENU_STATS_P5(rx_bytes), + GBENU_STATS_P5(tx_good_frames), + GBENU_STATS_P5(tx_broadcast_frames), + GBENU_STATS_P5(tx_multicast_frames), + GBENU_STATS_P5(tx_pause_frames), + GBENU_STATS_P5(tx_deferred_frames), + GBENU_STATS_P5(tx_collision_frames), + GBENU_STATS_P5(tx_single_coll_frames), + GBENU_STATS_P5(tx_mult_coll_frames), + GBENU_STATS_P5(tx_excessive_collisions), + GBENU_STATS_P5(tx_late_collisions), + GBENU_STATS_P5(rx_ipg_error), + GBENU_STATS_P5(tx_carrier_sense_errors), + GBENU_STATS_P5(tx_bytes), + GBENU_STATS_P5(tx_64B_frames), + GBENU_STATS_P5(tx_65_to_127B_frames), + GBENU_STATS_P5(tx_128_to_255B_frames), + GBENU_STATS_P5(tx_256_to_511B_frames), + GBENU_STATS_P5(tx_512_to_1023B_frames), + GBENU_STATS_P5(tx_1024B_frames), + GBENU_STATS_P5(net_bytes), + GBENU_STATS_P5(rx_bottom_fifo_drop), + GBENU_STATS_P5(rx_port_mask_drop), + GBENU_STATS_P5(rx_top_fifo_drop), + GBENU_STATS_P5(ale_rate_limit_drop), + GBENU_STATS_P5(ale_vid_ingress_drop), + GBENU_STATS_P5(ale_da_eq_sa_drop), + GBENU_STATS_P5(ale_unknown_ucast), + GBENU_STATS_P5(ale_unknown_ucast_bytes), + GBENU_STATS_P5(ale_unknown_mcast), + GBENU_STATS_P5(ale_unknown_mcast_bytes), + GBENU_STATS_P5(ale_unknown_bcast), + GBENU_STATS_P5(ale_unknown_bcast_bytes), + GBENU_STATS_P5(tx_mem_protect_err), + /* GBENU Module 6 */ + GBENU_STATS_P6(rx_good_frames), + GBENU_STATS_P6(rx_broadcast_frames), + GBENU_STATS_P6(rx_multicast_frames), + GBENU_STATS_P6(rx_pause_frames), + GBENU_STATS_P6(rx_crc_errors), + GBENU_STATS_P6(rx_align_code_errors), + GBENU_STATS_P6(rx_oversized_frames), + GBENU_STATS_P6(rx_jabber_frames), + GBENU_STATS_P6(rx_undersized_frames), + GBENU_STATS_P6(rx_fragments), + GBENU_STATS_P6(ale_drop), + GBENU_STATS_P6(ale_overrun_drop), + GBENU_STATS_P6(rx_bytes), + GBENU_STATS_P6(tx_good_frames), + GBENU_STATS_P6(tx_broadcast_frames), + GBENU_STATS_P6(tx_multicast_frames), + GBENU_STATS_P6(tx_pause_frames), + GBENU_STATS_P6(tx_deferred_frames), + GBENU_STATS_P6(tx_collision_frames), + GBENU_STATS_P6(tx_single_coll_frames), + GBENU_STATS_P6(tx_mult_coll_frames), + GBENU_STATS_P6(tx_excessive_collisions), + GBENU_STATS_P6(tx_late_collisions), + GBENU_STATS_P6(rx_ipg_error), + GBENU_STATS_P6(tx_carrier_sense_errors), + GBENU_STATS_P6(tx_bytes), + GBENU_STATS_P6(tx_64B_frames), + GBENU_STATS_P6(tx_65_to_127B_frames), + GBENU_STATS_P6(tx_128_to_255B_frames), + GBENU_STATS_P6(tx_256_to_511B_frames), + GBENU_STATS_P6(tx_512_to_1023B_frames), + GBENU_STATS_P6(tx_1024B_frames), + GBENU_STATS_P6(net_bytes), + GBENU_STATS_P6(rx_bottom_fifo_drop), + GBENU_STATS_P6(rx_port_mask_drop), + GBENU_STATS_P6(rx_top_fifo_drop), + GBENU_STATS_P6(ale_rate_limit_drop), + GBENU_STATS_P6(ale_vid_ingress_drop), + GBENU_STATS_P6(ale_da_eq_sa_drop), + GBENU_STATS_P6(ale_unknown_ucast), + GBENU_STATS_P6(ale_unknown_ucast_bytes), + GBENU_STATS_P6(ale_unknown_mcast), + GBENU_STATS_P6(ale_unknown_mcast_bytes), + GBENU_STATS_P6(ale_unknown_bcast), + GBENU_STATS_P6(ale_unknown_bcast_bytes), + GBENU_STATS_P6(tx_mem_protect_err), + /* GBENU Module 7 */ + GBENU_STATS_P7(rx_good_frames), + GBENU_STATS_P7(rx_broadcast_frames), + GBENU_STATS_P7(rx_multicast_frames), + GBENU_STATS_P7(rx_pause_frames), + GBENU_STATS_P7(rx_crc_errors), + GBENU_STATS_P7(rx_align_code_errors), + GBENU_STATS_P7(rx_oversized_frames), + GBENU_STATS_P7(rx_jabber_frames), + GBENU_STATS_P7(rx_undersized_frames), + GBENU_STATS_P7(rx_fragments), + GBENU_STATS_P7(ale_drop), + GBENU_STATS_P7(ale_overrun_drop), + GBENU_STATS_P7(rx_bytes), + GBENU_STATS_P7(tx_good_frames), + GBENU_STATS_P7(tx_broadcast_frames), + GBENU_STATS_P7(tx_multicast_frames), + GBENU_STATS_P7(tx_pause_frames), + GBENU_STATS_P7(tx_deferred_frames), + GBENU_STATS_P7(tx_collision_frames), + GBENU_STATS_P7(tx_single_coll_frames), + GBENU_STATS_P7(tx_mult_coll_frames), + GBENU_STATS_P7(tx_excessive_collisions), + GBENU_STATS_P7(tx_late_collisions), + GBENU_STATS_P7(rx_ipg_error), + GBENU_STATS_P7(tx_carrier_sense_errors), + GBENU_STATS_P7(tx_bytes), + GBENU_STATS_P7(tx_64B_frames), + GBENU_STATS_P7(tx_65_to_127B_frames), + GBENU_STATS_P7(tx_128_to_255B_frames), + GBENU_STATS_P7(tx_256_to_511B_frames), + GBENU_STATS_P7(tx_512_to_1023B_frames), + GBENU_STATS_P7(tx_1024B_frames), + GBENU_STATS_P7(net_bytes), + GBENU_STATS_P7(rx_bottom_fifo_drop), + GBENU_STATS_P7(rx_port_mask_drop), + GBENU_STATS_P7(rx_top_fifo_drop), + GBENU_STATS_P7(ale_rate_limit_drop), + GBENU_STATS_P7(ale_vid_ingress_drop), + GBENU_STATS_P7(ale_da_eq_sa_drop), + GBENU_STATS_P7(ale_unknown_ucast), + GBENU_STATS_P7(ale_unknown_ucast_bytes), + GBENU_STATS_P7(ale_unknown_mcast), + GBENU_STATS_P7(ale_unknown_mcast_bytes), + GBENU_STATS_P7(ale_unknown_bcast), + GBENU_STATS_P7(ale_unknown_bcast_bytes), + GBENU_STATS_P7(tx_mem_protect_err), + /* GBENU Module 8 */ + GBENU_STATS_P8(rx_good_frames), + GBENU_STATS_P8(rx_broadcast_frames), + GBENU_STATS_P8(rx_multicast_frames), + GBENU_STATS_P8(rx_pause_frames), + GBENU_STATS_P8(rx_crc_errors), + GBENU_STATS_P8(rx_align_code_errors), + GBENU_STATS_P8(rx_oversized_frames), + GBENU_STATS_P8(rx_jabber_frames), + GBENU_STATS_P8(rx_undersized_frames), + GBENU_STATS_P8(rx_fragments), + GBENU_STATS_P8(ale_drop), + GBENU_STATS_P8(ale_overrun_drop), + GBENU_STATS_P8(rx_bytes), + GBENU_STATS_P8(tx_good_frames), + GBENU_STATS_P8(tx_broadcast_frames), + GBENU_STATS_P8(tx_multicast_frames), + GBENU_STATS_P8(tx_pause_frames), + GBENU_STATS_P8(tx_deferred_frames), + GBENU_STATS_P8(tx_collision_frames), + GBENU_STATS_P8(tx_single_coll_frames), + GBENU_STATS_P8(tx_mult_coll_frames), + GBENU_STATS_P8(tx_excessive_collisions), + GBENU_STATS_P8(tx_late_collisions), + GBENU_STATS_P8(rx_ipg_error), + GBENU_STATS_P8(tx_carrier_sense_errors), + GBENU_STATS_P8(tx_bytes), + GBENU_STATS_P8(tx_64B_frames), + GBENU_STATS_P8(tx_65_to_127B_frames), + GBENU_STATS_P8(tx_128_to_255B_frames), + GBENU_STATS_P8(tx_256_to_511B_frames), + GBENU_STATS_P8(tx_512_to_1023B_frames), + GBENU_STATS_P8(tx_1024B_frames), + GBENU_STATS_P8(net_bytes), + GBENU_STATS_P8(rx_bottom_fifo_drop), + GBENU_STATS_P8(rx_port_mask_drop), + GBENU_STATS_P8(rx_top_fifo_drop), + GBENU_STATS_P8(ale_rate_limit_drop), + GBENU_STATS_P8(ale_vid_ingress_drop), + GBENU_STATS_P8(ale_da_eq_sa_drop), + GBENU_STATS_P8(ale_unknown_ucast), + GBENU_STATS_P8(ale_unknown_ucast_bytes), + GBENU_STATS_P8(ale_unknown_mcast), + GBENU_STATS_P8(ale_unknown_mcast_bytes), + GBENU_STATS_P8(ale_unknown_bcast), + GBENU_STATS_P8(ale_unknown_bcast_bytes), + GBENU_STATS_P8(tx_mem_protect_err), +}; + #define XGBE_STATS0_INFO(field) \ { \ "GBE_0:"#field, XGBE_STATS0_MODULE, \ @@ -1094,9 +1796,16 @@ static void netcp_ethss_update_link_state(struct gbe_priv *gbe_dev, if (!slave->open) return; - if (!SLAVE_LINK_IS_XGMII(slave)) - sgmii_link_state = netcp_sgmii_get_port_link(SGMII_BASE(sp), - sp); + if (!SLAVE_LINK_IS_XGMII(slave)) { + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + sgmii_link_state = + netcp_sgmii_get_port_link(SGMII_BASE(sp), sp); + else + sgmii_link_state = + netcp_sgmii_get_port_link( + gbe_dev->sgmii_port_regs, sp); + } + phy_link_state = gbe_phy_link_status(slave); link_state = phy_link_state & sgmii_link_state; @@ -1165,6 +1874,7 @@ static int gbe_port_reset(struct gbe_slave *slave) static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave, int max_rx_len) { + void __iomem *rx_maxlen_reg; u32 xgmii_mode; if (max_rx_len > NETCP_MAX_FRAME_SIZE) @@ -1178,7 +1888,12 @@ static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave, writel(xgmii_mode, GBE_REG_ADDR(gbe_dev, ss_regs, control)); } - writel(max_rx_len, GBE_REG_ADDR(slave, emac_regs, rx_maxlen)); + if (IS_SS_ID_MU(gbe_dev)) + rx_maxlen_reg = GBE_REG_ADDR(slave, port_regs, rx_maxlen); + else + rx_maxlen_reg = GBE_REG_ADDR(slave, emac_regs, rx_maxlen); + + writel(max_rx_len, rx_maxlen_reg); writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control)); } @@ -1270,6 +1985,12 @@ static int gbe_slave_open(struct gbe_intf *gbe_intf) static void gbe_init_host_port(struct gbe_priv *priv) { int bypass_en = 1; + + /* Host Tx Pri */ + if (IS_SS_ID_NU(priv)) + writel(HOST_TX_PRI_MAP_DEFAULT, + GBE_REG_ADDR(priv, host_port_regs, tx_pri_map)); + /* Max length register */ writel(NETCP_MAX_FRAME_SIZE, GBE_REG_ADDR(priv, host_port_regs, rx_maxlen)); @@ -1500,8 +2221,8 @@ static int gbe_open(void *intf_priv, struct net_device *ndev) GBE_MAJOR_VERSION(reg), GBE_MINOR_VERSION(reg), GBE_RTL_VERSION(reg), GBE_IDENT(reg)); - /* For 10G use directed to port */ - if (gbe_dev->ss_version == XGBE_SS_VERSION_10) + /* For 10G and on NetCP 1.5, use directed to port */ + if ((gbe_dev->ss_version == XGBE_SS_VERSION_10) || IS_SS_ID_MU(gbe_dev)) gbe_intf->tx_pipe.flags = SWITCH_TO_PORT_IN_TAGINFO; if (gbe_dev->enable_ale) @@ -1525,8 +2246,8 @@ static int gbe_open(void *intf_priv, struct net_device *ndev) writel(GBE_CTL_P0_ENABLE, GBE_REG_ADDR(gbe_dev, switch_regs, control)); /* All statistics enabled and STAT AB visible by default */ - writel(GBE_REG_VAL_STAT_ENABLE_ALL, GBE_REG_ADDR(gbe_dev, switch_regs, - stat_port_en)); + writel(gbe_dev->stats_en_mask, GBE_REG_ADDR(gbe_dev, switch_regs, + stat_port_en)); ret = gbe_slave_open(gbe_intf); if (ret) @@ -1563,6 +2284,7 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, { int port_reg_num; u32 port_reg_ofs, emac_reg_ofs; + u32 port_reg_blk_sz, emac_reg_blk_sz; if (of_property_read_u32(node, "slave-port", &slave->slave_num)) { dev_err(gbe_dev->dev, "missing slave-port parameter\n"); @@ -1594,23 +2316,29 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, } else { port_reg_ofs = GBE13_SLAVE_PORT_OFFSET; } + emac_reg_ofs = GBE13_EMAC_OFFSET; + port_reg_blk_sz = 0x30; + emac_reg_blk_sz = 0x40; + } else if (IS_SS_ID_MU(gbe_dev)) { + port_reg_ofs = GBENU_SLAVE_PORT_OFFSET; + emac_reg_ofs = GBENU_EMAC_OFFSET; + port_reg_blk_sz = 0x1000; + emac_reg_blk_sz = 0x1000; } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) { port_reg_ofs = XGBE10_SLAVE_PORT_OFFSET; + emac_reg_ofs = XGBE10_EMAC_OFFSET; + port_reg_blk_sz = 0x30; + emac_reg_blk_sz = 0x40; } else { dev_err(gbe_dev->dev, "unknown ethss(0x%x)\n", gbe_dev->ss_version); return -EINVAL; } - if (gbe_dev->ss_version == GBE_SS_VERSION_14) - emac_reg_ofs = GBE13_EMAC_OFFSET; - else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) - emac_reg_ofs = XGBE10_EMAC_OFFSET; - slave->port_regs = gbe_dev->switch_regs + port_reg_ofs + - (0x30 * port_reg_num); + (port_reg_blk_sz * port_reg_num); slave->emac_regs = gbe_dev->switch_regs + emac_reg_ofs + - (0x40 * slave->slave_num); + (emac_reg_blk_sz * slave->slave_num); if (gbe_dev->ss_version == GBE_SS_VERSION_14) { /* Initialize slave port register offsets */ @@ -1629,6 +2357,23 @@ static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave, GBE_SET_REG_OFS(slave, emac_regs, soft_reset); GBE_SET_REG_OFS(slave, emac_regs, rx_maxlen); + } else if (IS_SS_ID_MU(gbe_dev)) { + /* Initialize slave port register offsets */ + GBENU_SET_REG_OFS(slave, port_regs, port_vlan); + GBENU_SET_REG_OFS(slave, port_regs, tx_pri_map); + GBENU_SET_REG_OFS(slave, port_regs, sa_lo); + GBENU_SET_REG_OFS(slave, port_regs, sa_hi); + GBENU_SET_REG_OFS(slave, port_regs, ts_ctl); + GBENU_SET_REG_OFS(slave, port_regs, ts_seq_ltype); + GBENU_SET_REG_OFS(slave, port_regs, ts_vlan); + GBENU_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2); + GBENU_SET_REG_OFS(slave, port_regs, ts_ctl2); + GBENU_SET_REG_OFS(slave, port_regs, rx_maxlen); + + /* Initialize EMAC register offsets */ + GBENU_SET_REG_OFS(slave, emac_regs, mac_control); + GBENU_SET_REG_OFS(slave, emac_regs, soft_reset); + } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) { /* Initialize slave port register offsets */ XGBE_SET_REG_OFS(slave, port_regs, port_vlan); @@ -1688,6 +2433,8 @@ static void init_secondary_ports(struct gbe_priv *gbe_dev, mac_phy_link = true; slave->open = true; + if (gbe_dev->num_slaves >= gbe_dev->max_num_slaves) + break; } /* of_phy_connect() is needed only for MAC-PHY interface */ @@ -1758,7 +2505,7 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, void __iomem *regs; int ret, i; - ret = of_address_to_resource(node, 0, &res); + ret = of_address_to_resource(node, XGBE_SS_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, "Can't xlate xgbe of node(%s) ss address at %d\n", @@ -1804,9 +2551,9 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, gbe_dev->xgbe_serdes_regs = regs; gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - XGBE10_NUM_STAT_ENTRIES * - (XGBE10_NUM_SLAVES + 1) * sizeof(u64), - GFP_KERNEL); + XGBE10_NUM_STAT_ENTRIES * + (gbe_dev->max_num_ports) * sizeof(u64), + GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); return -ENOMEM; @@ -1817,16 +2564,17 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, XGBE10_SGMII_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->ss_regs + XGBE10_HOST_PORT_OFFSET; - for (i = 0; i < XGBE10_NUM_HW_STATS_MOD; i++) + for (i = 0; i < gbe_dev->max_num_ports; i++) gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i); - gbe_dev->ale_reg = gbe_dev->ss_regs + XGBE10_ALE_OFFSET; - gbe_dev->ale_ports = XGBE10_NUM_ALE_PORTS; + gbe_dev->ale_reg = gbe_dev->switch_regs + XGBE10_ALE_OFFSET; + gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = XGBE10_HOST_PORT_NUM; gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES; gbe_dev->et_stats = xgbe10_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); + gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1; /* Subsystem registers */ XGBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver); @@ -1912,7 +2660,7 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, GBE13_NUM_HW_STAT_ENTRIES * - GBE13_NUM_SLAVES * sizeof(u64), + gbe_dev->max_num_slaves * sizeof(u64), GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); @@ -1922,18 +2670,19 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBE13_SGMII_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->switch_regs + GBE13_HOST_PORT_OFFSET; - for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++) { + for (i = 0; i < gbe_dev->max_num_slaves; i++) { gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + GBE13_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i); } gbe_dev->ale_reg = gbe_dev->switch_regs + GBE13_ALE_OFFSET; - gbe_dev->ale_ports = GBE13_NUM_ALE_PORTS; + gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = GBE13_HOST_PORT_NUM; gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; gbe_dev->et_stats = gbe13_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); + gbe_dev->stats_en_mask = GBE13_REG_VAL_STAT_ENABLE_ALL; /* Subsystem registers */ GBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver); @@ -1952,6 +2701,80 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, return 0; } +static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, + struct device_node *node) +{ + struct resource res; + void __iomem *regs; + int i, ret; + + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, + GBENU_NUM_HW_STAT_ENTRIES * + (gbe_dev->max_num_ports) * sizeof(u64), + GFP_KERNEL); + if (!gbe_dev->hw_stats) { + dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); + return -ENOMEM; + } + + ret = of_address_to_resource(node, GBENU_SM_REG_INDEX, &res); + if (ret) { + dev_err(gbe_dev->dev, + "Can't translate of gbenu node(%s) addr at index %d\n", + node->name, GBENU_SM_REG_INDEX); + return ret; + } + + regs = devm_ioremap_resource(gbe_dev->dev, &res); + if (IS_ERR(regs)) { + dev_err(gbe_dev->dev, + "Failed to map gbenu switch module register base\n"); + return PTR_ERR(regs); + } + gbe_dev->switch_regs = regs; + + gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBENU_SGMII_MODULE_OFFSET; + gbe_dev->host_port_regs = gbe_dev->switch_regs + GBENU_HOST_PORT_OFFSET; + + for (i = 0; i < (gbe_dev->max_num_ports); i++) + gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + + GBENU_HW_STATS_OFFSET + (GBENU_HW_STATS_REG_MAP_SZ * i); + + gbe_dev->ale_reg = gbe_dev->switch_regs + GBENU_ALE_OFFSET; + gbe_dev->ale_ports = gbe_dev->max_num_ports; + gbe_dev->host_port = GBENU_HOST_PORT_NUM; + gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; + gbe_dev->et_stats = gbenu_et_stats; + gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1; + + if (IS_SS_ID_NU(gbe_dev)) + gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + + (gbe_dev->max_num_slaves * GBENU_ET_STATS_PORT_SIZE); + else + gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + + GBENU_ET_STATS_PORT_SIZE; + + /* Subsystem registers */ + GBENU_SET_REG_OFS(gbe_dev, ss_regs, id_ver); + + /* Switch module registers */ + GBENU_SET_REG_OFS(gbe_dev, switch_regs, id_ver); + GBENU_SET_REG_OFS(gbe_dev, switch_regs, control); + GBENU_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en); + GBENU_SET_REG_OFS(gbe_dev, switch_regs, ptype); + + /* Host port registers */ + GBENU_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan); + GBENU_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen); + + /* For NU only. 2U does not need tx_pri_map. + * NU cppi port 0 tx pkt streaming interface has (n-1)*8 egress threads + * while 2U has only 1 such thread + */ + GBENU_SET_REG_OFS(gbe_dev, host_port_regs, tx_pri_map); + return 0; +} + static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, struct device_node *node, void **inst_priv) { @@ -1971,6 +2794,21 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, if (!gbe_dev) return -ENOMEM; + if (of_device_is_compatible(node, "ti,netcp-gbe-5") || + of_device_is_compatible(node, "ti,netcp-gbe")) { + gbe_dev->max_num_slaves = 4; + } else if (of_device_is_compatible(node, "ti,netcp-gbe-9")) { + gbe_dev->max_num_slaves = 8; + } else if (of_device_is_compatible(node, "ti,netcp-gbe-2")) { + gbe_dev->max_num_slaves = 1; + } else if (of_device_is_compatible(node, "ti,netcp-xgbe")) { + gbe_dev->max_num_slaves = 2; + } else { + dev_err(dev, "device tree node for unknown device\n"); + return -EINVAL; + } + gbe_dev->max_num_ports = gbe_dev->max_num_slaves + 1; + gbe_dev->dev = dev; gbe_dev->netcp_device = netcp_device; gbe_dev->rx_packet_max = NETCP_MAX_FRAME_SIZE; @@ -2006,7 +2844,15 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, if (ret) goto quit; - ret = set_gbe_ethss14_priv(gbe_dev, node); + dev_dbg(dev, "ss_version: 0x%08x\n", gbe_dev->ss_version); + + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + ret = set_gbe_ethss14_priv(gbe_dev, node); + else if (IS_SS_ID_MU(gbe_dev)) + ret = set_gbenu_ethss_priv(gbe_dev, node); + else + ret = -ENODEV; + if (ret) goto quit; } else if (!strcmp(node->name, "xgbe")) { @@ -2046,6 +2892,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, continue; } gbe_dev->num_slaves++; + if (gbe_dev->num_slaves >= gbe_dev->max_num_slaves) + break; } if (!gbe_dev->num_slaves) @@ -2054,7 +2902,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, /* Initialize Secondary slave ports */ secondary_ports = of_get_child_by_name(node, "secondary-slave-ports"); INIT_LIST_HEAD(&gbe_dev->secondary_slaves); - if (secondary_ports) + if (secondary_ports && (gbe_dev->num_slaves < gbe_dev->max_num_slaves)) init_secondary_ports(gbe_dev, secondary_ports); of_node_put(secondary_ports); -- cgit v1.2.3 From 6be88670fc59d50426f90f734a36b90e1de7d148 Mon Sep 17 00:00:00 2001 From: Clément Perrochaud Date: Mon, 9 Mar 2015 11:12:05 +0100 Subject: NFC: nxp-nci_i2c: Add I2C support to NXP NCI driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a module to the NXP-NCI driver to support NFC controllers with an I2C control interface, such as the NPC100. Signed-off-by: Clément Perrochaud Signed-off-by: Samuel Ortiz --- .../devicetree/bindings/net/nfc/nxp-nci.txt | 35 ++ drivers/nfc/nxp-nci/Kconfig | 12 + drivers/nfc/nxp-nci/Makefile | 2 + drivers/nfc/nxp-nci/i2c.c | 415 +++++++++++++++++++++ 4 files changed, 464 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/nfc/nxp-nci.txt create mode 100644 drivers/nfc/nxp-nci/i2c.c (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt b/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt new file mode 100644 index 000000000000..5b6cd9b3f628 --- /dev/null +++ b/Documentation/devicetree/bindings/net/nfc/nxp-nci.txt @@ -0,0 +1,35 @@ +* NXP Semiconductors NXP NCI NFC Controllers + +Required properties: +- compatible: Should be "nxp,nxp-nci-i2c". +- clock-frequency: I²C work frequency. +- reg: address on the bus +- interrupt-parent: phandle for the interrupt gpio controller +- interrupts: GPIO interrupt to which the chip is connected +- enable-gpios: Output GPIO pin used for enabling/disabling the chip +- firmware-gpios: Output GPIO pin used to enter firmware download mode + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBone with NPC100 NFC controller on I2C2): + +&i2c2 { + + status = "okay"; + + npc100: npc100@29 { + + compatible = "nxp,nxp-nci-i2c"; + + reg = <0x29>; + clock-frequency = <100000>; + + interrupt-parent = <&gpio1>; + interrupts = <29 GPIO_ACTIVE_HIGH>; + + enable-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + firmware-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/drivers/nfc/nxp-nci/Kconfig b/drivers/nfc/nxp-nci/Kconfig index 5f60c7cf02e8..37b40612520d 100644 --- a/drivers/nfc/nxp-nci/Kconfig +++ b/drivers/nfc/nxp-nci/Kconfig @@ -11,3 +11,15 @@ config NFC_NXP_NCI To compile this driver as a module, choose m here. The module will be called nxp_nci. Say N if unsure. + +config NFC_NXP_NCI_I2C + tristate "NXP-NCI I2C support" + depends on NFC_NXP_NCI && I2C + ---help--- + This module adds support for an I2C interface to the NXP NCI + chips. + Select this if your platform is using the I2C bus. + + To compile this driver as a module, choose m here. The module will + be called nxp_nci_i2c. + Say Y if unsure. diff --git a/drivers/nfc/nxp-nci/Makefile b/drivers/nfc/nxp-nci/Makefile index 8f1e32826961..c008be30bb18 100644 --- a/drivers/nfc/nxp-nci/Makefile +++ b/drivers/nfc/nxp-nci/Makefile @@ -3,7 +3,9 @@ # nxp-nci-objs = core.o firmware.o +nxp-nci_i2c-objs = i2c.o obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci.o +obj-$(CONFIG_NFC_NXP_NCI_I2C) += nxp-nci_i2c.o ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c new file mode 100644 index 000000000000..17bd67dbebf0 --- /dev/null +++ b/drivers/nfc/nxp-nci/i2c.c @@ -0,0 +1,415 @@ +/* + * I2C link layer for the NXP NCI driver + * + * Copyright (C) 2014 NXP Semiconductors All rights reserved. + * + * Authors: Clément Perrochaud + * + * Derived from PN544 device driver: + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "nxp-nci.h" + +#define NXP_NCI_I2C_DRIVER_NAME "nxp-nci_i2c" + +#define NXP_NCI_I2C_MAX_PAYLOAD 32 + +struct nxp_nci_i2c_phy { + struct i2c_client *i2c_dev; + struct nci_dev *ndev; + + unsigned int gpio_en; + unsigned int gpio_fw; + + int hard_fault; /* + * < 0 if hardware error occurred (e.g. i2c err) + * and prevents normal operation. + */ +}; + +static int nxp_nci_i2c_set_mode(void *phy_id, + enum nxp_nci_mode mode) +{ + struct nxp_nci_i2c_phy *phy = (struct nxp_nci_i2c_phy *) phy_id; + + gpio_set_value(phy->gpio_fw, (mode == NXP_NCI_MODE_FW) ? 1 : 0); + gpio_set_value(phy->gpio_en, (mode != NXP_NCI_MODE_COLD) ? 1 : 0); + usleep_range(10000, 15000); + + if (mode == NXP_NCI_MODE_COLD) + phy->hard_fault = 0; + + return 0; +} + +static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb) +{ + int r; + struct nxp_nci_i2c_phy *phy = phy_id; + struct i2c_client *client = phy->i2c_dev; + + if (phy->hard_fault != 0) + return phy->hard_fault; + + r = i2c_master_send(client, skb->data, skb->len); + if (r == -EREMOTEIO) { + /* Retry, chip was in standby */ + usleep_range(110000, 120000); + r = i2c_master_send(client, skb->data, skb->len); + } + + if (r < 0) { + nfc_err(&client->dev, "Error %d on I2C send\n", r); + } else if (r != skb->len) { + nfc_err(&client->dev, + "Invalid length sent: %u (expected %u)\n", + r, skb->len); + r = -EREMOTEIO; + } else { + /* Success but return 0 and not number of bytes */ + r = 0; + } + + return r; +} + +static struct nxp_nci_phy_ops i2c_phy_ops = { + .set_mode = nxp_nci_i2c_set_mode, + .write = nxp_nci_i2c_write, +}; + +static int nxp_nci_i2c_fw_read(struct nxp_nci_i2c_phy *phy, + struct sk_buff **skb) +{ + struct i2c_client *client = phy->i2c_dev; + u16 header; + size_t frame_len; + int r; + + r = i2c_master_recv(client, (u8 *) &header, NXP_NCI_FW_HDR_LEN); + if (r < 0) { + goto fw_read_exit; + } else if (r != NXP_NCI_FW_HDR_LEN) { + nfc_err(&client->dev, "Incorrect header length: %u\n", r); + r = -EBADMSG; + goto fw_read_exit; + } + + frame_len = (get_unaligned_be16(&header) & NXP_NCI_FW_FRAME_LEN_MASK) + + NXP_NCI_FW_CRC_LEN; + + *skb = alloc_skb(NXP_NCI_FW_HDR_LEN + frame_len, GFP_KERNEL); + if (*skb == NULL) { + r = -ENOMEM; + goto fw_read_exit; + } + + memcpy(skb_put(*skb, NXP_NCI_FW_HDR_LEN), &header, NXP_NCI_FW_HDR_LEN); + + r = i2c_master_recv(client, skb_put(*skb, frame_len), frame_len); + if (r != frame_len) { + nfc_err(&client->dev, + "Invalid frame length: %u (expected %zu)\n", + r, frame_len); + r = -EBADMSG; + goto fw_read_exit_free_skb; + } + + return 0; + +fw_read_exit_free_skb: + kfree_skb(*skb); +fw_read_exit: + return r; +} + +static int nxp_nci_i2c_nci_read(struct nxp_nci_i2c_phy *phy, + struct sk_buff **skb) +{ + struct nci_ctrl_hdr header; /* May actually be a data header */ + struct i2c_client *client = phy->i2c_dev; + int r; + + r = i2c_master_recv(client, (u8 *) &header, NCI_CTRL_HDR_SIZE); + if (r < 0) { + goto nci_read_exit; + } else if (r != NCI_CTRL_HDR_SIZE) { + nfc_err(&client->dev, "Incorrect header length: %u\n", r); + r = -EBADMSG; + goto nci_read_exit; + } + + *skb = alloc_skb(NCI_CTRL_HDR_SIZE + header.plen, GFP_KERNEL); + if (*skb == NULL) { + r = -ENOMEM; + goto nci_read_exit; + } + + memcpy(skb_put(*skb, NCI_CTRL_HDR_SIZE), (void *) &header, + NCI_CTRL_HDR_SIZE); + + r = i2c_master_recv(client, skb_put(*skb, header.plen), header.plen); + if (r != header.plen) { + nfc_err(&client->dev, + "Invalid frame payload length: %u (expected %u)\n", + r, header.plen); + r = -EBADMSG; + goto nci_read_exit_free_skb; + } + + return 0; + +nci_read_exit_free_skb: + kfree_skb(*skb); +nci_read_exit: + return r; +} + +static irqreturn_t nxp_nci_i2c_irq_thread_fn(int irq, void *phy_id) +{ + struct nxp_nci_i2c_phy *phy = phy_id; + struct i2c_client *client; + struct nxp_nci_info *info; + + struct sk_buff *skb = NULL; + int r = 0; + + if (!phy || !phy->ndev) + goto exit_irq_none; + + client = phy->i2c_dev; + + if (!client || irq != client->irq) + goto exit_irq_none; + + info = nci_get_drvdata(phy->ndev); + + if (!info) + goto exit_irq_none; + + mutex_lock(&info->info_lock); + + if (phy->hard_fault != 0) + goto exit_irq_handled; + + switch (info->mode) { + case NXP_NCI_MODE_NCI: + r = nxp_nci_i2c_nci_read(phy, &skb); + break; + case NXP_NCI_MODE_FW: + r = nxp_nci_i2c_fw_read(phy, &skb); + break; + case NXP_NCI_MODE_COLD: + r = -EREMOTEIO; + break; + } + + if (r == -EREMOTEIO) { + phy->hard_fault = r; + skb = NULL; + } else if (r < 0) { + nfc_err(&client->dev, "Read failed with error %d\n", r); + goto exit_irq_handled; + } + + switch (info->mode) { + case NXP_NCI_MODE_NCI: + nci_recv_frame(phy->ndev, skb); + break; + case NXP_NCI_MODE_FW: + nxp_nci_fw_recv_frame(phy->ndev, skb); + break; + case NXP_NCI_MODE_COLD: + break; + } + +exit_irq_handled: + mutex_unlock(&info->info_lock); + return IRQ_HANDLED; +exit_irq_none: + WARN_ON_ONCE(1); + return IRQ_NONE; +} + +#ifdef CONFIG_OF + +static int nxp_nci_i2c_parse_devtree(struct i2c_client *client) +{ + struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client); + struct device_node *pp; + int r; + + pp = client->dev.of_node; + if (!pp) + return -ENODEV; + + r = of_get_named_gpio(pp, "enable-gpios", 0); + if (r == -EPROBE_DEFER) + r = of_get_named_gpio(pp, "enable-gpios", 0); + if (r < 0) { + nfc_err(&client->dev, "Failed to get EN gpio, error: %d\n", r); + return r; + } + phy->gpio_en = r; + + r = of_get_named_gpio(pp, "firmware-gpios", 0); + if (r == -EPROBE_DEFER) + r = of_get_named_gpio(pp, "firmware-gpios", 0); + if (r < 0) { + nfc_err(&client->dev, "Failed to get FW gpio, error: %d\n", r); + return r; + } + phy->gpio_fw = r; + + r = irq_of_parse_and_map(pp, 0); + if (r < 0) { + nfc_err(&client->dev, "Unable to get irq, error: %d\n", r); + return r; + } + client->irq = r; + + return 0; +} + +#else + +static int nxp_nci_i2c_parse_devtree(struct i2c_client *client) +{ + return -ENODEV; +} + +#endif + +static int nxp_nci_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct nxp_nci_i2c_phy *phy; + struct nxp_nci_nfc_platform_data *pdata; + int r; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + nfc_err(&client->dev, "Need I2C_FUNC_I2C\n"); + r = -ENODEV; + goto probe_exit; + } + + phy = devm_kzalloc(&client->dev, sizeof(struct nxp_nci_i2c_phy), + GFP_KERNEL); + if (!phy) { + r = -ENOMEM; + goto probe_exit; + } + + phy->i2c_dev = client; + i2c_set_clientdata(client, phy); + + pdata = client->dev.platform_data; + + if (!pdata && client->dev.of_node) { + r = nxp_nci_i2c_parse_devtree(client); + if (r < 0) { + nfc_err(&client->dev, "Failed to get DT data\n"); + goto probe_exit; + } + } else if (pdata) { + phy->gpio_en = pdata->gpio_en; + phy->gpio_fw = pdata->gpio_fw; + client->irq = pdata->irq; + } else { + nfc_err(&client->dev, "No platform data\n"); + r = -EINVAL; + goto probe_exit; + } + + r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en, + GPIOF_OUT_INIT_LOW, "nxp_nci_en"); + if (r < 0) + goto probe_exit; + + r = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw, + GPIOF_OUT_INIT_LOW, "nxp_nci_fw"); + if (r < 0) + goto probe_exit; + + r = nxp_nci_probe(phy, &client->dev, &i2c_phy_ops, + NXP_NCI_I2C_MAX_PAYLOAD, &phy->ndev); + if (r < 0) + goto probe_exit; + + r = request_threaded_irq(client->irq, NULL, + nxp_nci_i2c_irq_thread_fn, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + NXP_NCI_I2C_DRIVER_NAME, phy); + if (r < 0) + nfc_err(&client->dev, "Unable to register IRQ handler\n"); + +probe_exit: + return r; +} + +static int nxp_nci_i2c_remove(struct i2c_client *client) +{ + struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client); + + nxp_nci_remove(phy->ndev); + free_irq(client->irq, phy); + + return 0; +} + +static struct i2c_device_id nxp_nci_i2c_id_table[] = { + {"nxp-nci_i2c", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, nxp_nci_i2c_id_table); + +static const struct of_device_id of_nxp_nci_i2c_match[] = { + { .compatible = "nxp,nxp-nci-i2c", }, + {}, +}; +MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match); + +static struct i2c_driver nxp_nci_i2c_driver = { + .driver = { + .name = NXP_NCI_I2C_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_nxp_nci_i2c_match), + }, + .probe = nxp_nci_i2c_probe, + .id_table = nxp_nci_i2c_id_table, + .remove = nxp_nci_i2c_remove, +}; + +module_i2c_driver(nxp_nci_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("I2C driver for NXP NCI NFC controllers"); +MODULE_AUTHOR("Clément Perrochaud "); -- cgit v1.2.3 From 7e7d638ab1542d22ff9b14e56f323e1f6cd25cf1 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Wed, 25 Mar 2015 12:19:10 -0700 Subject: Documentation: dts: xgene: Update interrupt field description Signed-off-by: Iyappan Subramanian Signed-off-by: Keyur Chudgar Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/apm-xgene-enet.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt index dc7961b33076..f55aa280d34f 100644 --- a/Documentation/devicetree/bindings/net/apm-xgene-enet.txt +++ b/Documentation/devicetree/bindings/net/apm-xgene-enet.txt @@ -14,7 +14,10 @@ Required properties for all the ethernet interfaces: - "enet_csr": Ethernet control and status register address space - "ring_csr": Descriptor ring control and status register address space - "ring_cmd": Descriptor ring command register address space -- interrupts: Ethernet main interrupt +- interrupts: Two interrupt specifiers can be specified. + - First is the Rx interrupt. This irq is mandatory. + - Second is the Tx completion interrupt. + This is supported only on SGMII based 1GbE and 10GbE interfaces. - port-id: Port number (0 or 1) - clocks: Reference to the clock entry. - local-mac-address: MAC address assigned to this device -- cgit v1.2.3 From 5f9755d26fbfcb6787a6746653f1760fef0d5ba5 Mon Sep 17 00:00:00 2001 From: Andrew Bresticker Date: Tue, 7 Apr 2015 13:38:45 -0700 Subject: stmmac: Add an optional register interface clock The DWMAC block on certain SoCs (such as IMG Pistachio) have a second clock which must be enabled in order to access the peripheral's register interface, so add support for requesting and enabling an optional "pclk". Signed-off-by: Andrew Bresticker Cc: James Hartley Cc: Arnd Bergmann Signed-off-by: David S. Miller --- Documentation/devicetree/bindings/net/stmmac.txt | 7 ++++--- drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) (limited to 'Documentation/devicetree') diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt index 8ca65cec52ae..29aca8591b16 100644 --- a/Documentation/devicetree/bindings/net/stmmac.txt +++ b/Documentation/devicetree/bindings/net/stmmac.txt @@ -35,10 +35,11 @@ Optional properties: - reset-names: Should contain the reset signal name "stmmaceth", if a reset phandle is given - max-frame-size: See ethernet.txt file in the same directory -- clocks: If present, the first clock should be the GMAC main clock, - further clocks may be specified in derived bindings. +- clocks: If present, the first clock should be the GMAC main clock and + the second clock should be peripheral's register interface clock. Further + clocks may be specified in derived bindings. - clock-names: One name for each entry in the clocks property, the - first one should be "stmmaceth". + first one should be "stmmaceth" and the second one should be "pclk". - clk_ptp_ref: this is the PTP reference clock; in case of the PTP is available this clock is used for programming the Timestamp Addend Register. If not passed then the system clock will be used and this is fine on some diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index c0a391983372..2ac9552d1fa3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -97,6 +97,7 @@ struct stmmac_priv { int wolopts; int wol_irq; struct clk *stmmac_clk; + struct clk *pclk; struct reset_control *stmmac_rst; int clk_csr; struct timer_list eee_ctrl_timer; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 5336594abed1..06103cad7c77 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2849,6 +2849,16 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, } clk_prepare_enable(priv->stmmac_clk); + priv->pclk = devm_clk_get(priv->device, "pclk"); + if (IS_ERR(priv->pclk)) { + if (PTR_ERR(priv->pclk) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto error_pclk_get; + } + priv->pclk = NULL; + } + clk_prepare_enable(priv->pclk); + priv->stmmac_rst = devm_reset_control_get(priv->device, STMMAC_RESOURCE_NAME); if (IS_ERR(priv->stmmac_rst)) { @@ -2934,6 +2944,8 @@ error_mdio_register: error_netdev_register: netif_napi_del(&priv->napi); error_hw_init: + clk_disable_unprepare(priv->pclk); +error_pclk_get: clk_disable_unprepare(priv->stmmac_clk); error_clk_get: free_netdev(ndev); @@ -2965,6 +2977,7 @@ int stmmac_dvr_remove(struct net_device *ndev) unregister_netdev(ndev); if (priv->stmmac_rst) reset_control_assert(priv->stmmac_rst); + clk_disable_unprepare(priv->pclk); clk_disable_unprepare(priv->stmmac_clk); free_netdev(ndev); @@ -3011,6 +3024,7 @@ int stmmac_suspend(struct net_device *ndev) stmmac_set_mac(priv->ioaddr, false); pinctrl_pm_select_sleep_state(priv->device); /* Disable clock in case of PWM is off */ + clk_disable(priv->pclk); clk_disable(priv->stmmac_clk); } spin_unlock_irqrestore(&priv->lock, flags); @@ -3051,6 +3065,7 @@ int stmmac_resume(struct net_device *ndev) pinctrl_pm_select_default_state(priv->device); /* enable the clk prevously disabled */ clk_enable(priv->stmmac_clk); + clk_enable(priv->pclk); /* reset the phy so that it's ready */ if (priv->mii) stmmac_mdio_reset(priv->mii); -- cgit v1.2.3