]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - drivers/net/macb.c
Merge branch 'master' of git://git.denx.de/u-boot-nand-flash
[karo-tx-uboot.git] / drivers / net / macb.c
index 08bebf74a5c5ec83ef426a6b4ab2bd99f74caca1..b7802a2fed70828c7f9f38c10013a1f15d5abf25 100644 (file)
@@ -28,7 +28,7 @@
  * allocate our own, but we need one such buffer in case a packet
  * wraps around the DMA ring so that we have to copy it.
  *
- * Therefore, define CFG_RX_ETH_BUFFER to 1 in the board-specific
+ * Therefore, define CONFIG_SYS_RX_ETH_BUFFER to 1 in the board-specific
  * configuration header.  This way, the core allocates one RX buffer
  * and one TX buffer, each of which can hold a ethernet packet of
  * maximum size.
@@ -42,6 +42,7 @@
 #include <net.h>
 #include <netdev.h>
 #include <malloc.h>
+#include <miiphy.h>
 
 #include <linux/mii.h>
 #include <asm/io.h>
 
 #include "macb.h"
 
-#define barrier() asm volatile("" ::: "memory")
-
-#define CFG_MACB_RX_BUFFER_SIZE                4096
-#define CFG_MACB_RX_RING_SIZE          (CFG_MACB_RX_BUFFER_SIZE / 128)
-#define CFG_MACB_TX_RING_SIZE          16
-#define CFG_MACB_TX_TIMEOUT            1000
-#define CFG_MACB_AUTONEG_TIMEOUT       5000000
+#define CONFIG_SYS_MACB_RX_BUFFER_SIZE         4096
+#define CONFIG_SYS_MACB_RX_RING_SIZE           (CONFIG_SYS_MACB_RX_BUFFER_SIZE / 128)
+#define CONFIG_SYS_MACB_TX_RING_SIZE           16
+#define CONFIG_SYS_MACB_TX_TIMEOUT             1000
+#define CONFIG_SYS_MACB_AUTONEG_TIMEOUT        5000000
 
 struct macb_dma_desc {
        u32     addr;
@@ -104,9 +103,15 @@ struct macb_device {
        const struct device     *dev;
        struct eth_device       netdev;
        unsigned short          phy_addr;
+       struct mii_dev          *bus;
 };
 #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;
@@ -164,10 +169,46 @@ static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
        return MACB_BFEXT(DATA, frame);
 }
 
+void __weak arch_get_mdio_control(const char *name)
+{
+       return;
+}
+
+#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
+
+int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
+{
+       struct eth_device *dev = eth_get_dev_by_name(devname);
+       struct macb_device *macb = to_macb(dev);
+
+       if ( macb->phy_addr != phy_adr )
+               return -1;
+
+       arch_get_mdio_control(devname);
+       *value = macb_mdio_read(macb, reg);
+
+       return 0;
+}
+
+int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
+{
+       struct eth_device *dev = eth_get_dev_by_name(devname);
+       struct macb_device *macb = to_macb(dev);
+
+       if ( macb->phy_addr != phy_adr )
+               return -1;
+
+       arch_get_mdio_control(devname);
+       macb_mdio_write(macb, reg, value);
+
+       return 0;
+}
+#endif
+
+
 #if defined(CONFIG_CMD_NET)
 
-static int macb_send(struct eth_device *netdev, volatile void *packet,
-                    int length)
+static int macb_send(struct eth_device *netdev, void *packet, int length)
 {
        struct macb_device *macb = to_macb(netdev);
        unsigned long paddr, ctrl;
@@ -178,7 +219,7 @@ static int macb_send(struct eth_device *netdev, volatile void *packet,
 
        ctrl = length & TXBUF_FRMLEN_MASK;
        ctrl |= TXBUF_FRAME_END;
-       if (tx_head == (CFG_MACB_TX_RING_SIZE - 1)) {
+       if (tx_head == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) {
                ctrl |= TXBUF_WRAP;
                macb->tx_head = 0;
        } else
@@ -193,7 +234,7 @@ static int macb_send(struct eth_device *netdev, volatile void *packet,
         * I guess this is necessary because the networking core may
         * re-use the transmit buffer as soon as we return...
         */
-       for (i = 0; i <= CFG_MACB_TX_TIMEOUT; i++) {
+       for (i = 0; i <= CONFIG_SYS_MACB_TX_TIMEOUT; i++) {
                barrier();
                ctrl = macb->tx_ring[tx_head].ctrl;
                if (ctrl & TXBUF_USED)
@@ -203,7 +244,7 @@ static int macb_send(struct eth_device *netdev, volatile void *packet,
 
        dma_unmap_single(packet, length, paddr);
 
-       if (i <= CFG_MACB_TX_TIMEOUT) {
+       if (i <= CONFIG_SYS_MACB_TX_TIMEOUT) {
                if (ctrl & TXBUF_UNDERRUN)
                        printf("%s: TX underrun\n", netdev->name);
                if (ctrl & TXBUF_EXHAUSTED)
@@ -226,7 +267,7 @@ static void reclaim_rx_buffers(struct macb_device *macb,
        while (i > new_tail) {
                macb->rx_ring[i].addr &= ~RXADDR_USED;
                i++;
-               if (i > CFG_MACB_RX_RING_SIZE)
+               if (i > CONFIG_SYS_MACB_RX_RING_SIZE)
                        i = 0;
        }
 
@@ -265,7 +306,7 @@ static int macb_recv(struct eth_device *netdev)
                        if (wrapped) {
                                unsigned int headlen, taillen;
 
-                               headlen = 128 * (CFG_MACB_RX_RING_SIZE
+                               headlen = 128 * (CONFIG_SYS_MACB_RX_RING_SIZE
                                                 - macb->rx_tail);
                                taillen = length - headlen;
                                memcpy((void *)NetRxPackets[0],
@@ -276,11 +317,11 @@ static int macb_recv(struct eth_device *netdev)
                        }
 
                        NetReceive(buffer, length);
-                       if (++rx_tail >= CFG_MACB_RX_RING_SIZE)
+                       if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE)
                                rx_tail = 0;
                        reclaim_rx_buffers(macb, rx_tail);
                } else {
-                       if (++rx_tail >= CFG_MACB_RX_RING_SIZE) {
+                       if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) {
                                wrapped = 1;
                                rx_tail = 0;
                        }
@@ -303,7 +344,7 @@ static void macb_phy_reset(struct macb_device *macb)
        macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
                                         | BMCR_ANRESTART));
 
-       for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
+       for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) {
                status = macb_mdio_read(macb, MII_BMSR);
                if (status & BMSR_ANEGCOMPLETE)
                        break;
@@ -317,14 +358,49 @@ static void macb_phy_reset(struct macb_device *macb)
                       netdev->name, status);
 }
 
+#ifdef CONFIG_MACB_SEARCH_PHY
+static int macb_phy_find(struct macb_device *macb)
+{
+       int i;
+       u16 phy_id;
+
+       /* Search for PHY... */
+       for (i = 0; i < 32; i++) {
+               macb->phy_addr = i;
+               phy_id = macb_mdio_read(macb, MII_PHYSID1);
+               if (phy_id != 0xffff) {
+                       printf("%s: PHY present at %d\n", macb->netdev.name, i);
+                       return 1;
+               }
+       }
+
+       /* PHY isn't up to snuff */
+       printf("%s: PHY not found\n", macb->netdev.name);
+
+       return 0;
+}
+#endif /* CONFIG_MACB_SEARCH_PHY */
+
+
 static int macb_phy_init(struct macb_device *macb)
 {
        struct eth_device *netdev = &macb->netdev;
+#ifdef CONFIG_PHYLIB
+       struct phy_device *phydev;
+#endif
        u32 ncfgr;
        u16 phy_id, status, adv, lpa;
        int media, speed, duplex;
        int i;
 
+       arch_get_mdio_control(netdev->name);
+#ifdef CONFIG_MACB_SEARCH_PHY
+       /* Auto-detect phy_addr */
+       if (!macb_phy_find(macb)) {
+               return 0;
+       }
+#endif /* CONFIG_MACB_SEARCH_PHY */
+
        /* Check if the PHY is up to snuff... */
        phy_id = macb_mdio_read(macb, MII_PHYSID1);
        if (phy_id == 0xffff) {
@@ -332,12 +408,19 @@ static int macb_phy_init(struct macb_device *macb)
                return 0;
        }
 
+#ifdef CONFIG_PHYLIB
+       phydev->bus = macb->bus;
+       phydev->dev = netdev;
+       phydev->addr = macb->phy_addr;
+       phy_config(phydev);
+#endif
+
        status = macb_mdio_read(macb, MII_BMSR);
        if (!(status & BMSR_LSTATUS)) {
                /* Try to re-negotiate if we don't have link already. */
                macb_phy_reset(macb);
 
-               for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) {
+               for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) {
                        status = macb_mdio_read(macb, MII_BMSR);
                        if (status & BMSR_LSTATUS)
                                break;
@@ -349,36 +432,70 @@ 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)
 {
        struct macb_device *macb = to_macb(netdev);
        unsigned long paddr;
-       u32 hwaddr_bottom;
-       u16 hwaddr_top;
        int i;
 
        /*
@@ -388,16 +505,16 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
 
        /* initialize DMA descriptors */
        paddr = macb->rx_buffer_dma;
-       for (i = 0; i < CFG_MACB_RX_RING_SIZE; i++) {
-               if (i == (CFG_MACB_RX_RING_SIZE - 1))
+       for (i = 0; i < CONFIG_SYS_MACB_RX_RING_SIZE; i++) {
+               if (i == (CONFIG_SYS_MACB_RX_RING_SIZE - 1))
                        paddr |= RXADDR_WRAP;
                macb->rx_ring[i].addr = paddr;
                macb->rx_ring[i].ctrl = 0;
                paddr += 128;
        }
-       for (i = 0; i < CFG_MACB_TX_RING_SIZE; i++) {
+       for (i = 0; i < CONFIG_SYS_MACB_TX_RING_SIZE; i++) {
                macb->tx_ring[i].addr = 0;
-               if (i == (CFG_MACB_TX_RING_SIZE - 1))
+               if (i == (CONFIG_SYS_MACB_TX_RING_SIZE - 1))
                        macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
                else
                        macb->tx_ring[i].ctrl = TXBUF_USED;
@@ -407,28 +524,28 @@ 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);
 
-       /* set hardware address */
-       hwaddr_bottom = cpu_to_le32(*((u32 *)netdev->enetaddr));
-       macb_writel(macb, SA1B, hwaddr_bottom);
-       hwaddr_top = cpu_to_le16(*((u16 *)(netdev->enetaddr + 4)));
-       macb_writel(macb, SA1T, hwaddr_top);
-
+       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
-#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
-    defined(CONFIG_AT91SAM9263)
+#ifdef CONFIG_AT91FAMILY
        macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN));
 #else
        macb_writel(macb, USRIO, 0);
 #endif
 #else
-#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
-    defined(CONFIG_AT91SAM9263)
+#ifdef CONFIG_AT91FAMILY
        macb_writel(macb, USRIO, MACB_BIT(CLKEN));
 #else
        macb_writel(macb, USRIO, MACB_BIT(MII));
 #endif
 #endif /* CONFIG_RMII */
+       }
 
        if (!macb_phy_init(macb))
                return -1;
@@ -457,11 +574,63 @@ static void macb_halt(struct eth_device *netdev)
        macb_writel(macb, NCR, MACB_BIT(CLRSTAT));
 }
 
+static int macb_write_hwaddr(struct eth_device *dev)
+{
+       struct macb_device *macb = to_macb(dev);
+       u32 hwaddr_bottom;
+       u16 hwaddr_top;
+
+       /* set hardware address */
+       hwaddr_bottom = dev->enetaddr[0] | dev->enetaddr[1] << 8 |
+                       dev->enetaddr[2] << 16 | dev->enetaddr[3] << 24;
+       macb_writel(macb, SA1B, hwaddr_bottom);
+       hwaddr_top = dev->enetaddr[4] | dev->enetaddr[5] << 8;
+       macb_writel(macb, SA1T, hwaddr_top);
+       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));
@@ -473,120 +642,48 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
 
        netdev = &macb->netdev;
 
-       macb->rx_buffer = dma_alloc_coherent(CFG_MACB_RX_BUFFER_SIZE,
+       macb->rx_buffer = dma_alloc_coherent(CONFIG_SYS_MACB_RX_BUFFER_SIZE,
                                             &macb->rx_buffer_dma);
-       macb->rx_ring = dma_alloc_coherent(CFG_MACB_RX_RING_SIZE
+       macb->rx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_RX_RING_SIZE
                                           * sizeof(struct macb_dma_desc),
                                           &macb->rx_ring_dma);
-       macb->tx_ring = dma_alloc_coherent(CFG_MACB_TX_RING_SIZE
+       macb->tx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_TX_RING_SIZE
                                           * sizeof(struct macb_dma_desc),
                                           &macb->tx_ring_dma);
 
        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;
        netdev->recv = macb_recv;
+       netdev->write_hwaddr = macb_write_hwaddr;
 
        /*
         * 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);
 
        eth_register(netdev);
 
-       return 0;
-}
-
+#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
+       miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write);
+       macb->bus = miiphy_get_dev_by_name(netdev->name);
 #endif
-
-#if defined(CONFIG_CMD_MII)
-
-int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value)
-{
-       unsigned long netctl;
-       unsigned long netstat;
-       unsigned long frame;
-       int iflag;
-
-       iflag = disable_interrupts();
-       netctl = macb_readl(&macb, EMACB_NCR);
-       netctl |= MACB_BIT(MPE);
-       macb_writel(&macb, EMACB_NCR, netctl);
-       if (iflag)
-               enable_interrupts();
-
-       frame = (MACB_BF(SOF, 1)
-                | MACB_BF(RW, 2)
-                | MACB_BF(PHYA, addr)
-                | MACB_BF(REGA, reg)
-                | MACB_BF(CODE, 2));
-       macb_writel(&macb, EMACB_MAN, frame);
-
-       do {
-               netstat = macb_readl(&macb, EMACB_NSR);
-       } while (!(netstat & MACB_BIT(IDLE)));
-
-       frame = macb_readl(&macb, EMACB_MAN);
-       *value = MACB_BFEXT(DATA, frame);
-
-       iflag = disable_interrupts();
-       netctl = macb_readl(&macb, EMACB_NCR);
-       netctl &= ~MACB_BIT(MPE);
-       macb_writel(&macb, EMACB_NCR, netctl);
-       if (iflag)
-               enable_interrupts();
-
-       return 0;
-}
-
-int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value)
-{
-       unsigned long netctl;
-       unsigned long netstat;
-       unsigned long frame;
-       int iflag;
-
-       iflag = disable_interrupts();
-       netctl = macb_readl(&macb, EMACB_NCR);
-       netctl |= MACB_BIT(MPE);
-       macb_writel(&macb, EMACB_NCR, netctl);
-       if (iflag)
-               enable_interrupts();
-
-       frame = (MACB_BF(SOF, 1)
-                | MACB_BF(RW, 1)
-                | MACB_BF(PHYA, addr)
-                | MACB_BF(REGA, reg)
-                | MACB_BF(CODE, 2)
-                | MACB_BF(DATA, value));
-       macb_writel(&macb, EMACB_MAN, frame);
-
-       do {
-               netstat = macb_readl(&macb, EMACB_NSR);
-       } while (!(netstat & MACB_BIT(IDLE)));
-
-       iflag = disable_interrupts();
-       netctl = macb_readl(&macb, EMACB_NCR);
-       netctl &= ~MACB_BIT(MPE);
-       macb_writel(&macb, EMACB_NCR, netctl);
-       if (iflag)
-               enable_interrupts();
-
        return 0;
 }