macb: initial support for Cadence GEM
authorJamie Iles <jamie.iles@mathembedded.com>
Tue, 8 Nov 2011 10:12:32 +0000 (10:12 +0000)
committerJamie Iles <jamie@jamieiles.com>
Tue, 22 Nov 2011 15:21:17 +0000 (15:21 +0000)
The Cadence GEM is based on the MACB Ethernet controller but has a few
small changes with regards to register and bitfield placement.  This
patch detects the presence of a GEM by reading the module ID register
and setting a flag appropriately.

This handles the new HW address, USRIO and hash register base register
locations in GEM.

v3: - convert to macb_is_gem() inline rather than storing a boolean
      flag
    - handle rx_overrun stats for gem

Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Cc: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Tested-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
drivers/net/ethernet/Makefile
drivers/net/ethernet/cadence/Kconfig
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h

index be5dde0..94b7f28 100644 (file)
@@ -10,7 +10,7 @@ obj-$(CONFIG_NET_VENDOR_ALTEON) += alteon/
 obj-$(CONFIG_NET_VENDOR_AMD) += amd/
 obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
 obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
-obj-$(CONFIG_NET_ATMEL) += cadence/
+obj-$(CONFIG_NET_CADENCE) += cadence/
 obj-$(CONFIG_NET_BFIN) += adi/
 obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
 obj-$(CONFIG_NET_VENDOR_BROCADE) += brocade/
index 98849a1..a2e1500 100644 (file)
@@ -5,8 +5,8 @@
 config HAVE_NET_MACB
        bool
 
-config NET_ATMEL
-       bool "Atmel devices"
+config NET_CADENCE
+       bool "Cadence devices"
        depends on HAVE_NET_MACB || (ARM && ARCH_AT91RM9200)
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y.
@@ -20,7 +20,7 @@ config NET_ATMEL
          the remaining Atmel network card questions. If you say Y, you will be
          asked for your specific card in the following questions.
 
-if NET_ATMEL
+if NET_CADENCE
 
 config ARM_AT91_ETHER
        tristate "AT91RM9200 Ethernet support"
@@ -32,14 +32,16 @@ config ARM_AT91_ETHER
          ethernet support, then you should always answer Y to this.
 
 config MACB
-       tristate "Atmel MACB support"
+       tristate "Cadence MACB/GEM support"
        depends on HAVE_NET_MACB
        select PHYLIB
        ---help---
-         The Atmel MACB ethernet interface is found on many AT32 and AT91
-         parts. Say Y to include support for the MACB chip.
+         The Cadence MACB ethernet interface is found on many Atmel AT32 and
+         AT91 parts.  This driver also supports the Cadence GEM (Gigabit
+         Ethernet MAC found in some ARM SoC devices).  Note: the Gigabit mode
+         is not yet supported.  Say Y to include support for the MACB/GEM chip.
 
          To compile this driver as a module, choose M here: the module
          will be called macb.
 
-endif # NET_ATMEL
+endif # NET_CADENCE
index aa1d597..4e61a86 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Atmel MACB Ethernet Controller driver
+ * Cadence MACB/GEM Ethernet Controller driver
  *
  * Copyright (C) 2004-2006 Atmel Corporation
  *
@@ -59,9 +59,9 @@ static void __macb_set_hwaddr(struct macb *bp)
        u16 top;
 
        bottom = cpu_to_le32(*((u32 *)bp->dev->dev_addr));
-       macb_writel(bp, SA1B, bottom);
+       macb_or_gem_writel(bp, SA1B, bottom);
        top = cpu_to_le16(*((u16 *)(bp->dev->dev_addr + 4)));
-       macb_writel(bp, SA1T, top);
+       macb_or_gem_writel(bp, SA1T, top);
 }
 
 static void __init macb_get_hwaddr(struct macb *bp)
@@ -70,8 +70,8 @@ static void __init macb_get_hwaddr(struct macb *bp)
        u16 top;
        u8 addr[6];
 
-       bottom = macb_readl(bp, SA1B);
-       top = macb_readl(bp, SA1T);
+       bottom = macb_or_gem_readl(bp, SA1B);
+       top = macb_or_gem_readl(bp, SA1T);
 
        addr[0] = bottom & 0xff;
        addr[1] = (bottom >> 8) & 0xff;
@@ -580,7 +580,10 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
 
                if (status & MACB_BIT(ISR_ROVR)) {
                        /* We missed at least one packet */
-                       bp->hw_stats.rx_overruns++;
+                       if (macb_is_gem(bp))
+                               bp->hw_stats.gem.rx_overruns++;
+                       else
+                               bp->hw_stats.macb.rx_overruns++;
                }
 
                if (status & MACB_BIT(HRESP)) {
@@ -902,8 +905,8 @@ static void macb_sethashtable(struct net_device *dev)
                mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
        }
 
-       macb_writel(bp, HRB, mc_filter[0]);
-       macb_writel(bp, HRT, mc_filter[1]);
+       macb_or_gem_writel(bp, HRB, mc_filter[0]);
+       macb_or_gem_writel(bp, HRT, mc_filter[1]);
 }
 
 /*
@@ -925,8 +928,8 @@ static void macb_set_rx_mode(struct net_device *dev)
 
        if (dev->flags & IFF_ALLMULTI) {
                /* Enable all multicast mode */
-               macb_writel(bp, HRB, -1);
-               macb_writel(bp, HRT, -1);
+               macb_or_gem_writel(bp, HRB, -1);
+               macb_or_gem_writel(bp, HRT, -1);
                cfg |= MACB_BIT(NCFGR_MTI);
        } else if (!netdev_mc_empty(dev)) {
                /* Enable specific multicasts */
@@ -934,8 +937,8 @@ static void macb_set_rx_mode(struct net_device *dev)
                cfg |= MACB_BIT(NCFGR_MTI);
        } else if (dev->flags & (~IFF_ALLMULTI)) {
                /* Disable all multicast mode */
-               macb_writel(bp, HRB, 0);
-               macb_writel(bp, HRT, 0);
+               macb_or_gem_writel(bp, HRB, 0);
+               macb_or_gem_writel(bp, HRT, 0);
                cfg &= ~MACB_BIT(NCFGR_MTI);
        }
 
@@ -1196,15 +1199,16 @@ static int __init macb_probe(struct platform_device *pdev)
 
        if (pdata && pdata->is_rmii)
 #if defined(CONFIG_ARCH_AT91)
-               macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
+               macb_or_gem_writel(bp, USRIO, (MACB_BIT(RMII) |
+                                              MACB_BIT(CLKEN)));
 #else
-               macb_writel(bp, USRIO, 0);
+               macb_or_gem_writel(bp, USRIO, 0);
 #endif
        else
 #if defined(CONFIG_ARCH_AT91)
-               macb_writel(bp, USRIO, MACB_BIT(CLKEN));
+               macb_or_gem_writel(bp, USRIO, MACB_BIT(CLKEN));
 #else
-               macb_writel(bp, USRIO, MACB_BIT(MII));
+               macb_or_gem_writel(bp, USRIO, MACB_BIT(MII));
 #endif
 
        bp->tx_pending = DEF_TX_RING_PENDING;
@@ -1221,8 +1225,9 @@ static int __init macb_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dev);
 
-       netdev_info(dev, "Atmel MACB at 0x%08lx irq %d (%pM)\n",
-               dev->base_addr, dev->irq, dev->dev_addr);
+       netdev_info(dev, "Cadence %s at 0x%08lx irq %d (%pM)\n",
+                   macb_is_gem(bp) ? "GEM" : "MACB", dev->base_addr,
+                   dev->irq, dev->dev_addr);
 
        phydev = bp->phy_dev;
        netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
@@ -1332,6 +1337,6 @@ module_init(macb_init);
 module_exit(macb_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Atmel MACB Ethernet driver");
+MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver");
 MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
 MODULE_ALIAS("platform:macb");
index d3212f6..d50057c 100644 (file)
 #define MACB_TPQ                               0x00bc
 #define MACB_USRIO                             0x00c0
 #define MACB_WOL                               0x00c4
+#define MACB_MID                               0x00fc
+
+/* GEM register offsets. */
+#define GEM_NCFGR                              0x0004
+#define GEM_USRIO                              0x000c
+#define GEM_HRB                                        0x0080
+#define GEM_HRT                                        0x0084
+#define GEM_SA1B                               0x0088
+#define GEM_SA1T                               0x008C
 
 /* Bitfields in NCR */
 #define MACB_LB_OFFSET                         0
 #define MACB_WOL_MTI_OFFSET                    19
 #define MACB_WOL_MTI_SIZE                      1
 
+/* Bitfields in MID */
+#define MACB_IDNUM_OFFSET                      16
+#define MACB_IDNUM_SIZE                                16
+#define MACB_REV_OFFSET                                0
+#define MACB_REV_SIZE                          16
+
 /* Constants for CLK */
 #define MACB_CLK_DIV8                          0
 #define MACB_CLK_DIV16                         1
                    << MACB_##name##_OFFSET))           \
         | MACB_BF(name,value))
 
+#define GEM_BIT(name)                                  \
+       (1 << GEM_##name##_OFFSET)
+#define GEM_BF(name, value)                            \
+       (((value) & ((1 << GEM_##name##_SIZE) - 1))     \
+        << GEM_##name##_OFFSET)
+#define GEM_BFEXT(name, value)\
+       (((value) >> GEM_##name##_OFFSET)               \
+        & ((1 << GEM_##name##_SIZE) - 1))
+#define GEM_BFINS(name, value, old)                    \
+       (((old) & ~(((1 << GEM_##name##_SIZE) - 1)      \
+                   << GEM_##name##_OFFSET))            \
+        | GEM_BF(name, value))
+
 /* Register access macros */
 #define macb_readl(port,reg)                           \
        __raw_readl((port)->regs + MACB_##reg)
 #define macb_writel(port,reg,value)                    \
        __raw_writel((value), (port)->regs + MACB_##reg)
+#define gem_readl(port, reg)                           \
+       __raw_readl((port)->regs + GEM_##reg)
+#define gem_writel(port, reg, value)                   \
+       __raw_writel((value), (port)->regs + GEM_##reg)
+
+/*
+ * Conditional GEM/MACB macros.  These perform the operation to the correct
+ * register dependent on whether the device is a GEM or a MACB.  For registers
+ * and bitfields that are common across both devices, use macb_{read,write}l
+ * to avoid the cost of the conditional.
+ */
+#define macb_or_gem_writel(__bp, __reg, __value) \
+       ({ \
+               if (macb_is_gem((__bp))) \
+                       gem_writel((__bp), __reg, __value); \
+               else \
+                       macb_writel((__bp), __reg, __value); \
+       })
+
+#define macb_or_gem_readl(__bp, __reg) \
+       ({ \
+               u32 __v; \
+               if (macb_is_gem((__bp))) \
+                       __v = gem_readl((__bp), __reg); \
+               else \
+                       __v = macb_readl((__bp), __reg); \
+               __v; \
+       })
 
 struct dma_desc {
        u32     addr;
@@ -391,4 +447,9 @@ struct macb {
        unsigned int            duplex;
 };
 
+static inline bool macb_is_gem(struct macb *bp)
+{
+       return MACB_BFEXT(IDNUM, macb_readl(bp, MID)) == 0x2;
+}
+
 #endif /* _MACB_H */