X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fnet%2Fmacb.c;h=94c89c762b6ffe47c210946235c567f00f59ed7c;hb=4e7c1a26518fc4332f23c3ee001e10a31555b2b1;hp=a5c188066ca5822627f44e6fbc3473242d99b299;hpb=ade4ea4d71f6dad6683087621eb27bbcdfa6871d;p=u-boot diff --git a/drivers/net/macb.c b/drivers/net/macb.c index a5c188066c..94c89c762b 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -1,9 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2005-2006 Atmel Corporation - * - * SPDX-License-Identifier: GPL-2.0+ */ #include +#include +#include /* * The u-boot networking stack is a little weird. It seems like the @@ -28,7 +29,9 @@ */ #include +#ifndef CONFIG_DM_ETH #include +#endif #include #include @@ -36,16 +39,34 @@ #include #include #include -#include +#include #include "macb.h" +DECLARE_GLOBAL_DATA_PTR; + #define MACB_RX_BUFFER_SIZE 4096 #define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128) #define MACB_TX_RING_SIZE 16 #define MACB_TX_TIMEOUT 1000 #define MACB_AUTONEG_TIMEOUT 5000000 +#ifdef CONFIG_MACB_ZYNQ +/* INCR4 AHB bursts */ +#define MACB_ZYNQ_GEM_DMACR_BLENGTH 0x00000004 +/* Use full configured addressable space (8 Kb) */ +#define MACB_ZYNQ_GEM_DMACR_RXSIZE 0x00000300 +/* Use full configured addressable space (4 Kb) */ +#define MACB_ZYNQ_GEM_DMACR_TXSIZE 0x00000400 +/* Set RXBUF with use of 128 byte */ +#define MACB_ZYNQ_GEM_DMACR_RXBUF 0x00020000 +#define MACB_ZYNQ_GEM_DMACR_INIT \ + (MACB_ZYNQ_GEM_DMACR_BLENGTH | \ + MACB_ZYNQ_GEM_DMACR_RXSIZE | \ + MACB_ZYNQ_GEM_DMACR_TXSIZE | \ + MACB_ZYNQ_GEM_DMACR_RXBUF) +#endif + struct macb_dma_desc { u32 addr; u32 ctrl; @@ -84,6 +105,8 @@ struct macb_device { unsigned int rx_tail; unsigned int tx_head; unsigned int tx_tail; + unsigned int next_rx_tail; + bool wrapped; void *rx_buffer; void *tx_buffer; @@ -98,17 +121,48 @@ struct macb_device { unsigned long dummy_desc_dma; const struct device *dev; +#ifndef CONFIG_DM_ETH struct eth_device netdev; +#endif unsigned short phy_addr; struct mii_dev *bus; +#ifdef CONFIG_PHYLIB + struct phy_device *phydev; +#endif + +#ifdef CONFIG_DM_ETH +#ifdef CONFIG_CLK + unsigned long pclk_rate; +#endif + phy_interface_t phy_interface; +#endif }; +#ifndef CONFIG_DM_ETH #define to_macb(_nd) container_of(_nd, struct macb_device, netdev) +#endif static int macb_is_gem(struct macb_device *macb) { return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2; } +#ifndef cpu_is_sama5d2 +#define cpu_is_sama5d2() 0 +#endif + +#ifndef cpu_is_sama5d4 +#define cpu_is_sama5d4() 0 +#endif + +static int gem_is_gigabit_capable(struct macb_device *macb) +{ + /* + * The GEM controllers embedded in SAMA5D2 and SAMA5D4 are + * configured to support only 10/100. + */ + return macb_is_gem(macb) && !cpu_is_sama5d2() && !cpu_is_sama5d4(); +} + static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) { unsigned long netctl; @@ -173,29 +227,41 @@ void __weak arch_get_mdio_control(const char *name) #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) -int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) +int macb_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg) { - struct eth_device *dev = eth_get_dev_by_name(devname); + u16 value = 0; +#ifdef CONFIG_DM_ETH + struct udevice *dev = eth_get_dev_by_name(bus->name); + struct macb_device *macb = dev_get_priv(dev); +#else + struct eth_device *dev = eth_get_dev_by_name(bus->name); struct macb_device *macb = to_macb(dev); +#endif if (macb->phy_addr != phy_adr) return -1; - arch_get_mdio_control(devname); - *value = macb_mdio_read(macb, reg); + arch_get_mdio_control(bus->name); + value = macb_mdio_read(macb, reg); - return 0; + return value; } -int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) +int macb_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg, + u16 value) { - struct eth_device *dev = eth_get_dev_by_name(devname); +#ifdef CONFIG_DM_ETH + struct udevice *dev = eth_get_dev_by_name(bus->name); + struct macb_device *macb = dev_get_priv(dev); +#else + struct eth_device *dev = eth_get_dev_by_name(bus->name); struct macb_device *macb = to_macb(dev); +#endif if (macb->phy_addr != phy_adr) return -1; - arch_get_mdio_control(devname); + arch_get_mdio_control(bus->name); macb_mdio_write(macb, reg, value); return 0; @@ -207,40 +273,42 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) static inline void macb_invalidate_ring_desc(struct macb_device *macb, bool rx) { if (rx) - invalidate_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + - MACB_RX_DMA_DESC_SIZE); + invalidate_dcache_range(macb->rx_ring_dma, + ALIGN(macb->rx_ring_dma + MACB_RX_DMA_DESC_SIZE, + PKTALIGN)); else - invalidate_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + - MACB_TX_DMA_DESC_SIZE); + invalidate_dcache_range(macb->tx_ring_dma, + ALIGN(macb->tx_ring_dma + MACB_TX_DMA_DESC_SIZE, + PKTALIGN)); } static inline void macb_flush_ring_desc(struct macb_device *macb, bool rx) { if (rx) flush_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + - MACB_RX_DMA_DESC_SIZE); + ALIGN(MACB_RX_DMA_DESC_SIZE, PKTALIGN)); else flush_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + - MACB_TX_DMA_DESC_SIZE); + ALIGN(MACB_TX_DMA_DESC_SIZE, PKTALIGN)); } static inline void macb_flush_rx_buffer(struct macb_device *macb) { flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + - MACB_RX_BUFFER_SIZE); + ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN)); } static inline void macb_invalidate_rx_buffer(struct macb_device *macb) { invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + - MACB_RX_BUFFER_SIZE); + ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN)); } #if defined(CONFIG_CMD_NET) -static int macb_send(struct eth_device *netdev, void *packet, int length) +static int _macb_send(struct macb_device *macb, const char *name, void *packet, + int length) { - struct macb_device *macb = to_macb(netdev); unsigned long paddr, ctrl; unsigned int tx_head = macb->tx_head; int i; @@ -261,7 +329,7 @@ static int macb_send(struct eth_device *netdev, void *packet, int length) barrier(); macb_flush_ring_desc(macb, TX); /* Do we need check paddr and length is dcache line aligned? */ - flush_dcache_range(paddr, paddr + length); + flush_dcache_range(paddr, paddr + ALIGN(length, ARCH_DMA_MINALIGN)); macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); /* @@ -281,12 +349,11 @@ static int macb_send(struct eth_device *netdev, void *packet, int length) if (i <= MACB_TX_TIMEOUT) { if (ctrl & TXBUF_UNDERRUN) - printf("%s: TX underrun\n", netdev->name); + printf("%s: TX underrun\n", name); if (ctrl & TXBUF_EXHAUSTED) - printf("%s: TX buffers exhausted in mid frame\n", - netdev->name); + printf("%s: TX buffers exhausted in mid frame\n", name); } else { - printf("%s: TX timeout\n", netdev->name); + printf("%s: TX timeout\n", name); } /* No one cares anyway */ @@ -318,26 +385,25 @@ static void reclaim_rx_buffers(struct macb_device *macb, macb->rx_tail = new_tail; } -static int macb_recv(struct eth_device *netdev) +static int _macb_recv(struct macb_device *macb, uchar **packetp) { - struct macb_device *macb = to_macb(netdev); - unsigned int rx_tail = macb->rx_tail; + unsigned int next_rx_tail = macb->next_rx_tail; void *buffer; int length; - int wrapped = 0; u32 status; + macb->wrapped = false; for (;;) { macb_invalidate_ring_desc(macb, RX); - if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED)) - return -1; + if (!(macb->rx_ring[next_rx_tail].addr & RXADDR_USED)) + return -EAGAIN; - status = macb->rx_ring[rx_tail].ctrl; + status = macb->rx_ring[next_rx_tail].ctrl; if (status & RXBUF_FRAME_START) { - if (rx_tail != macb->rx_tail) - reclaim_rx_buffers(macb, rx_tail); - wrapped = 0; + if (next_rx_tail != macb->rx_tail) + reclaim_rx_buffers(macb, next_rx_tail); + macb->wrapped = false; } if (status & RXBUF_FRAME_END) { @@ -345,7 +411,7 @@ static int macb_recv(struct eth_device *netdev) length = status & RXBUF_FRMLEN_MASK; macb_invalidate_rx_buffer(macb); - if (wrapped) { + if (macb->wrapped) { unsigned int headlen, taillen; headlen = 128 * (MACB_RX_RING_SIZE @@ -355,34 +421,33 @@ static int macb_recv(struct eth_device *netdev) buffer, headlen); memcpy((void *)net_rx_packets[0] + headlen, macb->rx_buffer, taillen); - buffer = (void *)net_rx_packets[0]; + *packetp = (void *)net_rx_packets[0]; + } else { + *packetp = buffer; } - net_process_received_packet(buffer, length); - if (++rx_tail >= MACB_RX_RING_SIZE) - rx_tail = 0; - reclaim_rx_buffers(macb, rx_tail); + if (++next_rx_tail >= MACB_RX_RING_SIZE) + next_rx_tail = 0; + macb->next_rx_tail = next_rx_tail; + return length; } else { - if (++rx_tail >= MACB_RX_RING_SIZE) { - wrapped = 1; - rx_tail = 0; + if (++next_rx_tail >= MACB_RX_RING_SIZE) { + macb->wrapped = true; + next_rx_tail = 0; } } barrier(); } - - return 0; } -static void macb_phy_reset(struct macb_device *macb) +static void macb_phy_reset(struct macb_device *macb, const char *name) { - struct eth_device *netdev = &macb->netdev; int i; u16 status, adv; adv = ADVERTISE_CSMA | ADVERTISE_ALL; macb_mdio_write(macb, MII_ADVERTISE, adv); - printf("%s: Starting autonegotiation...\n", netdev->name); + printf("%s: Starting autonegotiation...\n", name); macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE | BMCR_ANRESTART)); @@ -394,14 +459,13 @@ static void macb_phy_reset(struct macb_device *macb) } if (status & BMSR_ANEGCOMPLETE) - printf("%s: Autonegotiation complete\n", netdev->name); + printf("%s: Autonegotiation complete\n", name); else printf("%s: Autonegotiation timed out (status=0x%04x)\n", - netdev->name, status); + name, status); } -#ifdef CONFIG_MACB_SEARCH_PHY -static int macb_phy_find(struct macb_device *macb) +static int macb_phy_find(struct macb_device *macb, const char *name) { int i; u16 phy_id; @@ -411,60 +475,78 @@ static int macb_phy_find(struct macb_device *macb) 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; + printf("%s: PHY present at %d\n", name, i); + return 0; } } /* PHY isn't up to snuff */ - printf("%s: PHY not found\n", macb->netdev.name); + printf("%s: PHY not found\n", name); - return 0; + return -ENODEV; } -#endif /* CONFIG_MACB_SEARCH_PHY */ +/** + * macb_linkspd_cb - Linkspeed change callback function + * @regs: Base Register of MACB devices + * @speed: Linkspeed + * Returns 0 when operation success and negative errno number + * when operation failed. + */ +int __weak macb_linkspd_cb(void *regs, unsigned int speed) +{ + return 0; +} -static int macb_phy_init(struct macb_device *macb) +#ifdef CONFIG_DM_ETH +static int macb_phy_init(struct udevice *dev, const char *name) +#else +static int macb_phy_init(struct macb_device *macb, const char *name) +#endif { - struct eth_device *netdev = &macb->netdev; -#ifdef CONFIG_PHYLIB - struct phy_device *phydev; +#ifdef CONFIG_DM_ETH + struct macb_device *macb = dev_get_priv(dev); #endif u32 ncfgr; u16 phy_id, status, adv, lpa; int media, speed, duplex; + int ret; int i; - arch_get_mdio_control(netdev->name); -#ifdef CONFIG_MACB_SEARCH_PHY + arch_get_mdio_control(name); /* Auto-detect phy_addr */ - if (!macb_phy_find(macb)) - return 0; -#endif /* CONFIG_MACB_SEARCH_PHY */ + ret = macb_phy_find(macb, name); + if (ret) + return ret; /* Check if the PHY is up to snuff... */ phy_id = macb_mdio_read(macb, MII_PHYSID1); if (phy_id == 0xffff) { - printf("%s: No PHY present\n", netdev->name); - return 0; + printf("%s: No PHY present\n", name); + return -ENODEV; } #ifdef CONFIG_PHYLIB +#ifdef CONFIG_DM_ETH + macb->phydev = phy_connect(macb->bus, macb->phy_addr, dev, + macb->phy_interface); +#else /* need to consider other phy interface mode */ - phydev = phy_connect(macb->bus, macb->phy_addr, netdev, + macb->phydev = phy_connect(macb->bus, macb->phy_addr, &macb->netdev, PHY_INTERFACE_MODE_RGMII); - if (!phydev) { +#endif + if (!macb->phydev) { printf("phy_connect failed\n"); return -ENODEV; } - phy_config(phydev); + phy_config(macb->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); + macb_phy_reset(macb, name); for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { status = macb_mdio_read(macb, MII_BMSR); @@ -476,19 +558,19 @@ static int macb_phy_init(struct macb_device *macb) if (!(status & BMSR_LSTATUS)) { printf("%s: link down (status: 0x%04x)\n", - netdev->name, status); - return 0; + name, status); + return -ENETDOWN; } - /* First check for GMAC */ - if (macb_is_gem(macb)) { + /* First check for GMAC and that it is GiB capable */ + if (gem_is_gigabit_capable(macb)) { lpa = macb_mdio_read(macb, MII_STAT1000); if (lpa & (LPA_1000FULL | LPA_1000HALF)) { duplex = ((lpa & LPA_1000FULL) ? 1 : 0); printf("%s: link up, 1000Mbps %s-duplex (lpa: 0x%04x)\n", - netdev->name, + name, duplex ? "full" : "half", lpa); @@ -501,7 +583,11 @@ static int macb_phy_init(struct macb_device *macb) macb_writel(macb, NCFGR, ncfgr); - return 1; + ret = macb_linkspd_cb(macb->regs, _1000BASET); + if (ret) + return ret; + + return 0; } } @@ -513,20 +599,28 @@ static int macb_phy_init(struct macb_device *macb) ? 1 : 0); duplex = (media & ADVERTISE_FULL) ? 1 : 0; printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", - netdev->name, + name, speed ? "100" : "10", duplex ? "full" : "half", lpa); ncfgr = macb_readl(macb, NCFGR); ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); - if (speed) + if (speed) { ncfgr |= MACB_BIT(SPD); + ret = macb_linkspd_cb(macb->regs, _100BASET); + } else { + ret = macb_linkspd_cb(macb->regs, _10BASET); + } + + if (ret) + return ret; + if (duplex) ncfgr |= MACB_BIT(FD); macb_writel(macb, NCFGR, ncfgr); - return 1; + return 0; } static int gmac_init_multi_queues(struct macb_device *macb) @@ -545,7 +639,7 @@ static int gmac_init_multi_queues(struct macb_device *macb) macb->dummy_desc->ctrl = TXBUF_USED; macb->dummy_desc->addr = 0; flush_dcache_range(macb->dummy_desc_dma, macb->dummy_desc_dma + - MACB_TX_DUMMY_DMA_DESC_SIZE); + ALIGN(MACB_TX_DUMMY_DMA_DESC_SIZE, PKTALIGN)); for (i = 1; i < num_queues; i++) gem_writel_queue_TBQP(macb, macb->dummy_desc_dma, i - 1); @@ -553,10 +647,17 @@ static int gmac_init_multi_queues(struct macb_device *macb) return 0; } -static int macb_init(struct eth_device *netdev, bd_t *bd) +#ifdef CONFIG_DM_ETH +static int _macb_init(struct udevice *dev, const char *name) +#else +static int _macb_init(struct macb_device *macb, const char *name) +#endif { - struct macb_device *macb = to_macb(netdev); +#ifdef CONFIG_DM_ETH + struct macb_device *macb = dev_get_priv(dev); +#endif unsigned long paddr; + int ret; int i; /* @@ -588,6 +689,11 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) macb->rx_tail = 0; macb->tx_head = 0; macb->tx_tail = 0; + macb->next_rx_tail = 0; + +#ifdef CONFIG_MACB_ZYNQ + macb_writel(macb, DMACFG, MACB_ZYNQ_GEM_DMACR_INIT); +#endif macb_writel(macb, RBQP, macb->rx_ring_dma); macb_writel(macb, TBQP, macb->tx_ring_dma); @@ -602,13 +708,36 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) * When the GMAC IP without GE feature, this bit is used * to select interface between RMII and MII. */ +#ifdef CONFIG_DM_ETH + if ((macb->phy_interface == PHY_INTERFACE_MODE_RMII) || + (macb->phy_interface == PHY_INTERFACE_MODE_RGMII)) + gem_writel(macb, UR, GEM_BIT(RGMII)); + else + gem_writel(macb, UR, 0); +#else #if defined(CONFIG_RGMII) || defined(CONFIG_RMII) gem_writel(macb, UR, GEM_BIT(RGMII)); #else gem_writel(macb, UR, 0); +#endif #endif } else { /* choose RMII or MII mode. This depends on the board */ +#ifdef CONFIG_DM_ETH +#ifdef CONFIG_AT91FAMILY + if (macb->phy_interface == PHY_INTERFACE_MODE_RMII) { + macb_writel(macb, USRIO, + MACB_BIT(RMII) | MACB_BIT(CLKEN)); + } else { + macb_writel(macb, USRIO, MACB_BIT(CLKEN)); + } +#else + if (macb->phy_interface == PHY_INTERFACE_MODE_RMII) + macb_writel(macb, USRIO, 0); + else + macb_writel(macb, USRIO, MACB_BIT(MII)); +#endif +#else #ifdef CONFIG_RMII #ifdef CONFIG_AT91FAMILY macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN)); @@ -622,10 +751,16 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) macb_writel(macb, USRIO, MACB_BIT(MII)); #endif #endif /* CONFIG_RMII */ +#endif } - if (!macb_phy_init(macb)) - return -1; +#ifdef CONFIG_DM_ETH + ret = macb_phy_init(dev, name); +#else + ret = macb_phy_init(macb, name); +#endif + if (ret) + return ret; /* Enable TX and RX */ macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE)); @@ -633,9 +768,8 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) return 0; } -static void macb_halt(struct eth_device *netdev) +static void _macb_halt(struct macb_device *macb) { - struct macb_device *macb = to_macb(netdev); u32 ncr, tsr; /* Halt the controller and wait for any ongoing transmission to end. */ @@ -651,17 +785,16 @@ static void macb_halt(struct eth_device *netdev) macb_writel(macb, NCR, MACB_BIT(CLRSTAT)); } -static int macb_write_hwaddr(struct eth_device *dev) +static int _macb_write_hwaddr(struct macb_device *macb, unsigned char *enetaddr) { - 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; + hwaddr_bottom = enetaddr[0] | enetaddr[1] << 8 | + enetaddr[2] << 16 | enetaddr[3] << 24; macb_writel(macb, SA1B, hwaddr_bottom); - hwaddr_top = dev->enetaddr[4] | dev->enetaddr[5] << 8; + hwaddr_top = enetaddr[4] | enetaddr[5] << 8; macb_writel(macb, SA1T, hwaddr_top); return 0; } @@ -669,7 +802,11 @@ static int macb_write_hwaddr(struct eth_device *dev) static u32 macb_mdc_clk_div(int id, struct macb_device *macb) { u32 config; +#if defined(CONFIG_DM_ETH) && defined(CONFIG_CLK) + unsigned long macb_hz = macb->pclk_rate; +#else unsigned long macb_hz = get_macb_pclk_rate(id); +#endif if (macb_hz < 20000000) config = MACB_BF(CLK, MACB_CLK_DIV8); @@ -686,7 +823,12 @@ static u32 macb_mdc_clk_div(int id, struct macb_device *macb) static u32 gem_mdc_clk_div(int id, struct macb_device *macb) { u32 config; + +#if defined(CONFIG_DM_ETH) && defined(CONFIG_CLK) + unsigned long macb_hz = macb->pclk_rate; +#else unsigned long macb_hz = get_macb_pclk_rate(id); +#endif if (macb_hz < 20000000) config = GEM_BF(CLK, GEM_CLK_DIV8); @@ -722,11 +864,87 @@ static u32 macb_dbw(struct macb_device *macb) } } +static void _macb_eth_initialize(struct macb_device *macb) +{ + int id = 0; /* This is not used by functions we call */ + u32 ncfgr; + + /* TODO: we need check the rx/tx_ring_dma is dcache line aligned */ + macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE, + &macb->rx_buffer_dma); + macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE, + &macb->rx_ring_dma); + macb->tx_ring = dma_alloc_coherent(MACB_TX_DMA_DESC_SIZE, + &macb->tx_ring_dma); + macb->dummy_desc = dma_alloc_coherent(MACB_TX_DUMMY_DMA_DESC_SIZE, + &macb->dummy_desc_dma); + + /* + * Do some basic initialization so that we at least can talk + * to the PHY + */ + if (macb_is_gem(macb)) { + ncfgr = gem_mdc_clk_div(id, macb); + ncfgr |= macb_dbw(macb); + } else { + ncfgr = macb_mdc_clk_div(id, macb); + } + + macb_writel(macb, NCFGR, ncfgr); +} + +#ifndef CONFIG_DM_ETH +static int macb_send(struct eth_device *netdev, void *packet, int length) +{ + struct macb_device *macb = to_macb(netdev); + + return _macb_send(macb, netdev->name, packet, length); +} + +static int macb_recv(struct eth_device *netdev) +{ + struct macb_device *macb = to_macb(netdev); + uchar *packet; + int length; + + macb->wrapped = false; + for (;;) { + macb->next_rx_tail = macb->rx_tail; + length = _macb_recv(macb, &packet); + if (length >= 0) { + net_process_received_packet(packet, length); + reclaim_rx_buffers(macb, macb->next_rx_tail); + } else { + return length; + } + } +} + +static int macb_init(struct eth_device *netdev, bd_t *bd) +{ + struct macb_device *macb = to_macb(netdev); + + return _macb_init(macb, netdev->name); +} + +static void macb_halt(struct eth_device *netdev) +{ + struct macb_device *macb = to_macb(netdev); + + return _macb_halt(macb); +} + +static int macb_write_hwaddr(struct eth_device *netdev) +{ + struct macb_device *macb = to_macb(netdev); + + return _macb_write_hwaddr(macb, netdev->enetaddr); +} + int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) { struct macb_device *macb; struct eth_device *netdev; - u32 ncfgr; macb = malloc(sizeof(struct macb_device)); if (!macb) { @@ -737,17 +955,6 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) netdev = &macb->netdev; - macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE, - &macb->rx_buffer_dma); - macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE, - &macb->rx_ring_dma); - macb->tx_ring = dma_alloc_coherent(MACB_TX_DMA_DESC_SIZE, - &macb->tx_ring_dma); - macb->dummy_desc = dma_alloc_coherent(MACB_TX_DUMMY_DMA_DESC_SIZE, - &macb->dummy_desc_dma); - - /* TODO: we need check the rx/tx_ring_dma is dcache line aligned */ - macb->regs = regs; macb->phy_addr = phy_addr; @@ -762,26 +969,214 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) netdev->recv = macb_recv; netdev->write_hwaddr = macb_write_hwaddr; + _macb_eth_initialize(macb); + + eth_register(netdev); + +#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) + int retval; + struct mii_dev *mdiodev = mdio_alloc(); + if (!mdiodev) + return -ENOMEM; + strncpy(mdiodev->name, netdev->name, MDIO_NAME_LEN); + mdiodev->read = macb_miiphy_read; + mdiodev->write = macb_miiphy_write; + + retval = mdio_register(mdiodev); + if (retval < 0) + return retval; + macb->bus = miiphy_get_dev_by_name(netdev->name); +#endif + return 0; +} +#endif /* !CONFIG_DM_ETH */ + +#ifdef CONFIG_DM_ETH + +static int macb_start(struct udevice *dev) +{ + return _macb_init(dev, dev->name); +} + +static int macb_send(struct udevice *dev, void *packet, int length) +{ + struct macb_device *macb = dev_get_priv(dev); + + return _macb_send(macb, dev->name, packet, length); +} + +static int macb_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct macb_device *macb = dev_get_priv(dev); + + macb->next_rx_tail = macb->rx_tail; + macb->wrapped = false; + + return _macb_recv(macb, packetp); +} + +static int macb_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct macb_device *macb = dev_get_priv(dev); + + reclaim_rx_buffers(macb, macb->next_rx_tail); + + return 0; +} + +static void macb_stop(struct udevice *dev) +{ + struct macb_device *macb = dev_get_priv(dev); + + _macb_halt(macb); +} + +static int macb_write_hwaddr(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + struct macb_device *macb = dev_get_priv(dev); + + return _macb_write_hwaddr(macb, plat->enetaddr); +} + +static const struct eth_ops macb_eth_ops = { + .start = macb_start, + .send = macb_send, + .recv = macb_recv, + .stop = macb_stop, + .free_pkt = macb_free_pkt, + .write_hwaddr = macb_write_hwaddr, +}; + +#ifdef CONFIG_CLK +static int macb_enable_clk(struct udevice *dev) +{ + struct macb_device *macb = dev_get_priv(dev); + struct clk clk; + ulong clk_rate; + int ret; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return -EINVAL; + /* - * Do some basic initialization so that we at least can talk - * to the PHY + * Zynq clock driver didn't support for enable or disable + * clock. Hence, clk_enable() didn't apply for Zynq */ - if (macb_is_gem(macb)) { - ncfgr = gem_mdc_clk_div(id, macb); - ncfgr |= macb_dbw(macb); - } else { - ncfgr = macb_mdc_clk_div(id, macb); +#ifndef CONFIG_MACB_ZYNQ + ret = clk_enable(&clk); + if (ret) + return ret; +#endif + + clk_rate = clk_get_rate(&clk); + if (!clk_rate) + return -EINVAL; + + macb->pclk_rate = clk_rate; + + return 0; +} +#endif + +static int macb_eth_probe(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct macb_device *macb = dev_get_priv(dev); + const char *phy_mode; + __maybe_unused int ret; + + phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", + NULL); + if (phy_mode) + macb->phy_interface = phy_get_interface_by_name(phy_mode); + if (macb->phy_interface == -1) { + debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); + return -EINVAL; } - macb_writel(macb, NCFGR, ncfgr); + macb->regs = (void *)pdata->iobase; - eth_register(netdev); +#ifdef CONFIG_CLK + ret = macb_enable_clk(dev); + if (ret) + return ret; +#endif + + _macb_eth_initialize(macb); #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); + macb->bus = mdio_alloc(); + if (!macb->bus) + return -ENOMEM; + strncpy(macb->bus->name, dev->name, MDIO_NAME_LEN); + macb->bus->read = macb_miiphy_read; + macb->bus->write = macb_miiphy_write; + + ret = mdio_register(macb->bus); + if (ret < 0) + return ret; + macb->bus = miiphy_get_dev_by_name(dev->name); #endif + return 0; } +static int macb_eth_remove(struct udevice *dev) +{ + struct macb_device *macb = dev_get_priv(dev); + +#ifdef CONFIG_PHYLIB + free(macb->phydev); +#endif + mdio_unregister(macb->bus); + mdio_free(macb->bus); + + return 0; +} + +/** + * macb_late_eth_ofdata_to_platdata + * @dev: udevice struct + * Returns 0 when operation success and negative errno number + * when operation failed. + */ +int __weak macb_late_eth_ofdata_to_platdata(struct udevice *dev) +{ + return 0; +} + +static int macb_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + + pdata->iobase = devfdt_get_addr(dev); + + return macb_late_eth_ofdata_to_platdata(dev); +} + +static const struct udevice_id macb_eth_ids[] = { + { .compatible = "cdns,macb" }, + { .compatible = "cdns,at91sam9260-macb" }, + { .compatible = "atmel,sama5d2-gem" }, + { .compatible = "atmel,sama5d3-gem" }, + { .compatible = "atmel,sama5d4-gem" }, + { .compatible = "cdns,zynq-gem" }, + { } +}; + +U_BOOT_DRIVER(eth_macb) = { + .name = "eth_macb", + .id = UCLASS_ETH, + .of_match = macb_eth_ids, + .ofdata_to_platdata = macb_eth_ofdata_to_platdata, + .probe = macb_eth_probe, + .remove = macb_eth_remove, + .ops = &macb_eth_ops, + .priv_auto_alloc_size = sizeof(struct macb_device), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; +#endif + #endif