The driver takes phy address as a parameter but ignores it, and instead takes the first available phy in the address range. This patch allows one to select a specific phy on boards that have multiple phys. Support for the new BCM 5221 phy - acp_net
Signed-off-by: Paul Butler <paul.but...@windriver.com> Signed-off-by: David Mercado <david.merc...@windriver.com> Signed-off-by: John Jacques <john.jacq...@lsi.com> --- drivers/net/ethernet/lsi/lsi_acp_net.c | 207 ++++++++++++++++++++++++++++----- 1 file changed, 181 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/lsi/lsi_acp_net.c b/drivers/net/ethernet/lsi/lsi_acp_net.c index 605a431..331c8e4 100644 --- a/drivers/net/ethernet/lsi/lsi_acp_net.c +++ b/drivers/net/ethernet/lsi/lsi_acp_net.c @@ -20,7 +20,9 @@ * * NOTES: * - * 1) This driver parses the DTB for driver specific settings. A few of + * 1) This driver is used by both ACP (PPC) and AXM (ARM) platforms. + * + * 2) This driver parses the DTB for driver specific settings. A few of * them can be overriden by setting environment variables in U-boot: * * ethaddr - MAC address of interface, in xx:xx:xx:xx:xx:xx format @@ -59,6 +61,8 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/dma-mapping.h> #include <linux/uaccess.h> @@ -68,9 +72,12 @@ #include <asm/lsi/acp_ncr.h> #include "lsi_acp_net.h" +#undef AMARILLO_WA +/*#define AMARILLO_WA*/ + #define LSI_DRV_NAME "acp-femac" #define LSI_MDIO_NAME "acp-femac-mdio" -#define LSI_DRV_VERSION "2013-04-30" +#define LSI_DRV_VERSION "2013-09-10" MODULE_AUTHOR("John Jacques"); MODULE_DESCRIPTION("LSI ACP-FEMAC Ethernet driver"); @@ -81,6 +88,10 @@ static void *rx_base; static void *tx_base; static void *dma_base; +/* BCM5221 registers */ +#define PHY_BCM_TEST_REG 0x1f +#define PHY_AUXILIARY_MODE3 0x1d + /* * ---------------------------------------------------------------------- * appnic_mii_read @@ -124,9 +135,13 @@ static void appnic_handle_link_change(struct net_device *dev) unsigned long tx_configuration = 0; rx_configuration = +#ifdef CONFIG_ARM + APPNIC_RX_CONF_STRIPCRC; +#else (APPNIC_RX_CONF_STRIPCRC | APPNIC_RX_CONF_RXFCE | APPNIC_RX_CONF_TXFCE); +#endif tx_configuration = (APPNIC_TX_CONF_ENABLE_SWAP_SA | APPNIC_TX_CONF_APP_CRC_ENABLE | @@ -178,6 +193,11 @@ static void appnic_handle_link_change(struct net_device *dev) netdev_info(dev, "link down\n"); } +#ifdef AMARILLO_WA + rx_configuration &= ~0x1000; + tx_configuration &= ~0x1000; +#endif + if (rx_configuration != read_mac(APPNIC_RX_CONF)) write_mac(rx_configuration, APPNIC_RX_CONF); @@ -199,13 +219,35 @@ static int appnic_mii_probe(struct net_device *dev) struct phy_device *phydev = NULL; int ret; + if (pdata->phy_address && (pdata->phy_address < PHY_MAX_ADDR)) { + phydev = pdata->mii_bus->phy_map[pdata->phy_address]; + if (phydev) + goto skip_first; + } + /* Find the first phy */ phydev = phy_find_first(pdata->mii_bus); if (!phydev) { + pr_crit("!!! no PHY found !!!\n"); netdev_err(dev, " no PHY found\n"); return -ENODEV; } +skip_first: + + /* + * For the Axxia AXM, allow the option to disable auto + * negotiation and manually specify the speed and duplex + * setting with the use of a environment setting. + */ + if (0 == pdata->phy_link_auto) { + phydev->autoneg = AUTONEG_DISABLE; + phydev->speed = + 0 == pdata->phy_link_speed ? SPEED_10 : SPEED_100; + phydev->duplex = + 0 == pdata->phy_link_duplex ? DUPLEX_HALF : DUPLEX_FULL; + } + ret = phy_connect_direct(dev, phydev, &appnic_handle_link_change, 0, PHY_INTERFACE_MODE_MII); @@ -215,6 +257,29 @@ static int appnic_mii_probe(struct net_device *dev) return ret; } +#ifdef CONFIG_ARCH_AXXIA + /* + * For the Axxia AXM, set RX FIFO size to 0x7. + */ + { + u16 val; + int rc; + + /* Enable access to shadow register @ 0x1d */ + rc = acp_mdio_read(phydev->addr, PHY_BCM_TEST_REG, &val); + val |= 0x80; + rc = acp_mdio_write(phydev->addr, PHY_BCM_TEST_REG, val); + + /* Set RX FIFO size to 0x7 */ + rc = acp_mdio_write(phydev->addr, PHY_AUXILIARY_MODE3, 0x7); + + /* Disable access to shadow register @ 0x1d */ + rc = acp_mdio_read(phydev->addr, PHY_BCM_TEST_REG, &val); + val &= ~0x80; + rc = acp_mdio_write(phydev->addr, PHY_BCM_TEST_REG, val); + } +#endif + netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", phydev->drv->name, dev_name(&phydev->dev), phydev->irq); @@ -663,7 +728,8 @@ static void lsinet_rx_packet(struct net_device *dev) struct sk_buff *sk_buff; unsigned bytes_copied = 0; unsigned error_num = 0; - unsigned long ok_stat, overflow_stat, crc_stat, align_stat; + unsigned long ok_stat = 0, overflow_stat = 0; + unsigned long crc_stat = 0, align_stat = 0; spin_lock(&pdata->extra_lock); @@ -679,10 +745,12 @@ static void lsinet_rx_packet(struct net_device *dev) return; } +#if 0 /* DAVE - why is this commented out? */ ok_stat = read_mac(APPNIC_RX_STAT_PACKET_OK); overflow_stat = read_mac(APPNIC_RX_STAT_OVERFLOW); crc_stat = read_mac(APPNIC_RX_STAT_CRC_ERROR); align_stat = read_mac(APPNIC_RX_STAT_ALIGN_ERROR); +#endif /* * Copy the received packet into the skb. @@ -1053,6 +1121,7 @@ static int appnic_hard_start_xmit(struct sk_buff *skb, length = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; buf_per_desc = pdata->tx_buf_sz / pdata->tx_num_desc; + /* dump_registers(dev); */ /* * If enough transmit descriptors are available, copy and transmit. */ @@ -1118,6 +1187,10 @@ static int appnic_hard_start_xmit(struct sk_buff *skb, descriptor.start_of_packet = 0; } +#ifdef CONFIG_ARM + /* ARM Data sync barrier */ + asm volatile ("mcr p15,0,%0,c7,c10,4" : : "r" (0)); +#endif write_mac(pdata->tx_head.raw, APPNIC_DMA_TX_HEAD_POINTER); dev->trans_start = jiffies; } else { @@ -1347,21 +1420,29 @@ int appnic_init(struct net_device *dev) /* The TX buffer (and padding...) */ (pdata->tx_buf_sz) + (BUFFER_ALIGNMENT); - /* * This needs to be set to something sane for * dma_alloc_coherent() */ - dev->dev.archdata.dma_ops = &dma_direct_ops; +#if defined(CONFIG_ARM) + pdata->dma_alloc = (void *) + dma_alloc_coherent(NULL, + pdata->dma_alloc_size, + &pdata->dma_alloc_dma, + GFP_KERNEL); +#else + device->dev.archdata.dma_ops = &dma_direct_ops; - pdata->dma_alloc = (void *)dma_alloc_coherent(&dev->dev, - pdata->dma_alloc_size, - &pdata->dma_alloc_dma, - GFP_KERNEL); + pdata->dma_alloc = (void *) + dma_alloc_coherent(&device->dev, + pdata->dma_alloc_size, + &pdata->dma_alloc_dma, + GFP_KERNEL); +#endif if ((void *)0 == pdata->dma_alloc) { - pr_err("%s: Could not allocate %d bytes of DMA-able memory!\n", + pr_err("%s: Can't allocate %d bytes of DMA-able memory!\n", LSI_DRV_NAME, pdata->dma_alloc_size); kfree(pdata); return -ENOMEM; @@ -1370,13 +1451,17 @@ int appnic_init(struct net_device *dev) pdata->dma_alloc_offset = (int)pdata->dma_alloc - (int)pdata->dma_alloc_dma; +#ifdef CONFIG_ARM + pdata->dma_alloc_rx = (void *)dma_alloc_coherent(NULL, +#else pdata->dma_alloc_rx = (void *)dma_alloc_coherent(&dev->dev, +#endif pdata->dma_alloc_size_rx, &pdata->dma_alloc_dma_rx, GFP_KERNEL); if ((void *)0 == pdata->dma_alloc_rx) { - pr_err("%s: Could not allocate %d bytes of DMA-able memory!\n", + pr_err("%s: Can't allocate %d bytes of RX DMA-able memory!\n", LSI_DRV_NAME, pdata->dma_alloc_size_rx); dma_free_coherent(&dev->dev, pdata->dma_alloc_size, pdata->dma_alloc, pdata->dma_alloc_dma); @@ -1387,13 +1472,17 @@ int appnic_init(struct net_device *dev) pdata->dma_alloc_offset_rx = (int)pdata->dma_alloc_rx - (int)pdata->dma_alloc_dma_rx; +#ifdef CONFIG_ARM + pdata->dma_alloc_tx = (void *)dma_alloc_coherent(NULL, +#else pdata->dma_alloc_tx = (void *)dma_alloc_coherent(&dev->dev, +#endif pdata->dma_alloc_size_tx, &pdata->dma_alloc_dma_tx, GFP_KERNEL); if ((void *)0 == pdata->dma_alloc_tx) { - pr_err("%s: Could not allocate %d bytes of DMA-able memory!\n", + pr_err("%s: Can't allocate %d bytes of TX DMA-able memory!\n", LSI_DRV_NAME, pdata->dma_alloc_size_tx); dma_free_coherent(&dev->dev, pdata->dma_alloc_size, pdata->dma_alloc, pdata->dma_alloc_dma); @@ -1414,16 +1503,16 @@ int appnic_init(struct net_device *dev) pdata->rx_tail = (union appnic_queue_pointer *)dma_offset; pdata->rx_tail_dma = (int)pdata->rx_tail - (int)pdata->dma_alloc_offset; + dma_offset += sizeof(union appnic_queue_pointer); memset((void *)pdata->rx_tail, 0, sizeof(union appnic_queue_pointer)); - dma_offset += sizeof(union appnic_queue_pointer); pdata->tx_tail = (union appnic_queue_pointer *)dma_offset; pdata->tx_tail_dma = (int)pdata->tx_tail - (int)pdata->dma_alloc_offset; + dma_offset += sizeof(union appnic_queue_pointer); memset((void *)pdata->tx_tail, 0, sizeof(union appnic_queue_pointer)); - dma_offset += sizeof(union appnic_queue_pointer); /* * Initialize the descriptor pointers @@ -1431,14 +1520,15 @@ int appnic_init(struct net_device *dev) pdata->rx_desc = (struct appnic_dma_descriptor *)ALIGN64B(dma_offset); pdata->rx_desc_dma = (int)pdata->rx_desc - (int)pdata->dma_alloc_offset; - memset((void *)pdata->rx_desc, 0, - (sizeof(struct appnic_dma_descriptor) * pdata->rx_num_desc)); - dma_offset += (sizeof(struct appnic_dma_descriptor) * pdata->rx_num_desc) + (DESCRIPTOR_GRANULARITY); + memset((void *)pdata->rx_desc, 0, + (sizeof(struct appnic_dma_descriptor) * pdata->rx_num_desc)); pdata->tx_desc = (struct appnic_dma_descriptor *)ALIGN64B(dma_offset); pdata->tx_desc_dma = (int)pdata->tx_desc - (int)pdata->dma_alloc_offset; + dma_offset += (sizeof(struct appnic_dma_descriptor) * + pdata->tx_num_desc) + (DESCRIPTOR_GRANULARITY); memset((void *)pdata->tx_desc, 0, (sizeof(struct appnic_dma_descriptor) * pdata->tx_num_desc)); @@ -1511,10 +1601,7 @@ int appnic_init(struct net_device *dev) write_mac(0x1, APPNIC_RX_MODE); write_mac(0x0, APPNIC_TX_SOFT_RESET); write_mac(0x1, APPNIC_TX_MODE); - if (is_asic()) - write_mac(0x300a, APPNIC_TX_WATERMARK); - else - write_mac(0xc00096, APPNIC_TX_WATERMARK); + write_mac(0x300a, APPNIC_TX_WATERMARK); write_mac(0x1, APPNIC_TX_HALF_DUPLEX_CONF); write_mac(0xffff, APPNIC_TX_TIME_VALUE_CONF); write_mac(0x1, APPNIC_TX_INTERRUPT_CONTROL); @@ -1523,12 +1610,20 @@ int appnic_init(struct net_device *dev) write_mac(0x1, APPNIC_RX_EXTERNAL_INTERRUPT_CONTROL); write_mac(0x40010000, APPNIC_DMA_PCI_CONTROL); write_mac(0x30000, APPNIC_DMA_CONTROL); +#ifdef CONFIG_ARM + writel(0x280044, dma_base + 0x60); + writel(0xc0, dma_base + 0x64); +#else out_le32(dma_base + 0x60, 0x280044); out_le32(dma_base + 0x64, 0xc0); +#endif /* * Set the MAC address */ + pr_info("%s: MAC %02x:%02x:%02x:%02x:%02x:%02x\n", LSI_DRV_NAME, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); memcpy(&(address.sa_data[0]), dev->dev_addr, 6); appnic_set_mac_address(dev, &address); @@ -1612,7 +1707,10 @@ int appnic_init(struct net_device *dev) /* Fill in the net_device structure */ ether_setup(dev); - dev->irq = irq_create_mapping(NULL, pdata->interrupt); +#ifdef CONFIG_ARM + dev->irq = pdata->dma_interrupt; +#else + dev->irq = irq_create_mapping(NULL, pdata->dma_interrupt); if (NO_IRQ == dev->irq) { pr_err("%s: irq_create_mapping() failed\n", LSI_DRV_NAME); return -EBUSY; @@ -1622,6 +1720,7 @@ int appnic_init(struct net_device *dev) pr_err("%s: set_irq_type() failed\n", LSI_DRV_NAME); return -EBUSY; } +#endif dev->netdev_ops = &appnic_netdev_ops; @@ -1663,13 +1762,22 @@ static int __devinit appnic_probe_config_dt(struct net_device *dev, { struct appnic_device *pdata = netdev_priv(dev); const u32 *field; +#ifndef CONFIG_ARM u64 value64; u32 value32; +#else + const char *macspeed; +#endif int length; if (!np) return -ENODEV; +#ifdef CONFIG_ARM + rx_base = of_iomap(np, 0); + tx_base = of_iomap(np, 1); + dma_base = of_iomap(np, 2); +#else field = of_get_property(np, "enabled", NULL); if (!field || (field && (0 == *field))) @@ -1686,41 +1794,88 @@ static int __devinit appnic_probe_config_dt(struct net_device *dev, value32 = field[1]; field += 2; rx_base = ioremap(value64, value32); - pdata->rx_base = (unsigned long)rx_base; value64 = of_translate_address(np, field); value32 = field[1]; field += 2; tx_base = ioremap(value64, value32); - pdata->tx_base = (unsigned long)tx_base; value64 = of_translate_address(np, field); value32 = field[1]; field += 2; dma_base = ioremap(value64, value32); +#endif + pdata->rx_base = (unsigned long)rx_base; + pdata->tx_base = (unsigned long)tx_base; pdata->dma_base = (unsigned long)dma_base; +#ifdef CONFIG_ARM + pdata->tx_interrupt = irq_of_parse_and_map(np, 0); + pdata->rx_interrupt = irq_of_parse_and_map(np, 1); + pdata->dma_interrupt = irq_of_parse_and_map(np, 2); +#else field = of_get_property(np, "interrupts", NULL); if (!field) goto device_tree_failed; else - pdata->interrupt = field[0]; - + pdata->dma_interrupt = field[0]; +#endif field = of_get_property(np, "mdio-clock", NULL); if (!field) goto device_tree_failed; else +#ifdef CONFIG_ARM + pdata->mdio_clock = swab32(field[0]); +#else pdata->mdio_clock = field[0]; +#endif field = of_get_property(np, "phy-address", NULL); if (!field) goto device_tree_failed; else +#ifdef CONFIG_ARM + pdata->phy_address = swab32(field[0]); +#else pdata->phy_address = field[0]; +#endif field = of_get_property(np, "ad-value", NULL); if (!field) goto device_tree_failed; else +#ifdef CONFIG_ARM + pdata->ad_value = swab32(field[0]); +#else pdata->ad_value = field[0]; +#endif + +#ifdef CONFIG_ARM + macspeed = of_get_property(np, "phy-link", NULL); + + if (macspeed) { + if (0 == strncmp(macspeed, "auto", strlen("auto"))) { + pdata->phy_link_auto = 1; + } else if (0 == strncmp(macspeed, "100MF", strlen("100MF"))) { + pdata->phy_link_auto = 0; + pdata->phy_link_speed = 1; + pdata->phy_link_duplex = 1; + } else if (0 == strncmp(macspeed, "100MH", strlen("100MH"))) { + pdata->phy_link_auto = 0; + pdata->phy_link_speed = 1; + pdata->phy_link_duplex = 0; + } else if (0 == strncmp(macspeed, "10MF", strlen("10MF"))) { + pdata->phy_link_auto = 0; + pdata->phy_link_speed = 0; + pdata->phy_link_duplex = 1; + } else if (0 == strncmp(macspeed, "10MH", strlen("10MH"))) { + pdata->phy_link_auto = 0; + pdata->phy_link_speed = 0; + pdata->phy_link_duplex = 0; + } + } else { + /* Auto is the default. */ + pdata->phy_link_auto = 1; + } +#endif field = of_get_property(np, "mac-address", &length); if (!field || 6 != length) { -- 1.8.3.4 _______________________________________________ linux-yocto mailing list linux-yocto@yoctoproject.org https://lists.yoctoproject.org/listinfo/linux-yocto