[linux-yocto] [PATCH 016/161] drivers/net: AXM5516 emulation bringup - lsi_acp_net.c
Cristian Bercaru
cristian.bercaru at windriver.com
Thu May 21 12:19:58 PDT 2015
From: John Jacques <john.jacques at lsi.com>
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 | 205 ++++++++++++++++++++++++++++----
1 file changed, 179 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..56cb258 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);
@@ -1053,6 +1119,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 +1185,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 +1418,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 +1449,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 +1470,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 +1501,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 +1518,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 +1599,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 +1608,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 +1705,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 +1718,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 +1760,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 +1792,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.7.9.5
More information about the linux-yocto
mailing list