net: macb: add support for gigabit MAC
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>
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 6026825..b7802a2 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -107,6 +107,11 @@
};
#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 @@
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 @@
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 @@
macb_writel(macb, USRIO, MACB_BIT(MII));
#endif
#endif /* CONFIG_RMII */
+ }
if (!macb_phy_init(macb))
return -1;
@@ -540,11 +589,48 @@
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 @@
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 @@
* 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);
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index f92a20c..68eef00 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -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
@@ -138,6 +140,13 @@
#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
@@ -146,6 +155,10 @@
#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
@@ -240,12 +253,25 @@
#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
@@ -255,21 +281,38 @@
/* 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__ */