net: macb: add support for gigabit MAC
authorBo Shen <voice.shen@atmel.com>
Wed, 24 Apr 2013 07:59:28 +0000 (15:59 +0800)
committerJoe Hershberger <joe.hershberger@ni.com>
Tue, 25 Jun 2013 00:11:16 +0000 (19:11 -0500)
Add gigabit MAC support in macb driver
  - using IP version to distinguish whether MAC is GMAC

Signed-off-by: Bo Shen <voice.shen@atmel.com>
drivers/net/macb.c
drivers/net/macb.h

index 6026825001841709d895a4abf58e27377ce2092d..b7802a2fed70828c7f9f38c10013a1f15d5abf25 100644 (file)
@@ -107,6 +107,11 @@ struct macb_device {
 };
 #define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
 
+static int macb_is_gem(struct macb_device *macb)
+{
+       return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2;
+}
+
 static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
 {
        unsigned long netctl;
@@ -427,28 +432,64 @@ static int macb_phy_init(struct macb_device *macb)
                printf("%s: link down (status: 0x%04x)\n",
                       netdev->name, status);
                return 0;
-       } else {
-               adv = macb_mdio_read(macb, MII_ADVERTISE);
-               lpa = macb_mdio_read(macb, MII_LPA);
-               media = mii_nway_result(lpa & adv);
-               speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
-                        ? 1 : 0);
-               duplex = (media & ADVERTISE_FULL) ? 1 : 0;
-               printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
-                      netdev->name,
-                      speed ? "100" : "10",
-                      duplex ? "full" : "half",
-                      lpa);
-
-               ncfgr = macb_readl(macb, NCFGR);
-               ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
-               if (speed)
-                       ncfgr |= MACB_BIT(SPD);
-               if (duplex)
-                       ncfgr |= MACB_BIT(FD);
-               macb_writel(macb, NCFGR, ncfgr);
-               return 1;
        }
+
+       /* First check for GMAC */
+       if (macb_is_gem(macb)) {
+               lpa = macb_mdio_read(macb, MII_STAT1000);
+               if (lpa & (1 << 11)) {
+                       speed = 1000;
+                       duplex = 1;
+               } else {
+                      if (lpa & (1 << 10)) {
+                               speed = 1000;
+                               duplex = 1;
+                       } else {
+                               speed = 0;
+                       }
+               }
+
+               if (speed == 1000) {
+                       printf("%s: link up, %dMbps %s-duplex (lpa: 0x%04x)\n",
+                              netdev->name,
+                              speed,
+                              duplex ? "full" : "half",
+                              lpa);
+
+                       ncfgr = macb_readl(macb, NCFGR);
+                       ncfgr &= ~(GEM_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD));
+                       if (speed)
+                               ncfgr |= GEM_BIT(GBE);
+                       if (duplex)
+                               ncfgr |= MACB_BIT(FD);
+                       macb_writel(macb, NCFGR, ncfgr);
+
+                       return 1;
+               }
+       }
+
+       /* fall back for EMAC checking */
+       adv = macb_mdio_read(macb, MII_ADVERTISE);
+       lpa = macb_mdio_read(macb, MII_LPA);
+       media = mii_nway_result(lpa & adv);
+       speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+                ? 1 : 0);
+       duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+       printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
+              netdev->name,
+              speed ? "100" : "10",
+              duplex ? "full" : "half",
+              lpa);
+
+       ncfgr = macb_readl(macb, NCFGR);
+       ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
+       if (speed)
+               ncfgr |= MACB_BIT(SPD);
+       if (duplex)
+               ncfgr |= MACB_BIT(FD);
+       macb_writel(macb, NCFGR, ncfgr);
+
+       return 1;
 }
 
 static int macb_init(struct eth_device *netdev, bd_t *bd)
@@ -483,6 +524,13 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
        macb_writel(macb, RBQP, macb->rx_ring_dma);
        macb_writel(macb, TBQP, macb->tx_ring_dma);
 
+       if (macb_is_gem(macb)) {
+#ifdef CONFIG_RGMII
+               gem_writel(macb, UR, GEM_BIT(RGMII));
+#else
+               gem_writel(macb, UR, 0);
+#endif
+       } else {
        /* choose RMII or MII mode. This depends on the board */
 #ifdef CONFIG_RMII
 #ifdef CONFIG_AT91FAMILY
@@ -497,6 +545,7 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
        macb_writel(macb, USRIO, MACB_BIT(MII));
 #endif
 #endif /* CONFIG_RMII */
+       }
 
        if (!macb_phy_init(macb))
                return -1;
@@ -540,11 +589,48 @@ static int macb_write_hwaddr(struct eth_device *dev)
        return 0;
 }
 
+static u32 macb_mdc_clk_div(int id, struct macb_device *macb)
+{
+       u32 config;
+       unsigned long macb_hz = get_macb_pclk_rate(id);
+
+       if (macb_hz < 20000000)
+               config = MACB_BF(CLK, MACB_CLK_DIV8);
+       else if (macb_hz < 40000000)
+               config = MACB_BF(CLK, MACB_CLK_DIV16);
+       else if (macb_hz < 80000000)
+               config = MACB_BF(CLK, MACB_CLK_DIV32);
+       else
+               config = MACB_BF(CLK, MACB_CLK_DIV64);
+
+       return config;
+}
+
+static u32 gem_mdc_clk_div(int id, struct macb_device *macb)
+{
+       u32 config;
+       unsigned long macb_hz = get_macb_pclk_rate(id);
+
+       if (macb_hz < 20000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV8);
+       else if (macb_hz < 40000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV16);
+       else if (macb_hz < 80000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV32);
+       else if (macb_hz < 120000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV48);
+       else if (macb_hz < 160000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV64);
+       else
+               config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+       return config;
+}
+
 int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
 {
        struct macb_device *macb;
        struct eth_device *netdev;
-       unsigned long macb_hz;
        u32 ncfgr;
 
        macb = malloc(sizeof(struct macb_device));
@@ -568,7 +654,11 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
        macb->regs = regs;
        macb->phy_addr = phy_addr;
 
-       sprintf(netdev->name, "macb%d", id);
+       if (macb_is_gem(macb))
+               sprintf(netdev->name, "gmac%d", id);
+       else
+               sprintf(netdev->name, "macb%d", id);
+
        netdev->init = macb_init;
        netdev->halt = macb_halt;
        netdev->send = macb_send;
@@ -579,15 +669,12 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
         * Do some basic initialization so that we at least can talk
         * to the PHY
         */
-       macb_hz = get_macb_pclk_rate(id);
-       if (macb_hz < 20000000)
-               ncfgr = MACB_BF(CLK, MACB_CLK_DIV8);
-       else if (macb_hz < 40000000)
-               ncfgr = MACB_BF(CLK, MACB_CLK_DIV16);
-       else if (macb_hz < 80000000)
-               ncfgr = MACB_BF(CLK, MACB_CLK_DIV32);
-       else
-               ncfgr = MACB_BF(CLK, MACB_CLK_DIV64);
+       if (macb_is_gem(macb)) {
+               ncfgr = gem_mdc_clk_div(id, macb);
+               ncfgr |= GEM_BF(DBW, 1);
+       } else {
+               ncfgr = macb_mdc_clk_div(id, macb);
+       }
 
        macb_writel(macb, NCFGR, ncfgr);
 
index f92a20c7015d04d496801ce7d9a5195095bbaac2..68eef00c03e67762e1369c3b2e4601b27975d5de 100644 (file)
@@ -26,6 +26,7 @@
 #define MACB_NCR                               0x0000
 #define MACB_NCFGR                             0x0004
 #define MACB_NSR                               0x0008
+#define GEM_UR                                 0x000c
 #define MACB_TSR                               0x0014
 #define MACB_RBQP                              0x0018
 #define MACB_TBQP                              0x001c
@@ -71,6 +72,7 @@
 #define MACB_TPQ                               0x00bc
 #define MACB_USRIO                             0x00c0
 #define MACB_WOL                               0x00c4
+#define MACB_MID                               0x00fc
 
 /* Bitfields in NCR */
 #define MACB_LB_OFFSET                         0
 #define MACB_IRXFCS_OFFSET                     19
 #define MACB_IRXFCS_SIZE                       1
 
+#define GEM_GBE_OFFSET                         10
+#define GEM_GBE_SIZE                           1
+#define GEM_CLK_OFFSET                         18
+#define GEM_CLK_SIZE                           3
+#define GEM_DBW_OFFSET                         21
+#define GEM_DBW_SIZE                           2
+
 /* Bitfields in NSR */
 #define MACB_NSR_LINK_OFFSET                   0
 #define MACB_NSR_LINK_SIZE                     1
 #define MACB_IDLE_OFFSET                       2
 #define MACB_IDLE_SIZE                         1
 
+/* Bitfields in UR */
+#define GEM_RGMII_OFFSET                       0
+#define GEM_RGMII_SIZE                         1
+
 /* Bitfields in TSR */
 #define MACB_UBR_OFFSET                                0
 #define MACB_UBR_SIZE                          1
 #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
+
+/* Bitfields in DCFG1 */
 /* Constants for CLK */
 #define MACB_CLK_DIV8                          0
 #define MACB_CLK_DIV16                         1
 #define MACB_CLK_DIV32                         2
 #define MACB_CLK_DIV64                         3
 
+/* GEM specific constants for CLK */
+#define GEM_CLK_DIV8                           0
+#define GEM_CLK_DIV16                          1
+#define GEM_CLK_DIV32                          2
+#define GEM_CLK_DIV48                          3
+#define GEM_CLK_DIV64                          4
+#define GEM_CLK_DIV96                          5
+
 /* Constants for MAN register */
 #define MACB_MAN_SOF                           1
 #define MACB_MAN_WRITE                         1
 /* Bit manipulation macros */
 #define MACB_BIT(name)                                 \
        (1 << MACB_##name##_OFFSET)
-#define MACB_BF(name,value)                            \
+#define MACB_BF(name, value)                           \
        (((value) & ((1 << MACB_##name##_SIZE) - 1))    \
         << MACB_##name##_OFFSET)
-#define MACB_BFEXT(name,value)\
+#define MACB_BFEXT(name, value)\
        (((value) >> MACB_##name##_OFFSET)              \
         & ((1 << MACB_##name##_SIZE) - 1))
-#define MACB_BFINS(name,value,old)                     \
+#define MACB_BFINS(name, value, old)                   \
        (((old) & ~(((1 << MACB_##name##_SIZE) - 1)     \
                    << MACB_##name##_OFFSET))           \
-        | MACB_BF(name,value))
+        | 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)                           \
+#define macb_readl(port, reg)                          \
        readl((port)->regs + MACB_##reg)
-#define macb_writel(port,reg,value)                    \
+#define macb_writel(port, reg, value)                  \
        writel((value), (port)->regs + MACB_##reg)
+#define gem_readl(port, reg)                           \
+       readl((port)->regs + GEM_##reg)
+#define gem_writel(port, reg, value)                   \
+       writel((value), (port)->regs + GEM_##reg)
 
 #endif /* __DRIVERS_MACB_H__ */