X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=drivers%2Fnet%2Fmacb.c;h=b7802a2fed70828c7f9f38c10013a1f15d5abf25;hp=aa39284d1d92de04d2ecdc643d3c30dd45e5f51b;hb=5a34d9bf31a021987f97f20aefa812b97b58584e;hpb=32d4e38eeb5bcc2f854787bfa68bea2b55eaa1d7 diff --git a/drivers/net/macb.c b/drivers/net/macb.c index aa39284d1d..b7802a2fed 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -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. @@ -40,7 +40,9 @@ */ #include +#include #include +#include #include #include @@ -49,13 +51,11 @@ #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; @@ -103,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; @@ -163,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; @@ -177,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 @@ -192,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) @@ -202,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) @@ -225,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; } @@ -264,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], @@ -275,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; } @@ -302,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; @@ -316,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) { @@ -331,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; @@ -348,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; /* @@ -387,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; @@ -406,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; @@ -456,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)); @@ -472,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; }