From 9743dce55a1ebaeae924eb5773088f994ba41b65 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 6 Sep 2013 12:35:28 +0200 Subject: [PATCH 01/12] net: designware: Fix broken cache invalidate Move the cache invalidation of a received packet before we actually use it. Signed-off-by: Sascha Hauer --- drivers/net/designware.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/designware.c b/drivers/net/designware.c index a6b32b9b2..45de31c60 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -337,14 +337,15 @@ static int dwc_ether_rx(struct eth_device *dev) length = (status & DESC_RXSTS_FRMLENMSK) >> \ DESC_RXSTS_FRMLENSHFT; - net_receive(desc_p->dmamac_addr, length); - /* * Make the current descriptor valid again and go to * the next one */ dma_inv_range((unsigned long)desc_p->dmamac_addr, (unsigned long)desc_p->dmamac_addr + length); + + net_receive(desc_p->dmamac_addr, length); + desc_p->txrx_status |= DESC_RXSTS_OWNBYDMA; /* Test the wrap-around condition. */ From 5302030510c3b51fec00a351aa25f7c82a2e2c07 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 5 Sep 2013 10:47:00 +0200 Subject: [PATCH 02/12] net: designware: drop HAS_DESIGNWARE_ETH To let the driver just compile when needed. Signed-off-by: Sascha Hauer --- drivers/net/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 5ad3e4d46..bd04531a2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -130,7 +130,6 @@ config DRIVER_NET_KS8851_MLL config DRIVER_NET_DESIGNWARE bool "Designware Universal MAC ethernet driver" select PHYLIB - depends on HAS_DESIGNWARE_ETH help This option enables support for the Synopsys Designware Core Univesal MAC 10M/100M/1G ethernet IP. From f8db2d225eff443d4464f92253829ee6607200db Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 5 Sep 2013 10:48:15 +0200 Subject: [PATCH 03/12] net: designware: use dma_alloc for descriptors Signed-off-by: Sascha Hauer --- drivers/net/designware.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 45de31c60..33d734544 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -418,8 +418,8 @@ static int dwc_ether_probe(struct device_d *dev) CONFIG_TX_DESCR_NUM * sizeof(struct dmamacdescr)); priv->rx_mac_descrtable = dma_alloc_coherent( CONFIG_RX_DESCR_NUM * sizeof(struct dmamacdescr)); - priv->txbuffs = malloc(TX_TOTAL_BUFSIZE); - priv->rxbuffs = malloc(RX_TOTAL_BUFSIZE); + priv->txbuffs = dma_alloc(TX_TOTAL_BUFSIZE); + priv->rxbuffs = dma_alloc(RX_TOTAL_BUFSIZE); priv->fix_mac_speed = pdata->fix_mac_speed; edev = &priv->netdev; From 8c3c7c5d646f377fd52cda3b79a84808c6c7bbec Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 9 Sep 2013 14:11:48 +0200 Subject: [PATCH 04/12] net: designware: make alt/enhanced descriptor runtime configurable Instead of hardcoding the alternate/enhanced descriptor layout make it configurable during runtime. This is based on the value of the enh_desc variable which is currently hardcoded to zero. This should be configurable via device_id in the future. Since currently we have no in tree user of this driver this currently doesn't hurt. Signed-off-by: Sascha Hauer --- drivers/net/Kconfig | 5 ---- drivers/net/designware.c | 62 +++++++++++++++++++++------------------- drivers/net/designware.h | 60 ++++++++++++++------------------------ 3 files changed, 54 insertions(+), 73 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index bd04531a2..5d7d20f08 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -134,11 +134,6 @@ config DRIVER_NET_DESIGNWARE This option enables support for the Synopsys Designware Core Univesal MAC 10M/100M/1G ethernet IP. -config DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR - bool - depends on DRIVER_NET_DESIGNWARE - default n - config DRIVER_NET_GIANFAR bool "Gianfar Ethernet" depends on ARCH_MPC85XX diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 33d734544..0b5390d73 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -54,6 +54,7 @@ struct dw_eth_dev { struct eth_dma_regs *dma_regs_p; int phy_addr; phy_interface_t interface; + int enh_desc; }; /* Speed specific definitions */ @@ -149,19 +150,19 @@ static void tx_descs_init(struct eth_device *dev) desc_p->dmamac_addr = &txbuffs[idx * CONFIG_ETH_BUFSIZE]; desc_p->dmamac_next = &desc_table_p[idx + 1]; -#if defined(CONFIG_DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR) - desc_p->txrx_status &= ~(DESC_TXSTS_TXINT | DESC_TXSTS_TXLAST | - DESC_TXSTS_TXFIRST | DESC_TXSTS_TXCRCDIS | \ - DESC_TXSTS_TXCHECKINSCTRL | \ - DESC_TXSTS_TXRINGEND | DESC_TXSTS_TXPADDIS); + if (priv->enh_desc) { + desc_p->txrx_status &= ~(DESC_ENH_TXSTS_TXINT | DESC_ENH_TXSTS_TXLAST | + DESC_ENH_TXSTS_TXFIRST | DESC_ENH_TXSTS_TXCRCDIS | + DESC_ENH_TXSTS_TXCHECKINSCTRL | + DESC_ENH_TXSTS_TXRINGEND | DESC_ENH_TXSTS_TXPADDIS); - desc_p->txrx_status |= DESC_TXSTS_TXCHAIN; - desc_p->dmamac_cntl = 0; - desc_p->txrx_status &= ~(DESC_TXSTS_MSK | DESC_TXSTS_OWNBYDMA); -#else - desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN; - desc_p->txrx_status = 0; -#endif + desc_p->txrx_status |= DESC_ENH_TXSTS_TXCHAIN; + desc_p->dmamac_cntl = 0; + desc_p->txrx_status &= ~(DESC_ENH_TXSTS_MSK | DESC_ENH_TXSTS_OWNBYDMA); + } else { + desc_p->dmamac_cntl = DESC_TXCTRL_TXCHAIN; + desc_p->txrx_status = 0; + } } /* Correcting the last pointer of the chain */ @@ -184,9 +185,11 @@ static void rx_descs_init(struct eth_device *dev) desc_p->dmamac_addr = &rxbuffs[idx * CONFIG_ETH_BUFSIZE]; desc_p->dmamac_next = &desc_table_p[idx + 1]; - desc_p->dmamac_cntl = - (MAC_MAX_FRAME_SZ & DESC_RXCTRL_SIZE1MASK) | \ - DESC_RXCTRL_RXCHAIN; + desc_p->dmamac_cntl = MAC_MAX_FRAME_SZ; + if (priv->enh_desc) + desc_p->dmamac_cntl |= DESC_ENH_RXCTRL_RXCHAIN; + else + desc_p->dmamac_cntl |= DESC_RXCTRL_RXCHAIN; dma_inv_range((unsigned long)desc_p->dmamac_addr, (unsigned long)desc_p->dmamac_addr + CONFIG_ETH_BUFSIZE); @@ -282,11 +285,12 @@ static int dwc_ether_send(struct eth_device *dev, void *packet, int length) { struct dw_eth_dev *priv = dev->priv; struct eth_dma_regs *dma_p = priv->dma_regs_p; - u32 desc_num = priv->tx_currdescnum; + u32 owndma, desc_num = priv->tx_currdescnum; struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num]; + owndma = priv->enh_desc ? DESC_ENH_TXSTS_OWNBYDMA : DESC_TXSTS_OWNBYDMA; /* Check if the descriptor is owned by CPU */ - if (desc_p->txrx_status & DESC_TXSTS_OWNBYDMA) { + if (desc_p->txrx_status & owndma) { dev_err(&dev->dev, "CPU not owner of tx frame\n"); return -1; } @@ -295,20 +299,20 @@ static int dwc_ether_send(struct eth_device *dev, void *packet, int length) dma_flush_range((unsigned long)desc_p->dmamac_addr, (unsigned long)desc_p->dmamac_addr + length); -#if defined(CONFIG_DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR) - desc_p->txrx_status |= DESC_TXSTS_TXFIRST | DESC_TXSTS_TXLAST; - desc_p->dmamac_cntl |= (length << DESC_TXCTRL_SIZE1SHFT) & \ - DESC_TXCTRL_SIZE1MASK; + if (priv->enh_desc) { + desc_p->txrx_status |= DESC_ENH_TXSTS_TXFIRST | DESC_ENH_TXSTS_TXLAST; + desc_p->dmamac_cntl |= (length << DESC_ENH_TXCTRL_SIZE1SHFT) & + DESC_ENH_TXCTRL_SIZE1MASK; - desc_p->txrx_status &= ~(DESC_TXSTS_MSK); - desc_p->txrx_status |= DESC_TXSTS_OWNBYDMA; -#else - desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & \ - DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | \ - DESC_TXCTRL_TXFIRST; + desc_p->txrx_status &= ~(DESC_ENH_TXSTS_MSK); + desc_p->txrx_status |= DESC_ENH_TXSTS_OWNBYDMA; + } else { + desc_p->dmamac_cntl |= ((length << DESC_TXCTRL_SIZE1SHFT) & + DESC_TXCTRL_SIZE1MASK) | DESC_TXCTRL_TXLAST | + DESC_TXCTRL_TXFIRST; - desc_p->txrx_status = DESC_TXSTS_OWNBYDMA; -#endif + desc_p->txrx_status = DESC_TXSTS_OWNBYDMA; + } /* Test the wrap-around condition. */ if (++desc_num >= CONFIG_TX_DESCR_NUM) diff --git a/drivers/net/designware.h b/drivers/net/designware.h index db2ead48a..f7b14be6c 100644 --- a/drivers/net/designware.h +++ b/drivers/net/designware.h @@ -130,27 +130,21 @@ struct dmamacdescr { */ /* tx status bits definitions */ -#if defined(CONFIG_DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR) +#define DESC_ENH_TXSTS_OWNBYDMA (1 << 31) +#define DESC_ENH_TXSTS_TXINT (1 << 30) +#define DESC_ENH_TXSTS_TXLAST (1 << 29) +#define DESC_ENH_TXSTS_TXFIRST (1 << 28) +#define DESC_ENH_TXSTS_TXCRCDIS (1 << 27) -#define DESC_TXSTS_OWNBYDMA (1 << 31) -#define DESC_TXSTS_TXINT (1 << 30) -#define DESC_TXSTS_TXLAST (1 << 29) -#define DESC_TXSTS_TXFIRST (1 << 28) -#define DESC_TXSTS_TXCRCDIS (1 << 27) - -#define DESC_TXSTS_TXPADDIS (1 << 26) -#define DESC_TXSTS_TXCHECKINSCTRL (3 << 22) -#define DESC_TXSTS_TXRINGEND (1 << 21) -#define DESC_TXSTS_TXCHAIN (1 << 20) -#define DESC_TXSTS_MSK (0x1FFFF << 0) - -#else +#define DESC_ENH_TXSTS_TXPADDIS (1 << 26) +#define DESC_ENH_TXSTS_TXCHECKINSCTRL (3 << 22) +#define DESC_ENH_TXSTS_TXRINGEND (1 << 21) +#define DESC_ENH_TXSTS_TXCHAIN (1 << 20) +#define DESC_ENH_TXSTS_MSK (0x1FFFF << 0) #define DESC_TXSTS_OWNBYDMA (1 << 31) #define DESC_TXSTS_MSK (0x1FFFF << 0) -#endif - /* rx status bits definitions */ #define DESC_RXSTS_OWNBYDMA (1 << 31) #define DESC_RXSTS_DAFILTERFAIL (1 << 30) @@ -178,14 +172,10 @@ struct dmamacdescr { */ /* tx control bits definitions */ -#if defined(CONFIG_DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR) - -#define DESC_TXCTRL_SIZE1MASK (0x1FFF << 0) -#define DESC_TXCTRL_SIZE1SHFT (0) -#define DESC_TXCTRL_SIZE2MASK (0x1FFF << 16) -#define DESC_TXCTRL_SIZE2SHFT (16) - -#else +#define DESC_ENH_TXCTRL_SIZE1MASK (0x1FFF << 0) +#define DESC_ENH_TXCTRL_SIZE1SHFT (0) +#define DESC_ENH_TXCTRL_SIZE2MASK (0x1FFF << 16) +#define DESC_ENH_TXCTRL_SIZE2SHFT (16) #define DESC_TXCTRL_TXINT (1 << 31) #define DESC_TXCTRL_TXLAST (1 << 30) @@ -200,21 +190,15 @@ struct dmamacdescr { #define DESC_TXCTRL_SIZE2MASK (0x7FF << 11) #define DESC_TXCTRL_SIZE2SHFT (11) -#endif - /* rx control bits definitions */ -#if defined(CONFIG_DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR) +#define DESC_ENH_RXCTRL_RXINTDIS (1 << 31) +#define DESC_ENH_RXCTRL_RXRINGEND (1 << 15) +#define DESC_ENH_RXCTRL_RXCHAIN (1 << 14) -#define DESC_RXCTRL_RXINTDIS (1 << 31) -#define DESC_RXCTRL_RXRINGEND (1 << 15) -#define DESC_RXCTRL_RXCHAIN (1 << 14) - -#define DESC_RXCTRL_SIZE1MASK (0x1FFF << 0) -#define DESC_RXCTRL_SIZE1SHFT (0) -#define DESC_RXCTRL_SIZE2MASK (0x1FFF << 16) -#define DESC_RXCTRL_SIZE2SHFT (16) - -#else +#define DESC_ENH_RXCTRL_SIZE1MASK (0x1FFF << 0) +#define DESC_ENH_RXCTRL_SIZE1SHFT (0) +#define DESC_ENH_RXCTRL_SIZE2MASK (0x1FFF << 16) +#define DESC_ENH_RXCTRL_SIZE2SHFT (16) #define DESC_RXCTRL_RXINTDIS (1 << 31) #define DESC_RXCTRL_RXRINGEND (1 << 25) @@ -226,5 +210,3 @@ struct dmamacdescr { #define DESC_RXCTRL_SIZE2SHFT (11) #endif - -#endif From c7278cc6250063ea7493b2ac817099cbaa221b2e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 4 Sep 2013 23:10:06 +0200 Subject: [PATCH 05/12] net: designware: Add decvicetree support Signed-off-by: Sascha Hauer --- drivers/net/designware.c | 54 +++++++++++++++++++++++++++++++++------- include/net/designware.h | 1 + 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 0b5390d73..a71e2e922 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -29,12 +29,12 @@ #include #include #include +#include #include #include #include #include "designware.h" - struct dw_eth_dev { struct eth_device netdev; struct mii_bus miibus; @@ -57,6 +57,14 @@ struct dw_eth_dev { int enh_desc; }; +struct dw_eth_drvdata { + bool enh_desc; +}; + +static struct dw_eth_drvdata dwmac_370a_drvdata = { + .enh_desc = 1, +}; + /* Speed specific definitions */ #define SPEED_10M 1 #define SPEED_100M 2 @@ -399,6 +407,14 @@ static void dwc_version(struct device_d *dev, u32 hwid) uid, synid); } +static int dwc_probe_dt(struct device_d *dev, struct dw_eth_dev *priv) +{ + priv->phy_addr = -1; + priv->interface = of_get_phy_mode(dev->device_node); + + return 0; +} + static int dwc_ether_probe(struct device_d *dev) { struct dw_eth_dev *priv; @@ -406,14 +422,27 @@ static int dwc_ether_probe(struct device_d *dev) struct mii_bus *miibus; void __iomem *base; struct dwc_ether_platform_data *pdata = dev->platform_data; - - if (!pdata) { - printf("dwc_ether: no platform_data\n"); - return -ENODEV; - } + int ret; + struct dw_eth_drvdata *drvdata; priv = xzalloc(sizeof(struct dw_eth_dev)); + ret = dev_get_drvdata(dev, (unsigned long *)&drvdata); + if (ret) + return ret; + + priv->enh_desc = drvdata->enh_desc; + + if (pdata) { + priv->phy_addr = pdata->phy_addr; + priv->interface = pdata->interface; + priv->fix_mac_speed = pdata->fix_mac_speed; + } else { + ret = dwc_probe_dt(dev, priv); + if (ret) + return ret; + } + base = dev_request_mem_region(dev, 0); priv->mac_regs_p = base; dwc_version(dev, readl(&priv->mac_regs_p->version)); @@ -424,7 +453,6 @@ static int dwc_ether_probe(struct device_d *dev) CONFIG_RX_DESCR_NUM * sizeof(struct dmamacdescr)); priv->txbuffs = dma_alloc(TX_TOTAL_BUFSIZE); priv->rxbuffs = dma_alloc(RX_TOTAL_BUFSIZE); - priv->fix_mac_speed = pdata->fix_mac_speed; edev = &priv->netdev; miibus = &priv->miibus; @@ -439,8 +467,6 @@ static int dwc_ether_probe(struct device_d *dev) edev->get_ethaddr = dwc_ether_get_ethaddr; edev->set_ethaddr = dwc_ether_set_ethaddr; - priv->phy_addr = pdata->phy_addr; - priv->interface = pdata->interface; miibus->parent = dev; miibus->read = dwc_ether_mii_read; miibus->write = dwc_ether_mii_write; @@ -455,9 +481,19 @@ static void dwc_ether_remove(struct device_d *dev) { } +static __maybe_unused struct of_device_id dwc_ether_compatible[] = { + { + .compatible = "snps,dwmac-3.70a", + .data = (unsigned long)&dwmac_370a_drvdata, + }, { + /* sentinel */ + } +}; + static struct driver_d dwc_ether_driver = { .name = "designware_eth", .probe = dwc_ether_probe, .remove = dwc_ether_remove, + .of_compatible = DRV_OF_COMPAT(dwc_ether_compatible), }; device_platform_driver(dwc_ether_driver); diff --git a/include/net/designware.h b/include/net/designware.h index 3f31c9761..7a7a26abf 100644 --- a/include/net/designware.h +++ b/include/net/designware.h @@ -7,6 +7,7 @@ struct dwc_ether_platform_data { int phy_addr; phy_interface_t interface; void (*fix_mac_speed)(int speed); + bool enh_desc; /* use Alternate/Enhanced Descriptor configurations */ }; #endif From 38b3be6f35baaf6f683f762b9111505502f91dbb Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 5 Sep 2013 00:20:36 +0200 Subject: [PATCH 06/12] net: designware: remove backspaces from code Signed-off-by: Sascha Hauer --- drivers/net/designware.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/designware.c b/drivers/net/designware.c index a71e2e922..ecb4656e9 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -82,7 +82,7 @@ static int dwc_ether_mii_read(struct mii_bus *dev, int addr, int reg) u64 start; u32 miiaddr; - miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ + miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | ((reg << MIIREGSHIFT) & MII_REGMSK); writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); @@ -105,7 +105,7 @@ static int dwc_ether_mii_write(struct mii_bus *dev, int addr, int reg, u16 val) u32 miiaddr; writel(val, &mac_p->miidata); - miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | \ + miiaddr = ((addr << MIIADDRSHIFT) & MII_ADDRMSK) | ((reg << MIIREGSHIFT) & MII_REGMSK) | MII_WRITE; writel(miiaddr | MII_CLKRANGE_150_250M | MII_BUSY, &mac_p->miiaddr); @@ -346,7 +346,7 @@ static int dwc_ether_rx(struct eth_device *dev) if (status & DESC_RXSTS_OWNBYDMA) return 0; - length = (status & DESC_RXSTS_FRMLENMSK) >> \ + length = (status & DESC_RXSTS_FRMLENMSK) >> DESC_RXSTS_FRMLENSHFT; /* @@ -389,7 +389,7 @@ static int dwc_ether_set_ethaddr(struct eth_device *dev, u8 adr[6]) struct eth_mac_regs *mac_p = priv->mac_regs_p; u32 macid_lo, macid_hi; - macid_lo = adr[0] + (adr[1] << 8) + \ + macid_lo = adr[0] + (adr[1] << 8) + (adr[2] << 16) + (adr[3] << 24); macid_hi = adr[4] + (adr[5] << 8); writel(macid_hi, &mac_p->macaddr0hi); From 7e6b99fd09fa149529bf3397db9707c24826ffa7 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Sun, 22 Sep 2013 07:12:23 +0200 Subject: [PATCH 07/12] smc91111: add fixup for qemu phy support as today qemu does not support phy, it will return always 0x0 to any read on the mii bus. So the phy_id is 0 and the link is donw. To have the norwork running on versatilpb & other qenu board for the link up at 100Mbps. Only enable if qemu_fixup is set. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- drivers/net/smc91111.c | 30 +++++++++++++++++++++++++++++- include/net/smc91111.h | 14 ++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 include/net/smc91111.h diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c index b868cbf19..ba81e2499 100644 --- a/drivers/net/smc91111.c +++ b/drivers/net/smc91111.c @@ -66,6 +66,7 @@ #include #include #include +#include /*--------------------------------------------------------------- . @@ -446,6 +447,7 @@ struct smc91c111_priv { struct mii_bus miibus; struct accessors a; void __iomem *base; + int qemu_fixup; }; #if (SMC_DEBUG > 2 ) @@ -882,6 +884,7 @@ static void smc91c111_enable(struct eth_device *edev) static int smc91c111_eth_open(struct eth_device *edev) { struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv; + int ret; /* Configure the Receive/Phy Control register */ SMC_SELECT_BANK(priv, 0); @@ -889,8 +892,27 @@ static int smc91c111_eth_open(struct eth_device *edev) smc91c111_enable(edev); - return phy_device_connect(edev, &priv->miibus, 0, NULL, + ret = phy_device_connect(edev, &priv->miibus, 0, NULL, 0, PHY_INTERFACE_MODE_NA); + + if (ret) + return ret; + + if (priv->qemu_fixup && edev->phydev->phy_id == 0x00000000) { + struct phy_device *dev = edev->phydev; + + dev->speed = SPEED_100; + dev->duplex = DUPLEX_FULL; + dev->autoneg = !AUTONEG_ENABLE; + dev->force = 1; + dev->link = 1; + + dev_info(edev->parent, "phy with id 0x%08x detected this might be qemu\n", + dev->phy_id); + dev_info(edev->parent, "force link at 100Mpbs\n"); + } + + return 0; } static int smc91c111_eth_send(struct eth_device *edev, void *packet, @@ -1286,6 +1308,12 @@ static int smc91c111_probe(struct device_d *dev) priv = edev->priv; + if (dev->platform_data) { + struct smc91c111_pdata *pdata = dev->platform_data; + + priv->qemu_fixup = pdata->qemu_fixup; + } + priv->a = access_via_32bit; edev->init = smc91c111_init_dev; diff --git a/include/net/smc91111.h b/include/net/smc91111.h new file mode 100644 index 000000000..0b2d49bb1 --- /dev/null +++ b/include/net/smc91111.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2013 Jean-Christophe PLAGNIOL-VILLARD + * + * Under GPLv2 only + */ + +#ifndef __SMC91111_H__ +#define __SMC91111_H__ + +struct smc91c111_pdata { + int qemu_fixup; +}; + +#endif /* __SMC91111_H__ */ From 189678dc6763271e7fad16ef1ee25806e79c4b4f Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Sun, 22 Sep 2013 07:12:24 +0200 Subject: [PATCH 08/12] versatilepb: enable qemu fixup Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- arch/arm/boards/versatile/versatilepb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/boards/versatile/versatilepb.c b/arch/arm/boards/versatile/versatilepb.c index ebf36954e..3df59bac1 100644 --- a/arch/arm/boards/versatile/versatilepb.c +++ b/arch/arm/boards/versatile/versatilepb.c @@ -28,6 +28,7 @@ #include #include #include +#include static int vpb_console_init(void) { @@ -47,6 +48,10 @@ static int vpb_mem_init(void) } mem_initcall(vpb_mem_init); +static struct smc91c111_pdata net_pdata = { + .qemu_fixup = 1, +}; + static int vpb_devices_init(void) { add_cfi_flash_device(DEVICE_ID_DYNAMIC, VERSATILE_FLASH_BASE, VERSATILE_FLASH_SIZE, 0); @@ -55,7 +60,7 @@ static int vpb_devices_init(void) devfs_add_partition("nor0", 0x40000, 0x20000, DEVFS_PARTITION_FIXED, "env0"); add_generic_device("smc91c111", DEVICE_ID_DYNAMIC, NULL, VERSATILE_ETH_BASE, - 64 * 1024, IORESOURCE_MEM, NULL); + 64 * 1024, IORESOURCE_MEM, &net_pdata); armlinux_set_architecture(MACH_TYPE_VERSATILE_PB); armlinux_set_bootparams((void *)(0x00000100)); From 3293c860ab539de5e35bc29907ed7bd2cd1e5ad6 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 20 Sep 2013 07:47:43 +0200 Subject: [PATCH 09/12] introduce helper to generate mac address with OUI use random mac address with fixed OUI provided Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- include/local_mac_address.h | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 include/local_mac_address.h diff --git a/include/local_mac_address.h b/include/local_mac_address.h new file mode 100644 index 000000000..3d1ec66b1 --- /dev/null +++ b/include/local_mac_address.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD + * + * Under GPLv2 only + */ + +#ifndef __LOCAL_MAC_ADDRESS_H__ +#define __LOCAL_MAC_ADDRESS_H__ + +#include + +/** + * local_mac_address_register - use random number with fix + * OUI provided device to provide an Ethernet address + * @ethid: ethernet device id + * @oui: Ethernet OUI (3 bytes) + * + * Generate a local Ethernet address (MAC) that is not multicast using a 1-wire id. + */ +static inline int local_mac_address_register(int ethid, char * oui) +{ + char addr[6]; + int nb_oui = 3; + int i; + + if (!oui) + return -EINVAL; + + random_ether_addr(addr); + + for (i = 0; i < nb_oui; i++) + addr[i] = oui[i]; + + addr[0] &= 0xfe; /* clear multicast bit */ + addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ + + eth_register_ethaddr(ethid, addr); + + return 0; +} + +#endif /* __LOCAL_MAC_ADDRESS_H__ */ From 6e419891d209ebbae87b361a90c089fec747693a Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 20 Sep 2013 07:47:44 +0200 Subject: [PATCH 10/12] animeo_ip: ensure the phy is reset correctly Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- arch/arm/boards/animeo_ip/init.c | 38 +++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/arch/arm/boards/animeo_ip/init.c b/arch/arm/boards/animeo_ip/init.c index 06d542e58..b30605dd3 100644 --- a/arch/arm/boards/animeo_ip/init.c +++ b/arch/arm/boards/animeo_ip/init.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -208,12 +209,45 @@ static void animeo_ip_power_control(void) animeo_export_gpio_out(AT91_PIN_PC4, "power_save"); } +static void animeo_ip_phy_reset(void) +{ + unsigned long rstc; + int i; + struct clk *clk = clk_get(NULL, "macb_clk"); + + clk_enable(clk); + + for (i = AT91_PIN_PA12; i <= AT91_PIN_PA29; i++) + at91_set_gpio_input(i, 0); + + rstc = at91_sys_read(AT91_RSTC_MR) & AT91_RSTC_ERSTL; + + /* Need to reset PHY -> 500ms reset */ + at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | + (AT91_RSTC_ERSTL & (0x0d << 8)) | + AT91_RSTC_URSTEN); + + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_EXTRST); + + /* Wait for end hardware reset */ + while (!(at91_sys_read(AT91_RSTC_SR) & AT91_RSTC_NRSTL)) + ; + + /* Restore NRST value */ + at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | (rstc) | AT91_RSTC_URSTEN); +} + +static void animeo_ip_add_device_eth(void) +{ + animeo_ip_phy_reset(); + at91_add_device_eth(0, &macb_pdata); +} + static int animeo_ip_devices_init(void) { animeo_ip_detect_version(); animeo_ip_power_control(); animeo_ip_add_device_nand(); - at91_add_device_eth(0, &macb_pdata); animeo_ip_add_device_mci(); animeo_ip_add_device_buttons(); animeo_ip_add_device_led(); @@ -232,6 +266,8 @@ static int animeo_ip_devices_init(void) devfs_add_partition("nand0", SZ_256K + SZ_32K, SZ_32K, DEVFS_PARTITION_FIXED, "env_raw"); dev_add_bb_dev("env_raw", "env0"); + animeo_ip_add_device_eth(); + return 0; } From a99a74f87faf6ae2cb7922095b1e24a39c74c166 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Fri, 20 Sep 2013 07:47:45 +0200 Subject: [PATCH 11/12] animeo_ip: retrieve the mac from the macb and set private mac to asix if the macb's mac is not a valid public mac set a private with "smf" as OUI as the mac address might be set by the previous bootloader set a private with "smf" as OUI for asix Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- arch/arm/boards/animeo_ip/init.c | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/arm/boards/animeo_ip/init.c b/arch/arm/boards/animeo_ip/init.c index b30605dd3..5f070d2c0 100644 --- a/arch/arm/boards/animeo_ip/init.c +++ b/arch/arm/boards/animeo_ip/init.c @@ -27,6 +27,7 @@ #include #include #include +#include static bool animeo_ip_is_buco; static bool animeo_ip_is_io; @@ -237,8 +238,42 @@ static void animeo_ip_phy_reset(void) at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | (rstc) | AT91_RSTC_URSTEN); } +#define MACB_SA1B 0x0098 +#define MACB_SA1T 0x009c + +static int animeo_ip_get_macb_ethaddr(u8 *addr) +{ + u32 top, bottom; + void __iomem *base = IOMEM(AT91SAM9260_BASE_EMAC); + + bottom = readl(base + MACB_SA1B); + top = readl(base + MACB_SA1T); + addr[0] = bottom & 0xff; + addr[1] = (bottom >> 8) & 0xff; + addr[2] = (bottom >> 16) & 0xff; + addr[3] = (bottom >> 24) & 0xff; + addr[4] = top & 0xff; + addr[5] = (top >> 8) & 0xff; + + /* valid and not private */ + if (is_valid_ether_addr(addr) && !(addr[0] & 0x02)) + return 0; + + return -EINVAL; +} + static void animeo_ip_add_device_eth(void) { + u8 enetaddr[6]; + + if (!animeo_ip_get_macb_ethaddr(enetaddr)) + eth_register_ethaddr(0, enetaddr); + else + local_mac_address_register(0, "smf"); + + /* for usb asix */ + local_mac_address_register(1, "smf"); + animeo_ip_phy_reset(); at91_add_device_eth(0, &macb_pdata); } From 7ccaaf71fe84f090b359d8d21e76aaff84d295f0 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Thu, 3 Oct 2013 11:45:29 +0200 Subject: [PATCH 12/12] macb: add support to read the mac address from register check the 4 mac address register and return at the first valid Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Sascha Hauer --- drivers/net/macb.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/macb.c b/drivers/net/macb.c index b1f544b5a..d8523cee3 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -458,9 +458,31 @@ static int macb_phy_write(struct mii_bus *bus, int addr, int reg, u16 value) static int macb_get_ethaddr(struct eth_device *edev, unsigned char *adr) { struct macb_device *macb = edev->priv; + u32 bottom; + u16 top; + u8 addr[6]; + int i; dev_dbg(macb->dev, "%s\n", __func__); + /* Check all 4 address register for vaild address */ + for (i = 0; i < 4; i++) { + bottom = macb_or_gem_readl(macb, SA1B + i * 8); + top = macb_or_gem_readl(macb, SA1T + i * 8); + + addr[0] = bottom & 0xff; + addr[1] = (bottom >> 8) & 0xff; + addr[2] = (bottom >> 16) & 0xff; + addr[3] = (bottom >> 24) & 0xff; + addr[4] = top & 0xff; + addr[5] = (top >> 8) & 0xff; + + if (is_valid_ether_addr(addr)) { + memcpy(adr, addr, sizeof(addr)); + return 0; + } + } + return -1; }