[linux-yocto] [PATCH 21/94] drivers/net: AXM5516 emulation bringup - lsi_acp_net.c

Paul Butler butler.paul at gmail.com
Thu Nov 7 17:12:35 PST 2013


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.butler at windriver.com>
Signed-off-by: David Mercado <david.mercado at windriver.com>
Signed-off-by: John Jacques <john.jacques at 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




More information about the linux-yocto mailing list