12439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 22439e4bfSJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2005-2006 Atmel Corporation 32439e4bfSJean-Christophe PLAGNIOL-VILLARD * 41a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 52439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 62439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h> 72439e4bfSJean-Christophe PLAGNIOL-VILLARD 82439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 92439e4bfSJean-Christophe PLAGNIOL-VILLARD * The u-boot networking stack is a little weird. It seems like the 102439e4bfSJean-Christophe PLAGNIOL-VILLARD * networking core allocates receive buffers up front without any 112439e4bfSJean-Christophe PLAGNIOL-VILLARD * regard to the hardware that's supposed to actually receive those 122439e4bfSJean-Christophe PLAGNIOL-VILLARD * packets. 132439e4bfSJean-Christophe PLAGNIOL-VILLARD * 142439e4bfSJean-Christophe PLAGNIOL-VILLARD * The MACB receives packets into 128-byte receive buffers, so the 152439e4bfSJean-Christophe PLAGNIOL-VILLARD * buffers allocated by the core isn't very practical to use. We'll 162439e4bfSJean-Christophe PLAGNIOL-VILLARD * allocate our own, but we need one such buffer in case a packet 172439e4bfSJean-Christophe PLAGNIOL-VILLARD * wraps around the DMA ring so that we have to copy it. 182439e4bfSJean-Christophe PLAGNIOL-VILLARD * 196d0f6bcfSJean-Christophe PLAGNIOL-VILLARD * Therefore, define CONFIG_SYS_RX_ETH_BUFFER to 1 in the board-specific 202439e4bfSJean-Christophe PLAGNIOL-VILLARD * configuration header. This way, the core allocates one RX buffer 212439e4bfSJean-Christophe PLAGNIOL-VILLARD * and one TX buffer, each of which can hold a ethernet packet of 222439e4bfSJean-Christophe PLAGNIOL-VILLARD * maximum size. 232439e4bfSJean-Christophe PLAGNIOL-VILLARD * 242439e4bfSJean-Christophe PLAGNIOL-VILLARD * For some reason, the networking core unconditionally specifies a 252439e4bfSJean-Christophe PLAGNIOL-VILLARD * 32-byte packet "alignment" (which really should be called 262439e4bfSJean-Christophe PLAGNIOL-VILLARD * "padding"). MACB shouldn't need that, but we'll refrain from any 272439e4bfSJean-Christophe PLAGNIOL-VILLARD * core modifications here... 282439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 292439e4bfSJean-Christophe PLAGNIOL-VILLARD 302439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h> 3189973f8aSBen Warren #include <netdev.h> 322439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h> 330f751d6eSSemih Hazar #include <miiphy.h> 342439e4bfSJean-Christophe PLAGNIOL-VILLARD 352439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <linux/mii.h> 362439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 372439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/dma-mapping.h> 382439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/clk.h> 398314ccd8SBo Shen #include <asm-generic/errno.h> 402439e4bfSJean-Christophe PLAGNIOL-VILLARD 412439e4bfSJean-Christophe PLAGNIOL-VILLARD #include "macb.h" 422439e4bfSJean-Christophe PLAGNIOL-VILLARD 43ceef983bSAndreas Bießmann #define MACB_RX_BUFFER_SIZE 4096 44ceef983bSAndreas Bießmann #define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128) 45ceef983bSAndreas Bießmann #define MACB_TX_RING_SIZE 16 46ceef983bSAndreas Bießmann #define MACB_TX_TIMEOUT 1000 47ceef983bSAndreas Bießmann #define MACB_AUTONEG_TIMEOUT 5000000 482439e4bfSJean-Christophe PLAGNIOL-VILLARD 492439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc { 502439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 addr; 512439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ctrl; 522439e4bfSJean-Christophe PLAGNIOL-VILLARD }; 532439e4bfSJean-Christophe PLAGNIOL-VILLARD 545ae0e382SWu, Josh #define DMA_DESC_BYTES(n) (n * sizeof(struct macb_dma_desc)) 555ae0e382SWu, Josh #define MACB_TX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_TX_RING_SIZE)) 565ae0e382SWu, Josh #define MACB_RX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_RX_RING_SIZE)) 57ade4ea4dSWu, Josh #define MACB_TX_DUMMY_DMA_DESC_SIZE (DMA_DESC_BYTES(1)) 585ae0e382SWu, Josh 592439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_USED 0x00000001 602439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_WRAP 0x00000002 612439e4bfSJean-Christophe PLAGNIOL-VILLARD 622439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRMLEN_MASK 0x00000fff 632439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_START 0x00004000 642439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_END 0x00008000 652439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_TYPEID_MATCH 0x00400000 662439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR4_MATCH 0x00800000 672439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR3_MATCH 0x01000000 682439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR2_MATCH 0x02000000 692439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR1_MATCH 0x04000000 702439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_BROADCAST 0x80000000 712439e4bfSJean-Christophe PLAGNIOL-VILLARD 722439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRMLEN_MASK 0x000007ff 732439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRAME_END 0x00008000 742439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_NOCRC 0x00010000 752439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_EXHAUSTED 0x08000000 762439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_UNDERRUN 0x10000000 772439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_MAXRETRY 0x20000000 782439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_WRAP 0x40000000 792439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_USED 0x80000000 802439e4bfSJean-Christophe PLAGNIOL-VILLARD 812439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device { 822439e4bfSJean-Christophe PLAGNIOL-VILLARD void *regs; 832439e4bfSJean-Christophe PLAGNIOL-VILLARD 842439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int rx_tail; 852439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_head; 862439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_tail; 87*d5555b70SSimon Glass unsigned int next_rx_tail; 88*d5555b70SSimon Glass bool wrapped; 892439e4bfSJean-Christophe PLAGNIOL-VILLARD 902439e4bfSJean-Christophe PLAGNIOL-VILLARD void *rx_buffer; 912439e4bfSJean-Christophe PLAGNIOL-VILLARD void *tx_buffer; 922439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc *rx_ring; 932439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc *tx_ring; 942439e4bfSJean-Christophe PLAGNIOL-VILLARD 952439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long rx_buffer_dma; 962439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long rx_ring_dma; 972439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long tx_ring_dma; 982439e4bfSJean-Christophe PLAGNIOL-VILLARD 99ade4ea4dSWu, Josh struct macb_dma_desc *dummy_desc; 100ade4ea4dSWu, Josh unsigned long dummy_desc_dma; 101ade4ea4dSWu, Josh 1022439e4bfSJean-Christophe PLAGNIOL-VILLARD const struct device *dev; 1032439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device netdev; 1042439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned short phy_addr; 105b1a0006eSBo Shen struct mii_dev *bus; 1062439e4bfSJean-Christophe PLAGNIOL-VILLARD }; 1072439e4bfSJean-Christophe PLAGNIOL-VILLARD #define to_macb(_nd) container_of(_nd, struct macb_device, netdev) 1082439e4bfSJean-Christophe PLAGNIOL-VILLARD 109d256be29SBo Shen static int macb_is_gem(struct macb_device *macb) 110d256be29SBo Shen { 111d256be29SBo Shen return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2; 112d256be29SBo Shen } 113d256be29SBo Shen 11475b03cf1SGregory CLEMENT #ifndef cpu_is_sama5d2 11575b03cf1SGregory CLEMENT #define cpu_is_sama5d2() 0 11675b03cf1SGregory CLEMENT #endif 11775b03cf1SGregory CLEMENT 11875b03cf1SGregory CLEMENT #ifndef cpu_is_sama5d4 11975b03cf1SGregory CLEMENT #define cpu_is_sama5d4() 0 12075b03cf1SGregory CLEMENT #endif 12175b03cf1SGregory CLEMENT 12275b03cf1SGregory CLEMENT static int gem_is_gigabit_capable(struct macb_device *macb) 12375b03cf1SGregory CLEMENT { 12475b03cf1SGregory CLEMENT /* 1251cc0a9f4SRobert P. J. Day * The GEM controllers embedded in SAMA5D2 and SAMA5D4 are 12675b03cf1SGregory CLEMENT * configured to support only 10/100. 12775b03cf1SGregory CLEMENT */ 12875b03cf1SGregory CLEMENT return macb_is_gem(macb) && !cpu_is_sama5d2() && !cpu_is_sama5d4(); 12975b03cf1SGregory CLEMENT } 13075b03cf1SGregory CLEMENT 1312439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) 1322439e4bfSJean-Christophe PLAGNIOL-VILLARD { 1332439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 1342439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 1352439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 1362439e4bfSJean-Christophe PLAGNIOL-VILLARD 1372439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1382439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 1392439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1402439e4bfSJean-Christophe PLAGNIOL-VILLARD 1412439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 1422439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 1) 1432439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, macb->phy_addr) 1442439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 1452439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2) 1462439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(DATA, value)); 1472439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, MAN, frame); 1482439e4bfSJean-Christophe PLAGNIOL-VILLARD 1492439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 1502439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(macb, NSR); 1512439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 1522439e4bfSJean-Christophe PLAGNIOL-VILLARD 1532439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1542439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 1552439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1562439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1572439e4bfSJean-Christophe PLAGNIOL-VILLARD 1582439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 macb_mdio_read(struct macb_device *macb, u8 reg) 1592439e4bfSJean-Christophe PLAGNIOL-VILLARD { 1602439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 1612439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 1622439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 1632439e4bfSJean-Christophe PLAGNIOL-VILLARD 1642439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1652439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 1662439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1672439e4bfSJean-Christophe PLAGNIOL-VILLARD 1682439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 1692439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 2) 1702439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, macb->phy_addr) 1712439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 1722439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2)); 1732439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, MAN, frame); 1742439e4bfSJean-Christophe PLAGNIOL-VILLARD 1752439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 1762439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(macb, NSR); 1772439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 1782439e4bfSJean-Christophe PLAGNIOL-VILLARD 1792439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = macb_readl(macb, MAN); 1802439e4bfSJean-Christophe PLAGNIOL-VILLARD 1812439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1822439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 1832439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1842439e4bfSJean-Christophe PLAGNIOL-VILLARD 1852439e4bfSJean-Christophe PLAGNIOL-VILLARD return MACB_BFEXT(DATA, frame); 1862439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1872439e4bfSJean-Christophe PLAGNIOL-VILLARD 1881b8c18b9SJoe Hershberger void __weak arch_get_mdio_control(const char *name) 189416ce623SShiraz Hashim { 190416ce623SShiraz Hashim return; 191416ce623SShiraz Hashim } 192416ce623SShiraz Hashim 193b1a0006eSBo Shen #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) 1940f751d6eSSemih Hazar 1955700bb63SMike Frysinger int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) 1960f751d6eSSemih Hazar { 1970f751d6eSSemih Hazar struct eth_device *dev = eth_get_dev_by_name(devname); 1980f751d6eSSemih Hazar struct macb_device *macb = to_macb(dev); 1990f751d6eSSemih Hazar 2000f751d6eSSemih Hazar if (macb->phy_addr != phy_adr) 2010f751d6eSSemih Hazar return -1; 2020f751d6eSSemih Hazar 203416ce623SShiraz Hashim arch_get_mdio_control(devname); 2040f751d6eSSemih Hazar *value = macb_mdio_read(macb, reg); 2050f751d6eSSemih Hazar 2060f751d6eSSemih Hazar return 0; 2070f751d6eSSemih Hazar } 2080f751d6eSSemih Hazar 2095700bb63SMike Frysinger int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) 2100f751d6eSSemih Hazar { 2110f751d6eSSemih Hazar struct eth_device *dev = eth_get_dev_by_name(devname); 2120f751d6eSSemih Hazar struct macb_device *macb = to_macb(dev); 2130f751d6eSSemih Hazar 2140f751d6eSSemih Hazar if (macb->phy_addr != phy_adr) 2150f751d6eSSemih Hazar return -1; 2160f751d6eSSemih Hazar 217416ce623SShiraz Hashim arch_get_mdio_control(devname); 2180f751d6eSSemih Hazar macb_mdio_write(macb, reg, value); 2190f751d6eSSemih Hazar 2200f751d6eSSemih Hazar return 0; 2210f751d6eSSemih Hazar } 2220f751d6eSSemih Hazar #endif 2230f751d6eSSemih Hazar 2245ae0e382SWu, Josh #define RX 1 2255ae0e382SWu, Josh #define TX 0 2265ae0e382SWu, Josh static inline void macb_invalidate_ring_desc(struct macb_device *macb, bool rx) 2275ae0e382SWu, Josh { 2285ae0e382SWu, Josh if (rx) 2295ae0e382SWu, Josh invalidate_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + 2305ae0e382SWu, Josh MACB_RX_DMA_DESC_SIZE); 2315ae0e382SWu, Josh else 2325ae0e382SWu, Josh invalidate_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + 2335ae0e382SWu, Josh MACB_TX_DMA_DESC_SIZE); 2345ae0e382SWu, Josh } 2355ae0e382SWu, Josh 2365ae0e382SWu, Josh static inline void macb_flush_ring_desc(struct macb_device *macb, bool rx) 2375ae0e382SWu, Josh { 2385ae0e382SWu, Josh if (rx) 2395ae0e382SWu, Josh flush_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + 2405ae0e382SWu, Josh MACB_RX_DMA_DESC_SIZE); 2415ae0e382SWu, Josh else 2425ae0e382SWu, Josh flush_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + 2435ae0e382SWu, Josh MACB_TX_DMA_DESC_SIZE); 2445ae0e382SWu, Josh } 2455ae0e382SWu, Josh 2465ae0e382SWu, Josh static inline void macb_flush_rx_buffer(struct macb_device *macb) 2475ae0e382SWu, Josh { 2485ae0e382SWu, Josh flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + 2495ae0e382SWu, Josh MACB_RX_BUFFER_SIZE); 2505ae0e382SWu, Josh } 2515ae0e382SWu, Josh 2525ae0e382SWu, Josh static inline void macb_invalidate_rx_buffer(struct macb_device *macb) 2535ae0e382SWu, Josh { 2545ae0e382SWu, Josh invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + 2555ae0e382SWu, Josh MACB_RX_BUFFER_SIZE); 2565ae0e382SWu, Josh } 2570f751d6eSSemih Hazar 2582439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_NET) 2592439e4bfSJean-Christophe PLAGNIOL-VILLARD 260*d5555b70SSimon Glass static int _macb_send(struct macb_device *macb, const char *name, void *packet, 261*d5555b70SSimon Glass int length) 2622439e4bfSJean-Christophe PLAGNIOL-VILLARD { 2632439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long paddr, ctrl; 2642439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_head = macb->tx_head; 2652439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 2662439e4bfSJean-Christophe PLAGNIOL-VILLARD 2672439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr = dma_map_single(packet, length, DMA_TO_DEVICE); 2682439e4bfSJean-Christophe PLAGNIOL-VILLARD 2692439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl = length & TXBUF_FRMLEN_MASK; 2702439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl |= TXBUF_FRAME_END; 271ceef983bSAndreas Bießmann if (tx_head == (MACB_TX_RING_SIZE - 1)) { 2722439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl |= TXBUF_WRAP; 2732439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_head = 0; 274ceef983bSAndreas Bießmann } else { 2752439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_head++; 276ceef983bSAndreas Bießmann } 2772439e4bfSJean-Christophe PLAGNIOL-VILLARD 2782439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[tx_head].ctrl = ctrl; 2792439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[tx_head].addr = paddr; 2802439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 2815ae0e382SWu, Josh macb_flush_ring_desc(macb, TX); 2825ae0e382SWu, Josh /* Do we need check paddr and length is dcache line aligned? */ 2835ae0e382SWu, Josh flush_dcache_range(paddr, paddr + length); 2842439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); 2852439e4bfSJean-Christophe PLAGNIOL-VILLARD 2862439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 2872439e4bfSJean-Christophe PLAGNIOL-VILLARD * I guess this is necessary because the networking core may 2882439e4bfSJean-Christophe PLAGNIOL-VILLARD * re-use the transmit buffer as soon as we return... 2892439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 290ceef983bSAndreas Bießmann for (i = 0; i <= MACB_TX_TIMEOUT; i++) { 2912439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 2925ae0e382SWu, Josh macb_invalidate_ring_desc(macb, TX); 2932439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl = macb->tx_ring[tx_head].ctrl; 2942439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_USED) 2952439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 2962439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(1); 2972439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2982439e4bfSJean-Christophe PLAGNIOL-VILLARD 2992439e4bfSJean-Christophe PLAGNIOL-VILLARD dma_unmap_single(packet, length, paddr); 3002439e4bfSJean-Christophe PLAGNIOL-VILLARD 301ceef983bSAndreas Bießmann if (i <= MACB_TX_TIMEOUT) { 3022439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_UNDERRUN) 303*d5555b70SSimon Glass printf("%s: TX underrun\n", name); 3042439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_EXHAUSTED) 305*d5555b70SSimon Glass printf("%s: TX buffers exhausted in mid frame\n", name); 3062439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 307*d5555b70SSimon Glass printf("%s: TX timeout\n", name); 3082439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3092439e4bfSJean-Christophe PLAGNIOL-VILLARD 3102439e4bfSJean-Christophe PLAGNIOL-VILLARD /* No one cares anyway */ 3112439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 3122439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3132439e4bfSJean-Christophe PLAGNIOL-VILLARD 3142439e4bfSJean-Christophe PLAGNIOL-VILLARD static void reclaim_rx_buffers(struct macb_device *macb, 3152439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int new_tail) 3162439e4bfSJean-Christophe PLAGNIOL-VILLARD { 3172439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int i; 3182439e4bfSJean-Christophe PLAGNIOL-VILLARD 3192439e4bfSJean-Christophe PLAGNIOL-VILLARD i = macb->rx_tail; 3205ae0e382SWu, Josh 3215ae0e382SWu, Josh macb_invalidate_ring_desc(macb, RX); 3222439e4bfSJean-Christophe PLAGNIOL-VILLARD while (i > new_tail) { 3232439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr &= ~RXADDR_USED; 3242439e4bfSJean-Christophe PLAGNIOL-VILLARD i++; 325ceef983bSAndreas Bießmann if (i > MACB_RX_RING_SIZE) 3262439e4bfSJean-Christophe PLAGNIOL-VILLARD i = 0; 3272439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3282439e4bfSJean-Christophe PLAGNIOL-VILLARD 3292439e4bfSJean-Christophe PLAGNIOL-VILLARD while (i < new_tail) { 3302439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr &= ~RXADDR_USED; 3312439e4bfSJean-Christophe PLAGNIOL-VILLARD i++; 3322439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3332439e4bfSJean-Christophe PLAGNIOL-VILLARD 3342439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 3355ae0e382SWu, Josh macb_flush_ring_desc(macb, RX); 3362439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_tail = new_tail; 3372439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3382439e4bfSJean-Christophe PLAGNIOL-VILLARD 339*d5555b70SSimon Glass static int _macb_recv(struct macb_device *macb, uchar **packetp) 3402439e4bfSJean-Christophe PLAGNIOL-VILLARD { 341*d5555b70SSimon Glass unsigned int next_rx_tail = macb->next_rx_tail; 3422439e4bfSJean-Christophe PLAGNIOL-VILLARD void *buffer; 3432439e4bfSJean-Christophe PLAGNIOL-VILLARD int length; 3442439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 status; 3452439e4bfSJean-Christophe PLAGNIOL-VILLARD 346*d5555b70SSimon Glass macb->wrapped = false; 3472439e4bfSJean-Christophe PLAGNIOL-VILLARD for (;;) { 3485ae0e382SWu, Josh macb_invalidate_ring_desc(macb, RX); 3495ae0e382SWu, Josh 350*d5555b70SSimon Glass if (!(macb->rx_ring[next_rx_tail].addr & RXADDR_USED)) 351*d5555b70SSimon Glass return -EAGAIN; 3522439e4bfSJean-Christophe PLAGNIOL-VILLARD 353*d5555b70SSimon Glass status = macb->rx_ring[next_rx_tail].ctrl; 3542439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & RXBUF_FRAME_START) { 355*d5555b70SSimon Glass if (next_rx_tail != macb->rx_tail) 356*d5555b70SSimon Glass reclaim_rx_buffers(macb, next_rx_tail); 357*d5555b70SSimon Glass macb->wrapped = false; 3582439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3592439e4bfSJean-Christophe PLAGNIOL-VILLARD 3602439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & RXBUF_FRAME_END) { 3612439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer = macb->rx_buffer + 128 * macb->rx_tail; 3622439e4bfSJean-Christophe PLAGNIOL-VILLARD length = status & RXBUF_FRMLEN_MASK; 3635ae0e382SWu, Josh 3645ae0e382SWu, Josh macb_invalidate_rx_buffer(macb); 365*d5555b70SSimon Glass if (macb->wrapped) { 3662439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int headlen, taillen; 3672439e4bfSJean-Christophe PLAGNIOL-VILLARD 368ceef983bSAndreas Bießmann headlen = 128 * (MACB_RX_RING_SIZE 3692439e4bfSJean-Christophe PLAGNIOL-VILLARD - macb->rx_tail); 3702439e4bfSJean-Christophe PLAGNIOL-VILLARD taillen = length - headlen; 3711fd92db8SJoe Hershberger memcpy((void *)net_rx_packets[0], 3722439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer, headlen); 3731fd92db8SJoe Hershberger memcpy((void *)net_rx_packets[0] + headlen, 3742439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_buffer, taillen); 375*d5555b70SSimon Glass *packetp = (void *)net_rx_packets[0]; 376*d5555b70SSimon Glass } else { 377*d5555b70SSimon Glass *packetp = buffer; 3782439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3792439e4bfSJean-Christophe PLAGNIOL-VILLARD 380*d5555b70SSimon Glass if (++next_rx_tail >= MACB_RX_RING_SIZE) 381*d5555b70SSimon Glass next_rx_tail = 0; 382*d5555b70SSimon Glass macb->next_rx_tail = next_rx_tail; 383*d5555b70SSimon Glass return length; 3842439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 385*d5555b70SSimon Glass if (++next_rx_tail >= MACB_RX_RING_SIZE) { 386*d5555b70SSimon Glass macb->wrapped = true; 387*d5555b70SSimon Glass next_rx_tail = 0; 3882439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3892439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3902439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 3912439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3922439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3932439e4bfSJean-Christophe PLAGNIOL-VILLARD 394*d5555b70SSimon Glass static void macb_phy_reset(struct macb_device *macb, const char *name) 3952439e4bfSJean-Christophe PLAGNIOL-VILLARD { 3962439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 3972439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 status, adv; 3982439e4bfSJean-Christophe PLAGNIOL-VILLARD 3992439e4bfSJean-Christophe PLAGNIOL-VILLARD adv = ADVERTISE_CSMA | ADVERTISE_ALL; 4002439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_mdio_write(macb, MII_ADVERTISE, adv); 401*d5555b70SSimon Glass printf("%s: Starting autonegotiation...\n", name); 4022439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE 4032439e4bfSJean-Christophe PLAGNIOL-VILLARD | BMCR_ANRESTART)); 4042439e4bfSJean-Christophe PLAGNIOL-VILLARD 405ceef983bSAndreas Bießmann for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { 4062439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 4072439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_ANEGCOMPLETE) 4082439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 4092439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(100); 4102439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4112439e4bfSJean-Christophe PLAGNIOL-VILLARD 4122439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_ANEGCOMPLETE) 413*d5555b70SSimon Glass printf("%s: Autonegotiation complete\n", name); 4142439e4bfSJean-Christophe PLAGNIOL-VILLARD else 4152439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: Autonegotiation timed out (status=0x%04x)\n", 416*d5555b70SSimon Glass name, status); 4172439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4182439e4bfSJean-Christophe PLAGNIOL-VILLARD 419fc01ea1eSGunnar Rangoy #ifdef CONFIG_MACB_SEARCH_PHY 420fc01ea1eSGunnar Rangoy static int macb_phy_find(struct macb_device *macb) 421fc01ea1eSGunnar Rangoy { 422fc01ea1eSGunnar Rangoy int i; 423fc01ea1eSGunnar Rangoy u16 phy_id; 424fc01ea1eSGunnar Rangoy 425fc01ea1eSGunnar Rangoy /* Search for PHY... */ 426fc01ea1eSGunnar Rangoy for (i = 0; i < 32; i++) { 427fc01ea1eSGunnar Rangoy macb->phy_addr = i; 428fc01ea1eSGunnar Rangoy phy_id = macb_mdio_read(macb, MII_PHYSID1); 429fc01ea1eSGunnar Rangoy if (phy_id != 0xffff) { 430fc01ea1eSGunnar Rangoy printf("%s: PHY present at %d\n", macb->netdev.name, i); 431fc01ea1eSGunnar Rangoy return 1; 432fc01ea1eSGunnar Rangoy } 433fc01ea1eSGunnar Rangoy } 434fc01ea1eSGunnar Rangoy 435fc01ea1eSGunnar Rangoy /* PHY isn't up to snuff */ 4366ed0e940SAndreas Bießmann printf("%s: PHY not found\n", macb->netdev.name); 437fc01ea1eSGunnar Rangoy 438fc01ea1eSGunnar Rangoy return 0; 439fc01ea1eSGunnar Rangoy } 440fc01ea1eSGunnar Rangoy #endif /* CONFIG_MACB_SEARCH_PHY */ 441fc01ea1eSGunnar Rangoy 442fc01ea1eSGunnar Rangoy 443*d5555b70SSimon Glass static int macb_phy_init(struct macb_device *macb, const char *name) 4442439e4bfSJean-Christophe PLAGNIOL-VILLARD { 445b1a0006eSBo Shen #ifdef CONFIG_PHYLIB 446b1a0006eSBo Shen struct phy_device *phydev; 447b1a0006eSBo Shen #endif 4482439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncfgr; 4492439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 phy_id, status, adv, lpa; 4502439e4bfSJean-Christophe PLAGNIOL-VILLARD int media, speed, duplex; 4512439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 4522439e4bfSJean-Christophe PLAGNIOL-VILLARD 453*d5555b70SSimon Glass arch_get_mdio_control(name); 454fc01ea1eSGunnar Rangoy #ifdef CONFIG_MACB_SEARCH_PHY 455fc01ea1eSGunnar Rangoy /* Auto-detect phy_addr */ 456ceef983bSAndreas Bießmann if (!macb_phy_find(macb)) 457fc01ea1eSGunnar Rangoy return 0; 458fc01ea1eSGunnar Rangoy #endif /* CONFIG_MACB_SEARCH_PHY */ 459fc01ea1eSGunnar Rangoy 4602439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Check if the PHY is up to snuff... */ 4612439e4bfSJean-Christophe PLAGNIOL-VILLARD phy_id = macb_mdio_read(macb, MII_PHYSID1); 4622439e4bfSJean-Christophe PLAGNIOL-VILLARD if (phy_id == 0xffff) { 463*d5555b70SSimon Glass printf("%s: No PHY present\n", name); 4642439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 4652439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4662439e4bfSJean-Christophe PLAGNIOL-VILLARD 467b1a0006eSBo Shen #ifdef CONFIG_PHYLIB 4688314ccd8SBo Shen /* need to consider other phy interface mode */ 469*d5555b70SSimon Glass phydev = phy_connect(macb->bus, macb->phy_addr, &macb->netdev, 4708314ccd8SBo Shen PHY_INTERFACE_MODE_RGMII); 4718314ccd8SBo Shen if (!phydev) { 4728314ccd8SBo Shen printf("phy_connect failed\n"); 4738314ccd8SBo Shen return -ENODEV; 4748314ccd8SBo Shen } 4758314ccd8SBo Shen 476b1a0006eSBo Shen phy_config(phydev); 477b1a0006eSBo Shen #endif 478b1a0006eSBo Shen 4792439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 4802439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(status & BMSR_LSTATUS)) { 4812439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Try to re-negotiate if we don't have link already. */ 482*d5555b70SSimon Glass macb_phy_reset(macb, name); 4832439e4bfSJean-Christophe PLAGNIOL-VILLARD 484ceef983bSAndreas Bießmann for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { 4852439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 4862439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_LSTATUS) 4872439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 4882439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(100); 4892439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4902439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4912439e4bfSJean-Christophe PLAGNIOL-VILLARD 4922439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(status & BMSR_LSTATUS)) { 4932439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: link down (status: 0x%04x)\n", 494*d5555b70SSimon Glass name, status); 4952439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 496d256be29SBo Shen } 497d256be29SBo Shen 49875b03cf1SGregory CLEMENT /* First check for GMAC and that it is GiB capable */ 49975b03cf1SGregory CLEMENT if (gem_is_gigabit_capable(macb)) { 500d256be29SBo Shen lpa = macb_mdio_read(macb, MII_STAT1000); 501d256be29SBo Shen 50247609577SAndreas Bießmann if (lpa & (LPA_1000FULL | LPA_1000HALF)) { 50347609577SAndreas Bießmann duplex = ((lpa & LPA_1000FULL) ? 1 : 0); 50447609577SAndreas Bießmann 50547609577SAndreas Bießmann printf("%s: link up, 1000Mbps %s-duplex (lpa: 0x%04x)\n", 506*d5555b70SSimon Glass name, 507d256be29SBo Shen duplex ? "full" : "half", 508d256be29SBo Shen lpa); 509d256be29SBo Shen 510d256be29SBo Shen ncfgr = macb_readl(macb, NCFGR); 51147609577SAndreas Bießmann ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); 512d256be29SBo Shen ncfgr |= GEM_BIT(GBE); 51347609577SAndreas Bießmann 514d256be29SBo Shen if (duplex) 515d256be29SBo Shen ncfgr |= MACB_BIT(FD); 51647609577SAndreas Bießmann 517d256be29SBo Shen macb_writel(macb, NCFGR, ncfgr); 518d256be29SBo Shen 519d256be29SBo Shen return 1; 520d256be29SBo Shen } 521d256be29SBo Shen } 522d256be29SBo Shen 523d256be29SBo Shen /* fall back for EMAC checking */ 5242439e4bfSJean-Christophe PLAGNIOL-VILLARD adv = macb_mdio_read(macb, MII_ADVERTISE); 5252439e4bfSJean-Christophe PLAGNIOL-VILLARD lpa = macb_mdio_read(macb, MII_LPA); 5262439e4bfSJean-Christophe PLAGNIOL-VILLARD media = mii_nway_result(lpa & adv); 5272439e4bfSJean-Christophe PLAGNIOL-VILLARD speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) 5282439e4bfSJean-Christophe PLAGNIOL-VILLARD ? 1 : 0); 5292439e4bfSJean-Christophe PLAGNIOL-VILLARD duplex = (media & ADVERTISE_FULL) ? 1 : 0; 5302439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", 531*d5555b70SSimon Glass name, 5322439e4bfSJean-Christophe PLAGNIOL-VILLARD speed ? "100" : "10", 5332439e4bfSJean-Christophe PLAGNIOL-VILLARD duplex ? "full" : "half", 5342439e4bfSJean-Christophe PLAGNIOL-VILLARD lpa); 5352439e4bfSJean-Christophe PLAGNIOL-VILLARD 5362439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = macb_readl(macb, NCFGR); 537c83cb5f6SBo Shen ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); 5382439e4bfSJean-Christophe PLAGNIOL-VILLARD if (speed) 5392439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr |= MACB_BIT(SPD); 5402439e4bfSJean-Christophe PLAGNIOL-VILLARD if (duplex) 5412439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr |= MACB_BIT(FD); 5422439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCFGR, ncfgr); 543d256be29SBo Shen 5442439e4bfSJean-Christophe PLAGNIOL-VILLARD return 1; 5452439e4bfSJean-Christophe PLAGNIOL-VILLARD } 5462439e4bfSJean-Christophe PLAGNIOL-VILLARD 547ade4ea4dSWu, Josh static int gmac_init_multi_queues(struct macb_device *macb) 548ade4ea4dSWu, Josh { 549ade4ea4dSWu, Josh int i, num_queues = 1; 550ade4ea4dSWu, Josh u32 queue_mask; 551ade4ea4dSWu, Josh 552ade4ea4dSWu, Josh /* bit 0 is never set but queue 0 always exists */ 553ade4ea4dSWu, Josh queue_mask = gem_readl(macb, DCFG6) & 0xff; 554ade4ea4dSWu, Josh queue_mask |= 0x1; 555ade4ea4dSWu, Josh 556ade4ea4dSWu, Josh for (i = 1; i < MACB_MAX_QUEUES; i++) 557ade4ea4dSWu, Josh if (queue_mask & (1 << i)) 558ade4ea4dSWu, Josh num_queues++; 559ade4ea4dSWu, Josh 560ade4ea4dSWu, Josh macb->dummy_desc->ctrl = TXBUF_USED; 561ade4ea4dSWu, Josh macb->dummy_desc->addr = 0; 562ade4ea4dSWu, Josh flush_dcache_range(macb->dummy_desc_dma, macb->dummy_desc_dma + 563ade4ea4dSWu, Josh MACB_TX_DUMMY_DMA_DESC_SIZE); 564ade4ea4dSWu, Josh 565ade4ea4dSWu, Josh for (i = 1; i < num_queues; i++) 566ade4ea4dSWu, Josh gem_writel_queue_TBQP(macb, macb->dummy_desc_dma, i - 1); 567ade4ea4dSWu, Josh 568ade4ea4dSWu, Josh return 0; 569ade4ea4dSWu, Josh } 570ade4ea4dSWu, Josh 571*d5555b70SSimon Glass static int _macb_init(struct macb_device *macb, const char *name) 5722439e4bfSJean-Christophe PLAGNIOL-VILLARD { 5732439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long paddr; 5742439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 5752439e4bfSJean-Christophe PLAGNIOL-VILLARD 5762439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 5772439e4bfSJean-Christophe PLAGNIOL-VILLARD * macb_halt should have been called at some point before now, 5782439e4bfSJean-Christophe PLAGNIOL-VILLARD * so we'll assume the controller is idle. 5792439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 5802439e4bfSJean-Christophe PLAGNIOL-VILLARD 5812439e4bfSJean-Christophe PLAGNIOL-VILLARD /* initialize DMA descriptors */ 5822439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr = macb->rx_buffer_dma; 583ceef983bSAndreas Bießmann for (i = 0; i < MACB_RX_RING_SIZE; i++) { 584ceef983bSAndreas Bießmann if (i == (MACB_RX_RING_SIZE - 1)) 5852439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr |= RXADDR_WRAP; 5862439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr = paddr; 5872439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].ctrl = 0; 5882439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr += 128; 5892439e4bfSJean-Christophe PLAGNIOL-VILLARD } 5905ae0e382SWu, Josh macb_flush_ring_desc(macb, RX); 5915ae0e382SWu, Josh macb_flush_rx_buffer(macb); 5925ae0e382SWu, Josh 593ceef983bSAndreas Bießmann for (i = 0; i < MACB_TX_RING_SIZE; i++) { 5942439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].addr = 0; 595ceef983bSAndreas Bießmann if (i == (MACB_TX_RING_SIZE - 1)) 5962439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP; 5972439e4bfSJean-Christophe PLAGNIOL-VILLARD else 5982439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].ctrl = TXBUF_USED; 5992439e4bfSJean-Christophe PLAGNIOL-VILLARD } 6005ae0e382SWu, Josh macb_flush_ring_desc(macb, TX); 6015ae0e382SWu, Josh 602ceef983bSAndreas Bießmann macb->rx_tail = 0; 603ceef983bSAndreas Bießmann macb->tx_head = 0; 604ceef983bSAndreas Bießmann macb->tx_tail = 0; 605*d5555b70SSimon Glass macb->next_rx_tail = 0; 6062439e4bfSJean-Christophe PLAGNIOL-VILLARD 6072439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, RBQP, macb->rx_ring_dma); 6082439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, TBQP, macb->tx_ring_dma); 6092439e4bfSJean-Christophe PLAGNIOL-VILLARD 610d256be29SBo Shen if (macb_is_gem(macb)) { 611ade4ea4dSWu, Josh /* Check the multi queue and initialize the queue for tx */ 612ade4ea4dSWu, Josh gmac_init_multi_queues(macb); 613ade4ea4dSWu, Josh 614cabf61ceSBo Shen /* 615cabf61ceSBo Shen * When the GMAC IP with GE feature, this bit is used to 616cabf61ceSBo Shen * select interface between RGMII and GMII. 617cabf61ceSBo Shen * When the GMAC IP without GE feature, this bit is used 618cabf61ceSBo Shen * to select interface between RMII and MII. 619cabf61ceSBo Shen */ 620cabf61ceSBo Shen #if defined(CONFIG_RGMII) || defined(CONFIG_RMII) 621d256be29SBo Shen gem_writel(macb, UR, GEM_BIT(RGMII)); 622d256be29SBo Shen #else 623d256be29SBo Shen gem_writel(macb, UR, 0); 624d256be29SBo Shen #endif 625d256be29SBo Shen } else { 6262439e4bfSJean-Christophe PLAGNIOL-VILLARD /* choose RMII or MII mode. This depends on the board */ 6272439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_RMII 628d8f64b44SBo Shen #ifdef CONFIG_AT91FAMILY 6297263ef19SStelian Pop macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN)); 6307263ef19SStelian Pop #else 6312439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, USRIO, 0); 6327263ef19SStelian Pop #endif 6337263ef19SStelian Pop #else 634d8f64b44SBo Shen #ifdef CONFIG_AT91FAMILY 6357263ef19SStelian Pop macb_writel(macb, USRIO, MACB_BIT(CLKEN)); 6362439e4bfSJean-Christophe PLAGNIOL-VILLARD #else 6372439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, USRIO, MACB_BIT(MII)); 6382439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 6397263ef19SStelian Pop #endif /* CONFIG_RMII */ 640d256be29SBo Shen } 6412439e4bfSJean-Christophe PLAGNIOL-VILLARD 642*d5555b70SSimon Glass if (!macb_phy_init(macb, name)) 643422b1a01SBen Warren return -1; 6442439e4bfSJean-Christophe PLAGNIOL-VILLARD 6452439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Enable TX and RX */ 6462439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE)); 6472439e4bfSJean-Christophe PLAGNIOL-VILLARD 648422b1a01SBen Warren return 0; 6492439e4bfSJean-Christophe PLAGNIOL-VILLARD } 6502439e4bfSJean-Christophe PLAGNIOL-VILLARD 651*d5555b70SSimon Glass static void _macb_halt(struct macb_device *macb) 6522439e4bfSJean-Christophe PLAGNIOL-VILLARD { 6532439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncr, tsr; 6542439e4bfSJean-Christophe PLAGNIOL-VILLARD 6552439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Halt the controller and wait for any ongoing transmission to end. */ 6562439e4bfSJean-Christophe PLAGNIOL-VILLARD ncr = macb_readl(macb, NCR); 6572439e4bfSJean-Christophe PLAGNIOL-VILLARD ncr |= MACB_BIT(THALT); 6582439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, ncr); 6592439e4bfSJean-Christophe PLAGNIOL-VILLARD 6602439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 6612439e4bfSJean-Christophe PLAGNIOL-VILLARD tsr = macb_readl(macb, TSR); 6622439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (tsr & MACB_BIT(TGO)); 6632439e4bfSJean-Christophe PLAGNIOL-VILLARD 6642439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Disable TX and RX, and clear statistics */ 6652439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(CLRSTAT)); 6662439e4bfSJean-Christophe PLAGNIOL-VILLARD } 6672439e4bfSJean-Christophe PLAGNIOL-VILLARD 668*d5555b70SSimon Glass static int _macb_write_hwaddr(struct macb_device *macb, unsigned char *enetaddr) 6696bb46790SBen Warren { 6706bb46790SBen Warren u32 hwaddr_bottom; 6716bb46790SBen Warren u16 hwaddr_top; 6726bb46790SBen Warren 6736bb46790SBen Warren /* set hardware address */ 674*d5555b70SSimon Glass hwaddr_bottom = enetaddr[0] | enetaddr[1] << 8 | 675*d5555b70SSimon Glass enetaddr[2] << 16 | enetaddr[3] << 24; 6766bb46790SBen Warren macb_writel(macb, SA1B, hwaddr_bottom); 677*d5555b70SSimon Glass hwaddr_top = enetaddr[4] | enetaddr[5] << 8; 6786bb46790SBen Warren macb_writel(macb, SA1T, hwaddr_top); 6796bb46790SBen Warren return 0; 6806bb46790SBen Warren } 6816bb46790SBen Warren 682d256be29SBo Shen static u32 macb_mdc_clk_div(int id, struct macb_device *macb) 683d256be29SBo Shen { 684d256be29SBo Shen u32 config; 685d256be29SBo Shen unsigned long macb_hz = get_macb_pclk_rate(id); 686d256be29SBo Shen 687d256be29SBo Shen if (macb_hz < 20000000) 688d256be29SBo Shen config = MACB_BF(CLK, MACB_CLK_DIV8); 689d256be29SBo Shen else if (macb_hz < 40000000) 690d256be29SBo Shen config = MACB_BF(CLK, MACB_CLK_DIV16); 691d256be29SBo Shen else if (macb_hz < 80000000) 692d256be29SBo Shen config = MACB_BF(CLK, MACB_CLK_DIV32); 693d256be29SBo Shen else 694d256be29SBo Shen config = MACB_BF(CLK, MACB_CLK_DIV64); 695d256be29SBo Shen 696d256be29SBo Shen return config; 697d256be29SBo Shen } 698d256be29SBo Shen 699d256be29SBo Shen static u32 gem_mdc_clk_div(int id, struct macb_device *macb) 700d256be29SBo Shen { 701d256be29SBo Shen u32 config; 702d256be29SBo Shen unsigned long macb_hz = get_macb_pclk_rate(id); 703d256be29SBo Shen 704d256be29SBo Shen if (macb_hz < 20000000) 705d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV8); 706d256be29SBo Shen else if (macb_hz < 40000000) 707d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV16); 708d256be29SBo Shen else if (macb_hz < 80000000) 709d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV32); 710d256be29SBo Shen else if (macb_hz < 120000000) 711d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV48); 712d256be29SBo Shen else if (macb_hz < 160000000) 713d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV64); 714d256be29SBo Shen else 715d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV96); 716d256be29SBo Shen 717d256be29SBo Shen return config; 718d256be29SBo Shen } 719d256be29SBo Shen 72032e4f6bfSBo Shen /* 72132e4f6bfSBo Shen * Get the DMA bus width field of the network configuration register that we 72232e4f6bfSBo Shen * should program. We find the width from decoding the design configuration 72332e4f6bfSBo Shen * register to find the maximum supported data bus width. 72432e4f6bfSBo Shen */ 72532e4f6bfSBo Shen static u32 macb_dbw(struct macb_device *macb) 72632e4f6bfSBo Shen { 72732e4f6bfSBo Shen switch (GEM_BFEXT(DBWDEF, gem_readl(macb, DCFG1))) { 72832e4f6bfSBo Shen case 4: 72932e4f6bfSBo Shen return GEM_BF(DBW, GEM_DBW128); 73032e4f6bfSBo Shen case 2: 73132e4f6bfSBo Shen return GEM_BF(DBW, GEM_DBW64); 73232e4f6bfSBo Shen case 1: 73332e4f6bfSBo Shen default: 73432e4f6bfSBo Shen return GEM_BF(DBW, GEM_DBW32); 73532e4f6bfSBo Shen } 73632e4f6bfSBo Shen } 73732e4f6bfSBo Shen 738*d5555b70SSimon Glass static void _macb_eth_initialize(struct macb_device *macb) 7392439e4bfSJean-Christophe PLAGNIOL-VILLARD { 740*d5555b70SSimon Glass int id = 0; /* This is not used by functions we call */ 7412439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncfgr; 7422439e4bfSJean-Christophe PLAGNIOL-VILLARD 743*d5555b70SSimon Glass /* TODO: we need check the rx/tx_ring_dma is dcache line aligned */ 744ceef983bSAndreas Bießmann macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE, 7452439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->rx_buffer_dma); 7465ae0e382SWu, Josh macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE, 7472439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->rx_ring_dma); 7485ae0e382SWu, Josh macb->tx_ring = dma_alloc_coherent(MACB_TX_DMA_DESC_SIZE, 7492439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->tx_ring_dma); 750ade4ea4dSWu, Josh macb->dummy_desc = dma_alloc_coherent(MACB_TX_DUMMY_DMA_DESC_SIZE, 751ade4ea4dSWu, Josh &macb->dummy_desc_dma); 7522439e4bfSJean-Christophe PLAGNIOL-VILLARD 753*d5555b70SSimon Glass /* 754*d5555b70SSimon Glass * Do some basic initialization so that we at least can talk 755*d5555b70SSimon Glass * to the PHY 756*d5555b70SSimon Glass */ 757*d5555b70SSimon Glass if (macb_is_gem(macb)) { 758*d5555b70SSimon Glass ncfgr = gem_mdc_clk_div(id, macb); 759*d5555b70SSimon Glass ncfgr |= macb_dbw(macb); 760*d5555b70SSimon Glass } else { 761*d5555b70SSimon Glass ncfgr = macb_mdc_clk_div(id, macb); 762*d5555b70SSimon Glass } 763*d5555b70SSimon Glass 764*d5555b70SSimon Glass macb_writel(macb, NCFGR, ncfgr); 765*d5555b70SSimon Glass } 766*d5555b70SSimon Glass 767*d5555b70SSimon Glass static int macb_send(struct eth_device *netdev, void *packet, int length) 768*d5555b70SSimon Glass { 769*d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 770*d5555b70SSimon Glass 771*d5555b70SSimon Glass return _macb_send(macb, netdev->name, packet, length); 772*d5555b70SSimon Glass } 773*d5555b70SSimon Glass 774*d5555b70SSimon Glass static int macb_recv(struct eth_device *netdev) 775*d5555b70SSimon Glass { 776*d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 777*d5555b70SSimon Glass uchar *packet; 778*d5555b70SSimon Glass int length; 779*d5555b70SSimon Glass 780*d5555b70SSimon Glass macb->wrapped = false; 781*d5555b70SSimon Glass for (;;) { 782*d5555b70SSimon Glass macb->next_rx_tail = macb->rx_tail; 783*d5555b70SSimon Glass length = _macb_recv(macb, &packet); 784*d5555b70SSimon Glass if (length >= 0) { 785*d5555b70SSimon Glass net_process_received_packet(packet, length); 786*d5555b70SSimon Glass reclaim_rx_buffers(macb, macb->next_rx_tail); 787*d5555b70SSimon Glass } else if (length < 0) { 788*d5555b70SSimon Glass return length; 789*d5555b70SSimon Glass } 790*d5555b70SSimon Glass } 791*d5555b70SSimon Glass } 792*d5555b70SSimon Glass 793*d5555b70SSimon Glass static int macb_init(struct eth_device *netdev, bd_t *bd) 794*d5555b70SSimon Glass { 795*d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 796*d5555b70SSimon Glass 797*d5555b70SSimon Glass return _macb_init(macb, netdev->name); 798*d5555b70SSimon Glass } 799*d5555b70SSimon Glass 800*d5555b70SSimon Glass static void macb_halt(struct eth_device *netdev) 801*d5555b70SSimon Glass { 802*d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 803*d5555b70SSimon Glass 804*d5555b70SSimon Glass return _macb_halt(macb); 805*d5555b70SSimon Glass } 806*d5555b70SSimon Glass 807*d5555b70SSimon Glass static int macb_write_hwaddr(struct eth_device *netdev) 808*d5555b70SSimon Glass { 809*d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 810*d5555b70SSimon Glass 811*d5555b70SSimon Glass return _macb_write_hwaddr(macb, netdev->enetaddr); 812*d5555b70SSimon Glass } 813*d5555b70SSimon Glass 814*d5555b70SSimon Glass int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) 815*d5555b70SSimon Glass { 816*d5555b70SSimon Glass struct macb_device *macb; 817*d5555b70SSimon Glass struct eth_device *netdev; 818*d5555b70SSimon Glass 819*d5555b70SSimon Glass macb = malloc(sizeof(struct macb_device)); 820*d5555b70SSimon Glass if (!macb) { 821*d5555b70SSimon Glass printf("Error: Failed to allocate memory for MACB%d\n", id); 822*d5555b70SSimon Glass return -1; 823*d5555b70SSimon Glass } 824*d5555b70SSimon Glass memset(macb, 0, sizeof(struct macb_device)); 825*d5555b70SSimon Glass 826*d5555b70SSimon Glass netdev = &macb->netdev; 8275ae0e382SWu, Josh 8282439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->regs = regs; 8292439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->phy_addr = phy_addr; 8302439e4bfSJean-Christophe PLAGNIOL-VILLARD 831d256be29SBo Shen if (macb_is_gem(macb)) 832d256be29SBo Shen sprintf(netdev->name, "gmac%d", id); 833d256be29SBo Shen else 8342439e4bfSJean-Christophe PLAGNIOL-VILLARD sprintf(netdev->name, "macb%d", id); 835d256be29SBo Shen 8362439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->init = macb_init; 8372439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->halt = macb_halt; 8382439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->send = macb_send; 8392439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->recv = macb_recv; 8406bb46790SBen Warren netdev->write_hwaddr = macb_write_hwaddr; 8412439e4bfSJean-Christophe PLAGNIOL-VILLARD 842*d5555b70SSimon Glass _macb_eth_initialize(macb); 8432439e4bfSJean-Christophe PLAGNIOL-VILLARD 8442439e4bfSJean-Christophe PLAGNIOL-VILLARD eth_register(netdev); 8452439e4bfSJean-Christophe PLAGNIOL-VILLARD 846b1a0006eSBo Shen #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) 8470f751d6eSSemih Hazar miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write); 848b1a0006eSBo Shen macb->bus = miiphy_get_dev_by_name(netdev->name); 8490f751d6eSSemih Hazar #endif 8502439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 8512439e4bfSJean-Christophe PLAGNIOL-VILLARD } 8522439e4bfSJean-Christophe PLAGNIOL-VILLARD 8532439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 854