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> 7577aa3b3SWenyou Yang #include <clk.h> 8f1dcc19bSSimon Glass #include <dm.h> 92439e4bfSJean-Christophe PLAGNIOL-VILLARD 102439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 112439e4bfSJean-Christophe PLAGNIOL-VILLARD * The u-boot networking stack is a little weird. It seems like the 122439e4bfSJean-Christophe PLAGNIOL-VILLARD * networking core allocates receive buffers up front without any 132439e4bfSJean-Christophe PLAGNIOL-VILLARD * regard to the hardware that's supposed to actually receive those 142439e4bfSJean-Christophe PLAGNIOL-VILLARD * packets. 152439e4bfSJean-Christophe PLAGNIOL-VILLARD * 162439e4bfSJean-Christophe PLAGNIOL-VILLARD * The MACB receives packets into 128-byte receive buffers, so the 172439e4bfSJean-Christophe PLAGNIOL-VILLARD * buffers allocated by the core isn't very practical to use. We'll 182439e4bfSJean-Christophe PLAGNIOL-VILLARD * allocate our own, but we need one such buffer in case a packet 192439e4bfSJean-Christophe PLAGNIOL-VILLARD * wraps around the DMA ring so that we have to copy it. 202439e4bfSJean-Christophe PLAGNIOL-VILLARD * 216d0f6bcfSJean-Christophe PLAGNIOL-VILLARD * Therefore, define CONFIG_SYS_RX_ETH_BUFFER to 1 in the board-specific 222439e4bfSJean-Christophe PLAGNIOL-VILLARD * configuration header. This way, the core allocates one RX buffer 232439e4bfSJean-Christophe PLAGNIOL-VILLARD * and one TX buffer, each of which can hold a ethernet packet of 242439e4bfSJean-Christophe PLAGNIOL-VILLARD * maximum size. 252439e4bfSJean-Christophe PLAGNIOL-VILLARD * 262439e4bfSJean-Christophe PLAGNIOL-VILLARD * For some reason, the networking core unconditionally specifies a 272439e4bfSJean-Christophe PLAGNIOL-VILLARD * 32-byte packet "alignment" (which really should be called 282439e4bfSJean-Christophe PLAGNIOL-VILLARD * "padding"). MACB shouldn't need that, but we'll refrain from any 292439e4bfSJean-Christophe PLAGNIOL-VILLARD * core modifications here... 302439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 312439e4bfSJean-Christophe PLAGNIOL-VILLARD 322439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h> 33f1dcc19bSSimon Glass #ifndef CONFIG_DM_ETH 3489973f8aSBen Warren #include <netdev.h> 35f1dcc19bSSimon Glass #endif 362439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h> 370f751d6eSSemih Hazar #include <miiphy.h> 382439e4bfSJean-Christophe PLAGNIOL-VILLARD 392439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <linux/mii.h> 402439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 412439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/dma-mapping.h> 422439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/clk.h> 435d97dff0SMasahiro Yamada #include <linux/errno.h> 442439e4bfSJean-Christophe PLAGNIOL-VILLARD 452439e4bfSJean-Christophe PLAGNIOL-VILLARD #include "macb.h" 462439e4bfSJean-Christophe PLAGNIOL-VILLARD 47a212b66dSWenyou Yang DECLARE_GLOBAL_DATA_PTR; 48a212b66dSWenyou Yang 49ceef983bSAndreas Bießmann #define MACB_RX_BUFFER_SIZE 4096 50ceef983bSAndreas Bießmann #define MACB_RX_RING_SIZE (MACB_RX_BUFFER_SIZE / 128) 51ceef983bSAndreas Bießmann #define MACB_TX_RING_SIZE 16 52ceef983bSAndreas Bießmann #define MACB_TX_TIMEOUT 1000 53ceef983bSAndreas Bießmann #define MACB_AUTONEG_TIMEOUT 5000000 542439e4bfSJean-Christophe PLAGNIOL-VILLARD 552439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc { 562439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 addr; 572439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ctrl; 582439e4bfSJean-Christophe PLAGNIOL-VILLARD }; 592439e4bfSJean-Christophe PLAGNIOL-VILLARD 605ae0e382SWu, Josh #define DMA_DESC_BYTES(n) (n * sizeof(struct macb_dma_desc)) 615ae0e382SWu, Josh #define MACB_TX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_TX_RING_SIZE)) 625ae0e382SWu, Josh #define MACB_RX_DMA_DESC_SIZE (DMA_DESC_BYTES(MACB_RX_RING_SIZE)) 63ade4ea4dSWu, Josh #define MACB_TX_DUMMY_DMA_DESC_SIZE (DMA_DESC_BYTES(1)) 645ae0e382SWu, Josh 652439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_USED 0x00000001 662439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_WRAP 0x00000002 672439e4bfSJean-Christophe PLAGNIOL-VILLARD 682439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRMLEN_MASK 0x00000fff 692439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_START 0x00004000 702439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_END 0x00008000 712439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_TYPEID_MATCH 0x00400000 722439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR4_MATCH 0x00800000 732439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR3_MATCH 0x01000000 742439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR2_MATCH 0x02000000 752439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR1_MATCH 0x04000000 762439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_BROADCAST 0x80000000 772439e4bfSJean-Christophe PLAGNIOL-VILLARD 782439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRMLEN_MASK 0x000007ff 792439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRAME_END 0x00008000 802439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_NOCRC 0x00010000 812439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_EXHAUSTED 0x08000000 822439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_UNDERRUN 0x10000000 832439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_MAXRETRY 0x20000000 842439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_WRAP 0x40000000 852439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_USED 0x80000000 862439e4bfSJean-Christophe PLAGNIOL-VILLARD 872439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device { 882439e4bfSJean-Christophe PLAGNIOL-VILLARD void *regs; 892439e4bfSJean-Christophe PLAGNIOL-VILLARD 902439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int rx_tail; 912439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_head; 922439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_tail; 93d5555b70SSimon Glass unsigned int next_rx_tail; 94d5555b70SSimon Glass bool wrapped; 952439e4bfSJean-Christophe PLAGNIOL-VILLARD 962439e4bfSJean-Christophe PLAGNIOL-VILLARD void *rx_buffer; 972439e4bfSJean-Christophe PLAGNIOL-VILLARD void *tx_buffer; 982439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc *rx_ring; 992439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc *tx_ring; 1002439e4bfSJean-Christophe PLAGNIOL-VILLARD 1012439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long rx_buffer_dma; 1022439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long rx_ring_dma; 1032439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long tx_ring_dma; 1042439e4bfSJean-Christophe PLAGNIOL-VILLARD 105ade4ea4dSWu, Josh struct macb_dma_desc *dummy_desc; 106ade4ea4dSWu, Josh unsigned long dummy_desc_dma; 107ade4ea4dSWu, Josh 1082439e4bfSJean-Christophe PLAGNIOL-VILLARD const struct device *dev; 109f1dcc19bSSimon Glass #ifndef CONFIG_DM_ETH 1102439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device netdev; 111f1dcc19bSSimon Glass #endif 1122439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned short phy_addr; 113b1a0006eSBo Shen struct mii_dev *bus; 1141870d4d7SWenyou Yang #ifdef CONFIG_PHYLIB 1151870d4d7SWenyou Yang struct phy_device *phydev; 1161870d4d7SWenyou Yang #endif 117a212b66dSWenyou Yang 118a212b66dSWenyou Yang #ifdef CONFIG_DM_ETH 1193fd2b3aaSWenyou Yang #ifdef CONFIG_CLK 120577aa3b3SWenyou Yang unsigned long pclk_rate; 1213fd2b3aaSWenyou Yang #endif 122a212b66dSWenyou Yang phy_interface_t phy_interface; 123a212b66dSWenyou Yang #endif 1242439e4bfSJean-Christophe PLAGNIOL-VILLARD }; 125f1dcc19bSSimon Glass #ifndef CONFIG_DM_ETH 1262439e4bfSJean-Christophe PLAGNIOL-VILLARD #define to_macb(_nd) container_of(_nd, struct macb_device, netdev) 127f1dcc19bSSimon Glass #endif 1282439e4bfSJean-Christophe PLAGNIOL-VILLARD 129d256be29SBo Shen static int macb_is_gem(struct macb_device *macb) 130d256be29SBo Shen { 131d256be29SBo Shen return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2; 132d256be29SBo Shen } 133d256be29SBo Shen 13475b03cf1SGregory CLEMENT #ifndef cpu_is_sama5d2 13575b03cf1SGregory CLEMENT #define cpu_is_sama5d2() 0 13675b03cf1SGregory CLEMENT #endif 13775b03cf1SGregory CLEMENT 13875b03cf1SGregory CLEMENT #ifndef cpu_is_sama5d4 13975b03cf1SGregory CLEMENT #define cpu_is_sama5d4() 0 14075b03cf1SGregory CLEMENT #endif 14175b03cf1SGregory CLEMENT 14275b03cf1SGregory CLEMENT static int gem_is_gigabit_capable(struct macb_device *macb) 14375b03cf1SGregory CLEMENT { 14475b03cf1SGregory CLEMENT /* 1451cc0a9f4SRobert P. J. Day * The GEM controllers embedded in SAMA5D2 and SAMA5D4 are 14675b03cf1SGregory CLEMENT * configured to support only 10/100. 14775b03cf1SGregory CLEMENT */ 14875b03cf1SGregory CLEMENT return macb_is_gem(macb) && !cpu_is_sama5d2() && !cpu_is_sama5d4(); 14975b03cf1SGregory CLEMENT } 15075b03cf1SGregory CLEMENT 1512439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) 1522439e4bfSJean-Christophe PLAGNIOL-VILLARD { 1532439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 1542439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 1552439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 1562439e4bfSJean-Christophe PLAGNIOL-VILLARD 1572439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1582439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 1592439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1602439e4bfSJean-Christophe PLAGNIOL-VILLARD 1612439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 1622439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 1) 1632439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, macb->phy_addr) 1642439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 1652439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2) 1662439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(DATA, value)); 1672439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, MAN, frame); 1682439e4bfSJean-Christophe PLAGNIOL-VILLARD 1692439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 1702439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(macb, NSR); 1712439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 1722439e4bfSJean-Christophe PLAGNIOL-VILLARD 1732439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1742439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 1752439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1762439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1772439e4bfSJean-Christophe PLAGNIOL-VILLARD 1782439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 macb_mdio_read(struct macb_device *macb, u8 reg) 1792439e4bfSJean-Christophe PLAGNIOL-VILLARD { 1802439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 1812439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 1822439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 1832439e4bfSJean-Christophe PLAGNIOL-VILLARD 1842439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1852439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 1862439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1872439e4bfSJean-Christophe PLAGNIOL-VILLARD 1882439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 1892439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 2) 1902439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, macb->phy_addr) 1912439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 1922439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2)); 1932439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, MAN, frame); 1942439e4bfSJean-Christophe PLAGNIOL-VILLARD 1952439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 1962439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(macb, NSR); 1972439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 1982439e4bfSJean-Christophe PLAGNIOL-VILLARD 1992439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = macb_readl(macb, MAN); 2002439e4bfSJean-Christophe PLAGNIOL-VILLARD 2012439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 2022439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 2032439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 2042439e4bfSJean-Christophe PLAGNIOL-VILLARD 2052439e4bfSJean-Christophe PLAGNIOL-VILLARD return MACB_BFEXT(DATA, frame); 2062439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2072439e4bfSJean-Christophe PLAGNIOL-VILLARD 2081b8c18b9SJoe Hershberger void __weak arch_get_mdio_control(const char *name) 209416ce623SShiraz Hashim { 210416ce623SShiraz Hashim return; 211416ce623SShiraz Hashim } 212416ce623SShiraz Hashim 213b1a0006eSBo Shen #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) 2140f751d6eSSemih Hazar 2155a49f174SJoe Hershberger int macb_miiphy_read(struct mii_dev *bus, int phy_adr, int devad, int reg) 2160f751d6eSSemih Hazar { 2175a49f174SJoe Hershberger u16 value = 0; 218f1dcc19bSSimon Glass #ifdef CONFIG_DM_ETH 2195a49f174SJoe Hershberger struct udevice *dev = eth_get_dev_by_name(bus->name); 220f1dcc19bSSimon Glass struct macb_device *macb = dev_get_priv(dev); 221f1dcc19bSSimon Glass #else 2225a49f174SJoe Hershberger struct eth_device *dev = eth_get_dev_by_name(bus->name); 2230f751d6eSSemih Hazar struct macb_device *macb = to_macb(dev); 224f1dcc19bSSimon Glass #endif 2250f751d6eSSemih Hazar 2260f751d6eSSemih Hazar if (macb->phy_addr != phy_adr) 2270f751d6eSSemih Hazar return -1; 2280f751d6eSSemih Hazar 2295a49f174SJoe Hershberger arch_get_mdio_control(bus->name); 2305a49f174SJoe Hershberger value = macb_mdio_read(macb, reg); 2310f751d6eSSemih Hazar 2325a49f174SJoe Hershberger return value; 2330f751d6eSSemih Hazar } 2340f751d6eSSemih Hazar 2355a49f174SJoe Hershberger int macb_miiphy_write(struct mii_dev *bus, int phy_adr, int devad, int reg, 2365a49f174SJoe Hershberger u16 value) 2370f751d6eSSemih Hazar { 238f1dcc19bSSimon Glass #ifdef CONFIG_DM_ETH 2395a49f174SJoe Hershberger struct udevice *dev = eth_get_dev_by_name(bus->name); 240f1dcc19bSSimon Glass struct macb_device *macb = dev_get_priv(dev); 241f1dcc19bSSimon Glass #else 2425a49f174SJoe Hershberger struct eth_device *dev = eth_get_dev_by_name(bus->name); 2430f751d6eSSemih Hazar struct macb_device *macb = to_macb(dev); 244f1dcc19bSSimon Glass #endif 2450f751d6eSSemih Hazar 2460f751d6eSSemih Hazar if (macb->phy_addr != phy_adr) 2470f751d6eSSemih Hazar return -1; 2480f751d6eSSemih Hazar 2495a49f174SJoe Hershberger arch_get_mdio_control(bus->name); 2500f751d6eSSemih Hazar macb_mdio_write(macb, reg, value); 2510f751d6eSSemih Hazar 2520f751d6eSSemih Hazar return 0; 2530f751d6eSSemih Hazar } 2540f751d6eSSemih Hazar #endif 2550f751d6eSSemih Hazar 2565ae0e382SWu, Josh #define RX 1 2575ae0e382SWu, Josh #define TX 0 2585ae0e382SWu, Josh static inline void macb_invalidate_ring_desc(struct macb_device *macb, bool rx) 2595ae0e382SWu, Josh { 2605ae0e382SWu, Josh if (rx) 261592a7495SHeiko Schocher invalidate_dcache_range(macb->rx_ring_dma, 262592a7495SHeiko Schocher ALIGN(macb->rx_ring_dma + MACB_RX_DMA_DESC_SIZE, 263592a7495SHeiko Schocher PKTALIGN)); 2645ae0e382SWu, Josh else 265592a7495SHeiko Schocher invalidate_dcache_range(macb->tx_ring_dma, 266592a7495SHeiko Schocher ALIGN(macb->tx_ring_dma + MACB_TX_DMA_DESC_SIZE, 267592a7495SHeiko Schocher PKTALIGN)); 2685ae0e382SWu, Josh } 2695ae0e382SWu, Josh 2705ae0e382SWu, Josh static inline void macb_flush_ring_desc(struct macb_device *macb, bool rx) 2715ae0e382SWu, Josh { 2725ae0e382SWu, Josh if (rx) 2735ae0e382SWu, Josh flush_dcache_range(macb->rx_ring_dma, macb->rx_ring_dma + 274592a7495SHeiko Schocher ALIGN(MACB_RX_DMA_DESC_SIZE, PKTALIGN)); 2755ae0e382SWu, Josh else 2765ae0e382SWu, Josh flush_dcache_range(macb->tx_ring_dma, macb->tx_ring_dma + 277592a7495SHeiko Schocher ALIGN(MACB_TX_DMA_DESC_SIZE, PKTALIGN)); 2785ae0e382SWu, Josh } 2795ae0e382SWu, Josh 2805ae0e382SWu, Josh static inline void macb_flush_rx_buffer(struct macb_device *macb) 2815ae0e382SWu, Josh { 2825ae0e382SWu, Josh flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + 283592a7495SHeiko Schocher ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN)); 2845ae0e382SWu, Josh } 2855ae0e382SWu, Josh 2865ae0e382SWu, Josh static inline void macb_invalidate_rx_buffer(struct macb_device *macb) 2875ae0e382SWu, Josh { 2885ae0e382SWu, Josh invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma + 289592a7495SHeiko Schocher ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN)); 2905ae0e382SWu, Josh } 2910f751d6eSSemih Hazar 2922439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_NET) 2932439e4bfSJean-Christophe PLAGNIOL-VILLARD 294d5555b70SSimon Glass static int _macb_send(struct macb_device *macb, const char *name, void *packet, 295d5555b70SSimon Glass int length) 2962439e4bfSJean-Christophe PLAGNIOL-VILLARD { 2972439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long paddr, ctrl; 2982439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_head = macb->tx_head; 2992439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 3002439e4bfSJean-Christophe PLAGNIOL-VILLARD 3012439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr = dma_map_single(packet, length, DMA_TO_DEVICE); 3022439e4bfSJean-Christophe PLAGNIOL-VILLARD 3032439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl = length & TXBUF_FRMLEN_MASK; 3042439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl |= TXBUF_FRAME_END; 305ceef983bSAndreas Bießmann if (tx_head == (MACB_TX_RING_SIZE - 1)) { 3062439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl |= TXBUF_WRAP; 3072439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_head = 0; 308ceef983bSAndreas Bießmann } else { 3092439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_head++; 310ceef983bSAndreas Bießmann } 3112439e4bfSJean-Christophe PLAGNIOL-VILLARD 3122439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[tx_head].ctrl = ctrl; 3132439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[tx_head].addr = paddr; 3142439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 3155ae0e382SWu, Josh macb_flush_ring_desc(macb, TX); 3165ae0e382SWu, Josh /* Do we need check paddr and length is dcache line aligned? */ 317f589f8ccSSimon Glass flush_dcache_range(paddr, paddr + ALIGN(length, ARCH_DMA_MINALIGN)); 3182439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); 3192439e4bfSJean-Christophe PLAGNIOL-VILLARD 3202439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 3212439e4bfSJean-Christophe PLAGNIOL-VILLARD * I guess this is necessary because the networking core may 3222439e4bfSJean-Christophe PLAGNIOL-VILLARD * re-use the transmit buffer as soon as we return... 3232439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 324ceef983bSAndreas Bießmann for (i = 0; i <= MACB_TX_TIMEOUT; i++) { 3252439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 3265ae0e382SWu, Josh macb_invalidate_ring_desc(macb, TX); 3272439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl = macb->tx_ring[tx_head].ctrl; 3282439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_USED) 3292439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 3302439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(1); 3312439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3322439e4bfSJean-Christophe PLAGNIOL-VILLARD 3332439e4bfSJean-Christophe PLAGNIOL-VILLARD dma_unmap_single(packet, length, paddr); 3342439e4bfSJean-Christophe PLAGNIOL-VILLARD 335ceef983bSAndreas Bießmann if (i <= MACB_TX_TIMEOUT) { 3362439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_UNDERRUN) 337d5555b70SSimon Glass printf("%s: TX underrun\n", name); 3382439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_EXHAUSTED) 339d5555b70SSimon Glass printf("%s: TX buffers exhausted in mid frame\n", name); 3402439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 341d5555b70SSimon Glass printf("%s: TX timeout\n", name); 3422439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3432439e4bfSJean-Christophe PLAGNIOL-VILLARD 3442439e4bfSJean-Christophe PLAGNIOL-VILLARD /* No one cares anyway */ 3452439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 3462439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3472439e4bfSJean-Christophe PLAGNIOL-VILLARD 3482439e4bfSJean-Christophe PLAGNIOL-VILLARD static void reclaim_rx_buffers(struct macb_device *macb, 3492439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int new_tail) 3502439e4bfSJean-Christophe PLAGNIOL-VILLARD { 3512439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int i; 3522439e4bfSJean-Christophe PLAGNIOL-VILLARD 3532439e4bfSJean-Christophe PLAGNIOL-VILLARD i = macb->rx_tail; 3545ae0e382SWu, Josh 3555ae0e382SWu, Josh macb_invalidate_ring_desc(macb, RX); 3562439e4bfSJean-Christophe PLAGNIOL-VILLARD while (i > new_tail) { 3572439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr &= ~RXADDR_USED; 3582439e4bfSJean-Christophe PLAGNIOL-VILLARD i++; 359ceef983bSAndreas Bießmann if (i > MACB_RX_RING_SIZE) 3602439e4bfSJean-Christophe PLAGNIOL-VILLARD i = 0; 3612439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3622439e4bfSJean-Christophe PLAGNIOL-VILLARD 3632439e4bfSJean-Christophe PLAGNIOL-VILLARD while (i < new_tail) { 3642439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr &= ~RXADDR_USED; 3652439e4bfSJean-Christophe PLAGNIOL-VILLARD i++; 3662439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3672439e4bfSJean-Christophe PLAGNIOL-VILLARD 3682439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 3695ae0e382SWu, Josh macb_flush_ring_desc(macb, RX); 3702439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_tail = new_tail; 3712439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3722439e4bfSJean-Christophe PLAGNIOL-VILLARD 373d5555b70SSimon Glass static int _macb_recv(struct macb_device *macb, uchar **packetp) 3742439e4bfSJean-Christophe PLAGNIOL-VILLARD { 375d5555b70SSimon Glass unsigned int next_rx_tail = macb->next_rx_tail; 3762439e4bfSJean-Christophe PLAGNIOL-VILLARD void *buffer; 3772439e4bfSJean-Christophe PLAGNIOL-VILLARD int length; 3782439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 status; 3792439e4bfSJean-Christophe PLAGNIOL-VILLARD 380d5555b70SSimon Glass macb->wrapped = false; 3812439e4bfSJean-Christophe PLAGNIOL-VILLARD for (;;) { 3825ae0e382SWu, Josh macb_invalidate_ring_desc(macb, RX); 3835ae0e382SWu, Josh 384d5555b70SSimon Glass if (!(macb->rx_ring[next_rx_tail].addr & RXADDR_USED)) 385d5555b70SSimon Glass return -EAGAIN; 3862439e4bfSJean-Christophe PLAGNIOL-VILLARD 387d5555b70SSimon Glass status = macb->rx_ring[next_rx_tail].ctrl; 3882439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & RXBUF_FRAME_START) { 389d5555b70SSimon Glass if (next_rx_tail != macb->rx_tail) 390d5555b70SSimon Glass reclaim_rx_buffers(macb, next_rx_tail); 391d5555b70SSimon Glass macb->wrapped = false; 3922439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3932439e4bfSJean-Christophe PLAGNIOL-VILLARD 3942439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & RXBUF_FRAME_END) { 3952439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer = macb->rx_buffer + 128 * macb->rx_tail; 3962439e4bfSJean-Christophe PLAGNIOL-VILLARD length = status & RXBUF_FRMLEN_MASK; 3975ae0e382SWu, Josh 3985ae0e382SWu, Josh macb_invalidate_rx_buffer(macb); 399d5555b70SSimon Glass if (macb->wrapped) { 4002439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int headlen, taillen; 4012439e4bfSJean-Christophe PLAGNIOL-VILLARD 402ceef983bSAndreas Bießmann headlen = 128 * (MACB_RX_RING_SIZE 4032439e4bfSJean-Christophe PLAGNIOL-VILLARD - macb->rx_tail); 4042439e4bfSJean-Christophe PLAGNIOL-VILLARD taillen = length - headlen; 4051fd92db8SJoe Hershberger memcpy((void *)net_rx_packets[0], 4062439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer, headlen); 4071fd92db8SJoe Hershberger memcpy((void *)net_rx_packets[0] + headlen, 4082439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_buffer, taillen); 409d5555b70SSimon Glass *packetp = (void *)net_rx_packets[0]; 410d5555b70SSimon Glass } else { 411d5555b70SSimon Glass *packetp = buffer; 4122439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4132439e4bfSJean-Christophe PLAGNIOL-VILLARD 414d5555b70SSimon Glass if (++next_rx_tail >= MACB_RX_RING_SIZE) 415d5555b70SSimon Glass next_rx_tail = 0; 416d5555b70SSimon Glass macb->next_rx_tail = next_rx_tail; 417d5555b70SSimon Glass return length; 4182439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 419d5555b70SSimon Glass if (++next_rx_tail >= MACB_RX_RING_SIZE) { 420d5555b70SSimon Glass macb->wrapped = true; 421d5555b70SSimon Glass next_rx_tail = 0; 4222439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4232439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4242439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 4252439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4262439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4272439e4bfSJean-Christophe PLAGNIOL-VILLARD 428d5555b70SSimon Glass static void macb_phy_reset(struct macb_device *macb, const char *name) 4292439e4bfSJean-Christophe PLAGNIOL-VILLARD { 4302439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 4312439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 status, adv; 4322439e4bfSJean-Christophe PLAGNIOL-VILLARD 4332439e4bfSJean-Christophe PLAGNIOL-VILLARD adv = ADVERTISE_CSMA | ADVERTISE_ALL; 4342439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_mdio_write(macb, MII_ADVERTISE, adv); 435d5555b70SSimon Glass printf("%s: Starting autonegotiation...\n", name); 4362439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE 4372439e4bfSJean-Christophe PLAGNIOL-VILLARD | BMCR_ANRESTART)); 4382439e4bfSJean-Christophe PLAGNIOL-VILLARD 439ceef983bSAndreas Bießmann for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { 4402439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 4412439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_ANEGCOMPLETE) 4422439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 4432439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(100); 4442439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4452439e4bfSJean-Christophe PLAGNIOL-VILLARD 4462439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_ANEGCOMPLETE) 447d5555b70SSimon Glass printf("%s: Autonegotiation complete\n", name); 4482439e4bfSJean-Christophe PLAGNIOL-VILLARD else 4492439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: Autonegotiation timed out (status=0x%04x)\n", 450d5555b70SSimon Glass name, status); 4512439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4522439e4bfSJean-Christophe PLAGNIOL-VILLARD 453a212b66dSWenyou Yang static int macb_phy_find(struct macb_device *macb, const char *name) 454fc01ea1eSGunnar Rangoy { 455fc01ea1eSGunnar Rangoy int i; 456fc01ea1eSGunnar Rangoy u16 phy_id; 457fc01ea1eSGunnar Rangoy 458fc01ea1eSGunnar Rangoy /* Search for PHY... */ 459fc01ea1eSGunnar Rangoy for (i = 0; i < 32; i++) { 460fc01ea1eSGunnar Rangoy macb->phy_addr = i; 461fc01ea1eSGunnar Rangoy phy_id = macb_mdio_read(macb, MII_PHYSID1); 462fc01ea1eSGunnar Rangoy if (phy_id != 0xffff) { 463a212b66dSWenyou Yang printf("%s: PHY present at %d\n", name, i); 464fc01ea1eSGunnar Rangoy return 1; 465fc01ea1eSGunnar Rangoy } 466fc01ea1eSGunnar Rangoy } 467fc01ea1eSGunnar Rangoy 468fc01ea1eSGunnar Rangoy /* PHY isn't up to snuff */ 469a212b66dSWenyou Yang printf("%s: PHY not found\n", name); 470fc01ea1eSGunnar Rangoy 471fc01ea1eSGunnar Rangoy return 0; 472fc01ea1eSGunnar Rangoy } 473fc01ea1eSGunnar Rangoy 474a212b66dSWenyou Yang #ifdef CONFIG_DM_ETH 475a212b66dSWenyou Yang static int macb_phy_init(struct udevice *dev, const char *name) 476a212b66dSWenyou Yang #else 477d5555b70SSimon Glass static int macb_phy_init(struct macb_device *macb, const char *name) 478a212b66dSWenyou Yang #endif 4792439e4bfSJean-Christophe PLAGNIOL-VILLARD { 480a212b66dSWenyou Yang #ifdef CONFIG_DM_ETH 481a212b66dSWenyou Yang struct macb_device *macb = dev_get_priv(dev); 482a212b66dSWenyou Yang #endif 4832439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncfgr; 4842439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 phy_id, status, adv, lpa; 4852439e4bfSJean-Christophe PLAGNIOL-VILLARD int media, speed, duplex; 4862439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 4872439e4bfSJean-Christophe PLAGNIOL-VILLARD 488d5555b70SSimon Glass arch_get_mdio_control(name); 489fc01ea1eSGunnar Rangoy /* Auto-detect phy_addr */ 490a212b66dSWenyou Yang if (!macb_phy_find(macb, name)) 491fc01ea1eSGunnar Rangoy return 0; 492fc01ea1eSGunnar Rangoy 4932439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Check if the PHY is up to snuff... */ 4942439e4bfSJean-Christophe PLAGNIOL-VILLARD phy_id = macb_mdio_read(macb, MII_PHYSID1); 4952439e4bfSJean-Christophe PLAGNIOL-VILLARD if (phy_id == 0xffff) { 496d5555b70SSimon Glass printf("%s: No PHY present\n", name); 4972439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 4982439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4992439e4bfSJean-Christophe PLAGNIOL-VILLARD 500b1a0006eSBo Shen #ifdef CONFIG_PHYLIB 501a212b66dSWenyou Yang #ifdef CONFIG_DM_ETH 5021870d4d7SWenyou Yang macb->phydev = phy_connect(macb->bus, macb->phy_addr, dev, 503a212b66dSWenyou Yang macb->phy_interface); 504a212b66dSWenyou Yang #else 5058314ccd8SBo Shen /* need to consider other phy interface mode */ 5061870d4d7SWenyou Yang macb->phydev = phy_connect(macb->bus, macb->phy_addr, &macb->netdev, 5078314ccd8SBo Shen PHY_INTERFACE_MODE_RGMII); 508a212b66dSWenyou Yang #endif 5091870d4d7SWenyou Yang if (!macb->phydev) { 5108314ccd8SBo Shen printf("phy_connect failed\n"); 5118314ccd8SBo Shen return -ENODEV; 5128314ccd8SBo Shen } 5138314ccd8SBo Shen 5141870d4d7SWenyou Yang phy_config(macb->phydev); 515b1a0006eSBo Shen #endif 516b1a0006eSBo Shen 5172439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 5182439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(status & BMSR_LSTATUS)) { 5192439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Try to re-negotiate if we don't have link already. */ 520d5555b70SSimon Glass macb_phy_reset(macb, name); 5212439e4bfSJean-Christophe PLAGNIOL-VILLARD 522ceef983bSAndreas Bießmann for (i = 0; i < MACB_AUTONEG_TIMEOUT / 100; i++) { 5232439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 5242439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_LSTATUS) 5252439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 5262439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(100); 5272439e4bfSJean-Christophe PLAGNIOL-VILLARD } 5282439e4bfSJean-Christophe PLAGNIOL-VILLARD } 5292439e4bfSJean-Christophe PLAGNIOL-VILLARD 5302439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(status & BMSR_LSTATUS)) { 5312439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: link down (status: 0x%04x)\n", 532d5555b70SSimon Glass name, status); 5332439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 534d256be29SBo Shen } 535d256be29SBo Shen 53675b03cf1SGregory CLEMENT /* First check for GMAC and that it is GiB capable */ 53775b03cf1SGregory CLEMENT if (gem_is_gigabit_capable(macb)) { 538d256be29SBo Shen lpa = macb_mdio_read(macb, MII_STAT1000); 539d256be29SBo Shen 54047609577SAndreas Bießmann if (lpa & (LPA_1000FULL | LPA_1000HALF)) { 54147609577SAndreas Bießmann duplex = ((lpa & LPA_1000FULL) ? 1 : 0); 54247609577SAndreas Bießmann 54347609577SAndreas Bießmann printf("%s: link up, 1000Mbps %s-duplex (lpa: 0x%04x)\n", 544d5555b70SSimon Glass name, 545d256be29SBo Shen duplex ? "full" : "half", 546d256be29SBo Shen lpa); 547d256be29SBo Shen 548d256be29SBo Shen ncfgr = macb_readl(macb, NCFGR); 54947609577SAndreas Bießmann ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); 550d256be29SBo Shen ncfgr |= GEM_BIT(GBE); 55147609577SAndreas Bießmann 552d256be29SBo Shen if (duplex) 553d256be29SBo Shen ncfgr |= MACB_BIT(FD); 55447609577SAndreas Bießmann 555d256be29SBo Shen macb_writel(macb, NCFGR, ncfgr); 556d256be29SBo Shen 557d256be29SBo Shen return 1; 558d256be29SBo Shen } 559d256be29SBo Shen } 560d256be29SBo Shen 561d256be29SBo Shen /* fall back for EMAC checking */ 5622439e4bfSJean-Christophe PLAGNIOL-VILLARD adv = macb_mdio_read(macb, MII_ADVERTISE); 5632439e4bfSJean-Christophe PLAGNIOL-VILLARD lpa = macb_mdio_read(macb, MII_LPA); 5642439e4bfSJean-Christophe PLAGNIOL-VILLARD media = mii_nway_result(lpa & adv); 5652439e4bfSJean-Christophe PLAGNIOL-VILLARD speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) 5662439e4bfSJean-Christophe PLAGNIOL-VILLARD ? 1 : 0); 5672439e4bfSJean-Christophe PLAGNIOL-VILLARD duplex = (media & ADVERTISE_FULL) ? 1 : 0; 5682439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", 569d5555b70SSimon Glass name, 5702439e4bfSJean-Christophe PLAGNIOL-VILLARD speed ? "100" : "10", 5712439e4bfSJean-Christophe PLAGNIOL-VILLARD duplex ? "full" : "half", 5722439e4bfSJean-Christophe PLAGNIOL-VILLARD lpa); 5732439e4bfSJean-Christophe PLAGNIOL-VILLARD 5742439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = macb_readl(macb, NCFGR); 575c83cb5f6SBo Shen ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); 5762439e4bfSJean-Christophe PLAGNIOL-VILLARD if (speed) 5772439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr |= MACB_BIT(SPD); 5782439e4bfSJean-Christophe PLAGNIOL-VILLARD if (duplex) 5792439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr |= MACB_BIT(FD); 5802439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCFGR, ncfgr); 581d256be29SBo Shen 5822439e4bfSJean-Christophe PLAGNIOL-VILLARD return 1; 5832439e4bfSJean-Christophe PLAGNIOL-VILLARD } 5842439e4bfSJean-Christophe PLAGNIOL-VILLARD 585ade4ea4dSWu, Josh static int gmac_init_multi_queues(struct macb_device *macb) 586ade4ea4dSWu, Josh { 587ade4ea4dSWu, Josh int i, num_queues = 1; 588ade4ea4dSWu, Josh u32 queue_mask; 589ade4ea4dSWu, Josh 590ade4ea4dSWu, Josh /* bit 0 is never set but queue 0 always exists */ 591ade4ea4dSWu, Josh queue_mask = gem_readl(macb, DCFG6) & 0xff; 592ade4ea4dSWu, Josh queue_mask |= 0x1; 593ade4ea4dSWu, Josh 594ade4ea4dSWu, Josh for (i = 1; i < MACB_MAX_QUEUES; i++) 595ade4ea4dSWu, Josh if (queue_mask & (1 << i)) 596ade4ea4dSWu, Josh num_queues++; 597ade4ea4dSWu, Josh 598ade4ea4dSWu, Josh macb->dummy_desc->ctrl = TXBUF_USED; 599ade4ea4dSWu, Josh macb->dummy_desc->addr = 0; 600ade4ea4dSWu, Josh flush_dcache_range(macb->dummy_desc_dma, macb->dummy_desc_dma + 601592a7495SHeiko Schocher ALIGN(MACB_TX_DUMMY_DMA_DESC_SIZE, PKTALIGN)); 602ade4ea4dSWu, Josh 603ade4ea4dSWu, Josh for (i = 1; i < num_queues; i++) 604ade4ea4dSWu, Josh gem_writel_queue_TBQP(macb, macb->dummy_desc_dma, i - 1); 605ade4ea4dSWu, Josh 606ade4ea4dSWu, Josh return 0; 607ade4ea4dSWu, Josh } 608ade4ea4dSWu, Josh 609a212b66dSWenyou Yang #ifdef CONFIG_DM_ETH 610a212b66dSWenyou Yang static int _macb_init(struct udevice *dev, const char *name) 611a212b66dSWenyou Yang #else 612d5555b70SSimon Glass static int _macb_init(struct macb_device *macb, const char *name) 613a212b66dSWenyou Yang #endif 6142439e4bfSJean-Christophe PLAGNIOL-VILLARD { 615a212b66dSWenyou Yang #ifdef CONFIG_DM_ETH 616a212b66dSWenyou Yang struct macb_device *macb = dev_get_priv(dev); 617a212b66dSWenyou Yang #endif 6182439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long paddr; 6192439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 6202439e4bfSJean-Christophe PLAGNIOL-VILLARD 6212439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 6222439e4bfSJean-Christophe PLAGNIOL-VILLARD * macb_halt should have been called at some point before now, 6232439e4bfSJean-Christophe PLAGNIOL-VILLARD * so we'll assume the controller is idle. 6242439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 6252439e4bfSJean-Christophe PLAGNIOL-VILLARD 6262439e4bfSJean-Christophe PLAGNIOL-VILLARD /* initialize DMA descriptors */ 6272439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr = macb->rx_buffer_dma; 628ceef983bSAndreas Bießmann for (i = 0; i < MACB_RX_RING_SIZE; i++) { 629ceef983bSAndreas Bießmann if (i == (MACB_RX_RING_SIZE - 1)) 6302439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr |= RXADDR_WRAP; 6312439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr = paddr; 6322439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].ctrl = 0; 6332439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr += 128; 6342439e4bfSJean-Christophe PLAGNIOL-VILLARD } 6355ae0e382SWu, Josh macb_flush_ring_desc(macb, RX); 6365ae0e382SWu, Josh macb_flush_rx_buffer(macb); 6375ae0e382SWu, Josh 638ceef983bSAndreas Bießmann for (i = 0; i < MACB_TX_RING_SIZE; i++) { 6392439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].addr = 0; 640ceef983bSAndreas Bießmann if (i == (MACB_TX_RING_SIZE - 1)) 6412439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP; 6422439e4bfSJean-Christophe PLAGNIOL-VILLARD else 6432439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].ctrl = TXBUF_USED; 6442439e4bfSJean-Christophe PLAGNIOL-VILLARD } 6455ae0e382SWu, Josh macb_flush_ring_desc(macb, TX); 6465ae0e382SWu, Josh 647ceef983bSAndreas Bießmann macb->rx_tail = 0; 648ceef983bSAndreas Bießmann macb->tx_head = 0; 649ceef983bSAndreas Bießmann macb->tx_tail = 0; 650d5555b70SSimon Glass macb->next_rx_tail = 0; 6512439e4bfSJean-Christophe PLAGNIOL-VILLARD 6522439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, RBQP, macb->rx_ring_dma); 6532439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, TBQP, macb->tx_ring_dma); 6542439e4bfSJean-Christophe PLAGNIOL-VILLARD 655d256be29SBo Shen if (macb_is_gem(macb)) { 656ade4ea4dSWu, Josh /* Check the multi queue and initialize the queue for tx */ 657ade4ea4dSWu, Josh gmac_init_multi_queues(macb); 658ade4ea4dSWu, Josh 659cabf61ceSBo Shen /* 660cabf61ceSBo Shen * When the GMAC IP with GE feature, this bit is used to 661cabf61ceSBo Shen * select interface between RGMII and GMII. 662cabf61ceSBo Shen * When the GMAC IP without GE feature, this bit is used 663cabf61ceSBo Shen * to select interface between RMII and MII. 664cabf61ceSBo Shen */ 665a212b66dSWenyou Yang #ifdef CONFIG_DM_ETH 666*6de046eaSWenyou Yang if ((macb->phy_interface == PHY_INTERFACE_MODE_RMII) || 667*6de046eaSWenyou Yang (macb->phy_interface == PHY_INTERFACE_MODE_RGMII)) 668a212b66dSWenyou Yang gem_writel(macb, UR, GEM_BIT(RGMII)); 669a212b66dSWenyou Yang else 670a212b66dSWenyou Yang gem_writel(macb, UR, 0); 671a212b66dSWenyou Yang #else 672cabf61ceSBo Shen #if defined(CONFIG_RGMII) || defined(CONFIG_RMII) 673d256be29SBo Shen gem_writel(macb, UR, GEM_BIT(RGMII)); 674d256be29SBo Shen #else 675d256be29SBo Shen gem_writel(macb, UR, 0); 676d256be29SBo Shen #endif 677a212b66dSWenyou Yang #endif 678d256be29SBo Shen } else { 6792439e4bfSJean-Christophe PLAGNIOL-VILLARD /* choose RMII or MII mode. This depends on the board */ 680a212b66dSWenyou Yang #ifdef CONFIG_DM_ETH 681a212b66dSWenyou Yang #ifdef CONFIG_AT91FAMILY 682a212b66dSWenyou Yang if (macb->phy_interface == PHY_INTERFACE_MODE_RMII) { 683a212b66dSWenyou Yang macb_writel(macb, USRIO, 684a212b66dSWenyou Yang MACB_BIT(RMII) | MACB_BIT(CLKEN)); 685a212b66dSWenyou Yang } else { 686a212b66dSWenyou Yang macb_writel(macb, USRIO, MACB_BIT(CLKEN)); 687a212b66dSWenyou Yang } 688a212b66dSWenyou Yang #else 689a212b66dSWenyou Yang if (macb->phy_interface == PHY_INTERFACE_MODE_RMII) 690a212b66dSWenyou Yang macb_writel(macb, USRIO, 0); 691a212b66dSWenyou Yang else 692a212b66dSWenyou Yang macb_writel(macb, USRIO, MACB_BIT(MII)); 693a212b66dSWenyou Yang #endif 694a212b66dSWenyou Yang #else 6952439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_RMII 696d8f64b44SBo Shen #ifdef CONFIG_AT91FAMILY 6977263ef19SStelian Pop macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN)); 6987263ef19SStelian Pop #else 6992439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, USRIO, 0); 7007263ef19SStelian Pop #endif 7017263ef19SStelian Pop #else 702d8f64b44SBo Shen #ifdef CONFIG_AT91FAMILY 7037263ef19SStelian Pop macb_writel(macb, USRIO, MACB_BIT(CLKEN)); 7042439e4bfSJean-Christophe PLAGNIOL-VILLARD #else 7052439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, USRIO, MACB_BIT(MII)); 7062439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 7077263ef19SStelian Pop #endif /* CONFIG_RMII */ 708a212b66dSWenyou Yang #endif 709d256be29SBo Shen } 7102439e4bfSJean-Christophe PLAGNIOL-VILLARD 711a212b66dSWenyou Yang #ifdef CONFIG_DM_ETH 712a212b66dSWenyou Yang if (!macb_phy_init(dev, name)) 713a212b66dSWenyou Yang #else 714d5555b70SSimon Glass if (!macb_phy_init(macb, name)) 715a212b66dSWenyou Yang #endif 716422b1a01SBen Warren return -1; 7172439e4bfSJean-Christophe PLAGNIOL-VILLARD 7182439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Enable TX and RX */ 7192439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE)); 7202439e4bfSJean-Christophe PLAGNIOL-VILLARD 721422b1a01SBen Warren return 0; 7222439e4bfSJean-Christophe PLAGNIOL-VILLARD } 7232439e4bfSJean-Christophe PLAGNIOL-VILLARD 724d5555b70SSimon Glass static void _macb_halt(struct macb_device *macb) 7252439e4bfSJean-Christophe PLAGNIOL-VILLARD { 7262439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncr, tsr; 7272439e4bfSJean-Christophe PLAGNIOL-VILLARD 7282439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Halt the controller and wait for any ongoing transmission to end. */ 7292439e4bfSJean-Christophe PLAGNIOL-VILLARD ncr = macb_readl(macb, NCR); 7302439e4bfSJean-Christophe PLAGNIOL-VILLARD ncr |= MACB_BIT(THALT); 7312439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, ncr); 7322439e4bfSJean-Christophe PLAGNIOL-VILLARD 7332439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 7342439e4bfSJean-Christophe PLAGNIOL-VILLARD tsr = macb_readl(macb, TSR); 7352439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (tsr & MACB_BIT(TGO)); 7362439e4bfSJean-Christophe PLAGNIOL-VILLARD 7372439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Disable TX and RX, and clear statistics */ 7382439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(CLRSTAT)); 7392439e4bfSJean-Christophe PLAGNIOL-VILLARD } 7402439e4bfSJean-Christophe PLAGNIOL-VILLARD 741d5555b70SSimon Glass static int _macb_write_hwaddr(struct macb_device *macb, unsigned char *enetaddr) 7426bb46790SBen Warren { 7436bb46790SBen Warren u32 hwaddr_bottom; 7446bb46790SBen Warren u16 hwaddr_top; 7456bb46790SBen Warren 7466bb46790SBen Warren /* set hardware address */ 747d5555b70SSimon Glass hwaddr_bottom = enetaddr[0] | enetaddr[1] << 8 | 748d5555b70SSimon Glass enetaddr[2] << 16 | enetaddr[3] << 24; 7496bb46790SBen Warren macb_writel(macb, SA1B, hwaddr_bottom); 750d5555b70SSimon Glass hwaddr_top = enetaddr[4] | enetaddr[5] << 8; 7516bb46790SBen Warren macb_writel(macb, SA1T, hwaddr_top); 7526bb46790SBen Warren return 0; 7536bb46790SBen Warren } 7546bb46790SBen Warren 755d256be29SBo Shen static u32 macb_mdc_clk_div(int id, struct macb_device *macb) 756d256be29SBo Shen { 757d256be29SBo Shen u32 config; 7583fd2b3aaSWenyou Yang #if defined(CONFIG_DM_ETH) && defined(CONFIG_CLK) 759577aa3b3SWenyou Yang unsigned long macb_hz = macb->pclk_rate; 760577aa3b3SWenyou Yang #else 761d256be29SBo Shen unsigned long macb_hz = get_macb_pclk_rate(id); 762577aa3b3SWenyou Yang #endif 763d256be29SBo Shen 764d256be29SBo Shen if (macb_hz < 20000000) 765d256be29SBo Shen config = MACB_BF(CLK, MACB_CLK_DIV8); 766d256be29SBo Shen else if (macb_hz < 40000000) 767d256be29SBo Shen config = MACB_BF(CLK, MACB_CLK_DIV16); 768d256be29SBo Shen else if (macb_hz < 80000000) 769d256be29SBo Shen config = MACB_BF(CLK, MACB_CLK_DIV32); 770d256be29SBo Shen else 771d256be29SBo Shen config = MACB_BF(CLK, MACB_CLK_DIV64); 772d256be29SBo Shen 773d256be29SBo Shen return config; 774d256be29SBo Shen } 775d256be29SBo Shen 776d256be29SBo Shen static u32 gem_mdc_clk_div(int id, struct macb_device *macb) 777d256be29SBo Shen { 778d256be29SBo Shen u32 config; 779577aa3b3SWenyou Yang 7803fd2b3aaSWenyou Yang #if defined(CONFIG_DM_ETH) && defined(CONFIG_CLK) 781577aa3b3SWenyou Yang unsigned long macb_hz = macb->pclk_rate; 782577aa3b3SWenyou Yang #else 783d256be29SBo Shen unsigned long macb_hz = get_macb_pclk_rate(id); 784577aa3b3SWenyou Yang #endif 785d256be29SBo Shen 786d256be29SBo Shen if (macb_hz < 20000000) 787d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV8); 788d256be29SBo Shen else if (macb_hz < 40000000) 789d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV16); 790d256be29SBo Shen else if (macb_hz < 80000000) 791d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV32); 792d256be29SBo Shen else if (macb_hz < 120000000) 793d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV48); 794d256be29SBo Shen else if (macb_hz < 160000000) 795d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV64); 796d256be29SBo Shen else 797d256be29SBo Shen config = GEM_BF(CLK, GEM_CLK_DIV96); 798d256be29SBo Shen 799d256be29SBo Shen return config; 800d256be29SBo Shen } 801d256be29SBo Shen 80232e4f6bfSBo Shen /* 80332e4f6bfSBo Shen * Get the DMA bus width field of the network configuration register that we 80432e4f6bfSBo Shen * should program. We find the width from decoding the design configuration 80532e4f6bfSBo Shen * register to find the maximum supported data bus width. 80632e4f6bfSBo Shen */ 80732e4f6bfSBo Shen static u32 macb_dbw(struct macb_device *macb) 80832e4f6bfSBo Shen { 80932e4f6bfSBo Shen switch (GEM_BFEXT(DBWDEF, gem_readl(macb, DCFG1))) { 81032e4f6bfSBo Shen case 4: 81132e4f6bfSBo Shen return GEM_BF(DBW, GEM_DBW128); 81232e4f6bfSBo Shen case 2: 81332e4f6bfSBo Shen return GEM_BF(DBW, GEM_DBW64); 81432e4f6bfSBo Shen case 1: 81532e4f6bfSBo Shen default: 81632e4f6bfSBo Shen return GEM_BF(DBW, GEM_DBW32); 81732e4f6bfSBo Shen } 81832e4f6bfSBo Shen } 81932e4f6bfSBo Shen 820d5555b70SSimon Glass static void _macb_eth_initialize(struct macb_device *macb) 8212439e4bfSJean-Christophe PLAGNIOL-VILLARD { 822d5555b70SSimon Glass int id = 0; /* This is not used by functions we call */ 8232439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncfgr; 8242439e4bfSJean-Christophe PLAGNIOL-VILLARD 825d5555b70SSimon Glass /* TODO: we need check the rx/tx_ring_dma is dcache line aligned */ 826ceef983bSAndreas Bießmann macb->rx_buffer = dma_alloc_coherent(MACB_RX_BUFFER_SIZE, 8272439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->rx_buffer_dma); 8285ae0e382SWu, Josh macb->rx_ring = dma_alloc_coherent(MACB_RX_DMA_DESC_SIZE, 8292439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->rx_ring_dma); 8305ae0e382SWu, Josh macb->tx_ring = dma_alloc_coherent(MACB_TX_DMA_DESC_SIZE, 8312439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->tx_ring_dma); 832ade4ea4dSWu, Josh macb->dummy_desc = dma_alloc_coherent(MACB_TX_DUMMY_DMA_DESC_SIZE, 833ade4ea4dSWu, Josh &macb->dummy_desc_dma); 8342439e4bfSJean-Christophe PLAGNIOL-VILLARD 835d5555b70SSimon Glass /* 836d5555b70SSimon Glass * Do some basic initialization so that we at least can talk 837d5555b70SSimon Glass * to the PHY 838d5555b70SSimon Glass */ 839d5555b70SSimon Glass if (macb_is_gem(macb)) { 840d5555b70SSimon Glass ncfgr = gem_mdc_clk_div(id, macb); 841d5555b70SSimon Glass ncfgr |= macb_dbw(macb); 842d5555b70SSimon Glass } else { 843d5555b70SSimon Glass ncfgr = macb_mdc_clk_div(id, macb); 844d5555b70SSimon Glass } 845d5555b70SSimon Glass 846d5555b70SSimon Glass macb_writel(macb, NCFGR, ncfgr); 847d5555b70SSimon Glass } 848d5555b70SSimon Glass 849f1dcc19bSSimon Glass #ifndef CONFIG_DM_ETH 850d5555b70SSimon Glass static int macb_send(struct eth_device *netdev, void *packet, int length) 851d5555b70SSimon Glass { 852d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 853d5555b70SSimon Glass 854d5555b70SSimon Glass return _macb_send(macb, netdev->name, packet, length); 855d5555b70SSimon Glass } 856d5555b70SSimon Glass 857d5555b70SSimon Glass static int macb_recv(struct eth_device *netdev) 858d5555b70SSimon Glass { 859d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 860d5555b70SSimon Glass uchar *packet; 861d5555b70SSimon Glass int length; 862d5555b70SSimon Glass 863d5555b70SSimon Glass macb->wrapped = false; 864d5555b70SSimon Glass for (;;) { 865d5555b70SSimon Glass macb->next_rx_tail = macb->rx_tail; 866d5555b70SSimon Glass length = _macb_recv(macb, &packet); 867d5555b70SSimon Glass if (length >= 0) { 868d5555b70SSimon Glass net_process_received_packet(packet, length); 869d5555b70SSimon Glass reclaim_rx_buffers(macb, macb->next_rx_tail); 870d5555b70SSimon Glass } else if (length < 0) { 871d5555b70SSimon Glass return length; 872d5555b70SSimon Glass } 873d5555b70SSimon Glass } 874d5555b70SSimon Glass } 875d5555b70SSimon Glass 876d5555b70SSimon Glass static int macb_init(struct eth_device *netdev, bd_t *bd) 877d5555b70SSimon Glass { 878d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 879d5555b70SSimon Glass 880d5555b70SSimon Glass return _macb_init(macb, netdev->name); 881d5555b70SSimon Glass } 882d5555b70SSimon Glass 883d5555b70SSimon Glass static void macb_halt(struct eth_device *netdev) 884d5555b70SSimon Glass { 885d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 886d5555b70SSimon Glass 887d5555b70SSimon Glass return _macb_halt(macb); 888d5555b70SSimon Glass } 889d5555b70SSimon Glass 890d5555b70SSimon Glass static int macb_write_hwaddr(struct eth_device *netdev) 891d5555b70SSimon Glass { 892d5555b70SSimon Glass struct macb_device *macb = to_macb(netdev); 893d5555b70SSimon Glass 894d5555b70SSimon Glass return _macb_write_hwaddr(macb, netdev->enetaddr); 895d5555b70SSimon Glass } 896d5555b70SSimon Glass 897d5555b70SSimon Glass int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) 898d5555b70SSimon Glass { 899d5555b70SSimon Glass struct macb_device *macb; 900d5555b70SSimon Glass struct eth_device *netdev; 901d5555b70SSimon Glass 902d5555b70SSimon Glass macb = malloc(sizeof(struct macb_device)); 903d5555b70SSimon Glass if (!macb) { 904d5555b70SSimon Glass printf("Error: Failed to allocate memory for MACB%d\n", id); 905d5555b70SSimon Glass return -1; 906d5555b70SSimon Glass } 907d5555b70SSimon Glass memset(macb, 0, sizeof(struct macb_device)); 908d5555b70SSimon Glass 909d5555b70SSimon Glass netdev = &macb->netdev; 9105ae0e382SWu, Josh 9112439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->regs = regs; 9122439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->phy_addr = phy_addr; 9132439e4bfSJean-Christophe PLAGNIOL-VILLARD 914d256be29SBo Shen if (macb_is_gem(macb)) 915d256be29SBo Shen sprintf(netdev->name, "gmac%d", id); 916d256be29SBo Shen else 9172439e4bfSJean-Christophe PLAGNIOL-VILLARD sprintf(netdev->name, "macb%d", id); 918d256be29SBo Shen 9192439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->init = macb_init; 9202439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->halt = macb_halt; 9212439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->send = macb_send; 9222439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->recv = macb_recv; 9236bb46790SBen Warren netdev->write_hwaddr = macb_write_hwaddr; 9242439e4bfSJean-Christophe PLAGNIOL-VILLARD 925d5555b70SSimon Glass _macb_eth_initialize(macb); 9262439e4bfSJean-Christophe PLAGNIOL-VILLARD 9272439e4bfSJean-Christophe PLAGNIOL-VILLARD eth_register(netdev); 9282439e4bfSJean-Christophe PLAGNIOL-VILLARD 929b1a0006eSBo Shen #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) 9305a49f174SJoe Hershberger int retval; 9315a49f174SJoe Hershberger struct mii_dev *mdiodev = mdio_alloc(); 9325a49f174SJoe Hershberger if (!mdiodev) 9335a49f174SJoe Hershberger return -ENOMEM; 9345a49f174SJoe Hershberger strncpy(mdiodev->name, netdev->name, MDIO_NAME_LEN); 9355a49f174SJoe Hershberger mdiodev->read = macb_miiphy_read; 9365a49f174SJoe Hershberger mdiodev->write = macb_miiphy_write; 9375a49f174SJoe Hershberger 9385a49f174SJoe Hershberger retval = mdio_register(mdiodev); 9395a49f174SJoe Hershberger if (retval < 0) 9405a49f174SJoe Hershberger return retval; 941b1a0006eSBo Shen macb->bus = miiphy_get_dev_by_name(netdev->name); 9420f751d6eSSemih Hazar #endif 9432439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 9442439e4bfSJean-Christophe PLAGNIOL-VILLARD } 945f1dcc19bSSimon Glass #endif /* !CONFIG_DM_ETH */ 946f1dcc19bSSimon Glass 947f1dcc19bSSimon Glass #ifdef CONFIG_DM_ETH 948f1dcc19bSSimon Glass 949f1dcc19bSSimon Glass static int macb_start(struct udevice *dev) 950f1dcc19bSSimon Glass { 951a212b66dSWenyou Yang return _macb_init(dev, dev->name); 952f1dcc19bSSimon Glass } 953f1dcc19bSSimon Glass 954f1dcc19bSSimon Glass static int macb_send(struct udevice *dev, void *packet, int length) 955f1dcc19bSSimon Glass { 956f1dcc19bSSimon Glass struct macb_device *macb = dev_get_priv(dev); 957f1dcc19bSSimon Glass 958f1dcc19bSSimon Glass return _macb_send(macb, dev->name, packet, length); 959f1dcc19bSSimon Glass } 960f1dcc19bSSimon Glass 961f1dcc19bSSimon Glass static int macb_recv(struct udevice *dev, int flags, uchar **packetp) 962f1dcc19bSSimon Glass { 963f1dcc19bSSimon Glass struct macb_device *macb = dev_get_priv(dev); 964f1dcc19bSSimon Glass 965f1dcc19bSSimon Glass macb->next_rx_tail = macb->rx_tail; 966f1dcc19bSSimon Glass macb->wrapped = false; 967f1dcc19bSSimon Glass 968f1dcc19bSSimon Glass return _macb_recv(macb, packetp); 969f1dcc19bSSimon Glass } 970f1dcc19bSSimon Glass 971f1dcc19bSSimon Glass static int macb_free_pkt(struct udevice *dev, uchar *packet, int length) 972f1dcc19bSSimon Glass { 973f1dcc19bSSimon Glass struct macb_device *macb = dev_get_priv(dev); 974f1dcc19bSSimon Glass 975f1dcc19bSSimon Glass reclaim_rx_buffers(macb, macb->next_rx_tail); 976f1dcc19bSSimon Glass 977f1dcc19bSSimon Glass return 0; 978f1dcc19bSSimon Glass } 979f1dcc19bSSimon Glass 980f1dcc19bSSimon Glass static void macb_stop(struct udevice *dev) 981f1dcc19bSSimon Glass { 982f1dcc19bSSimon Glass struct macb_device *macb = dev_get_priv(dev); 983f1dcc19bSSimon Glass 984f1dcc19bSSimon Glass _macb_halt(macb); 985f1dcc19bSSimon Glass } 986f1dcc19bSSimon Glass 987f1dcc19bSSimon Glass static int macb_write_hwaddr(struct udevice *dev) 988f1dcc19bSSimon Glass { 989f1dcc19bSSimon Glass struct eth_pdata *plat = dev_get_platdata(dev); 990f1dcc19bSSimon Glass struct macb_device *macb = dev_get_priv(dev); 991f1dcc19bSSimon Glass 992f1dcc19bSSimon Glass return _macb_write_hwaddr(macb, plat->enetaddr); 993f1dcc19bSSimon Glass } 994f1dcc19bSSimon Glass 995f1dcc19bSSimon Glass static const struct eth_ops macb_eth_ops = { 996f1dcc19bSSimon Glass .start = macb_start, 997f1dcc19bSSimon Glass .send = macb_send, 998f1dcc19bSSimon Glass .recv = macb_recv, 999f1dcc19bSSimon Glass .stop = macb_stop, 1000f1dcc19bSSimon Glass .free_pkt = macb_free_pkt, 1001f1dcc19bSSimon Glass .write_hwaddr = macb_write_hwaddr, 1002f1dcc19bSSimon Glass }; 1003f1dcc19bSSimon Glass 10043fd2b3aaSWenyou Yang #ifdef CONFIG_CLK 1005577aa3b3SWenyou Yang static int macb_enable_clk(struct udevice *dev) 1006577aa3b3SWenyou Yang { 1007577aa3b3SWenyou Yang struct macb_device *macb = dev_get_priv(dev); 1008577aa3b3SWenyou Yang struct clk clk; 1009577aa3b3SWenyou Yang ulong clk_rate; 1010577aa3b3SWenyou Yang int ret; 1011577aa3b3SWenyou Yang 1012577aa3b3SWenyou Yang ret = clk_get_by_index(dev, 0, &clk); 1013577aa3b3SWenyou Yang if (ret) 1014577aa3b3SWenyou Yang return -EINVAL; 1015577aa3b3SWenyou Yang 1016577aa3b3SWenyou Yang ret = clk_enable(&clk); 1017577aa3b3SWenyou Yang if (ret) 1018577aa3b3SWenyou Yang return ret; 1019577aa3b3SWenyou Yang 1020577aa3b3SWenyou Yang clk_rate = clk_get_rate(&clk); 1021577aa3b3SWenyou Yang if (!clk_rate) 1022577aa3b3SWenyou Yang return -EINVAL; 1023577aa3b3SWenyou Yang 1024577aa3b3SWenyou Yang macb->pclk_rate = clk_rate; 1025577aa3b3SWenyou Yang 1026577aa3b3SWenyou Yang return 0; 1027577aa3b3SWenyou Yang } 10283fd2b3aaSWenyou Yang #endif 1029577aa3b3SWenyou Yang 1030f1dcc19bSSimon Glass static int macb_eth_probe(struct udevice *dev) 1031f1dcc19bSSimon Glass { 1032f1dcc19bSSimon Glass struct eth_pdata *pdata = dev_get_platdata(dev); 1033f1dcc19bSSimon Glass struct macb_device *macb = dev_get_priv(dev); 1034a212b66dSWenyou Yang const char *phy_mode; 10351870d4d7SWenyou Yang __maybe_unused int ret; 1036a212b66dSWenyou Yang 1037e160f7d4SSimon Glass phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode", 1038e160f7d4SSimon Glass NULL); 1039a212b66dSWenyou Yang if (phy_mode) 1040a212b66dSWenyou Yang macb->phy_interface = phy_get_interface_by_name(phy_mode); 1041a212b66dSWenyou Yang if (macb->phy_interface == -1) { 1042a212b66dSWenyou Yang debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); 1043a212b66dSWenyou Yang return -EINVAL; 1044a212b66dSWenyou Yang } 1045a212b66dSWenyou Yang 1046f1dcc19bSSimon Glass macb->regs = (void *)pdata->iobase; 1047f1dcc19bSSimon Glass 10483fd2b3aaSWenyou Yang #ifdef CONFIG_CLK 10491870d4d7SWenyou Yang ret = macb_enable_clk(dev); 1050577aa3b3SWenyou Yang if (ret) 1051577aa3b3SWenyou Yang return ret; 10523fd2b3aaSWenyou Yang #endif 1053577aa3b3SWenyou Yang 1054f1dcc19bSSimon Glass _macb_eth_initialize(macb); 1055577aa3b3SWenyou Yang 1056f1dcc19bSSimon Glass #if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) 10571870d4d7SWenyou Yang macb->bus = mdio_alloc(); 10581870d4d7SWenyou Yang if (!macb->bus) 10595a49f174SJoe Hershberger return -ENOMEM; 10601870d4d7SWenyou Yang strncpy(macb->bus->name, dev->name, MDIO_NAME_LEN); 10611870d4d7SWenyou Yang macb->bus->read = macb_miiphy_read; 10621870d4d7SWenyou Yang macb->bus->write = macb_miiphy_write; 10635a49f174SJoe Hershberger 10641870d4d7SWenyou Yang ret = mdio_register(macb->bus); 10651870d4d7SWenyou Yang if (ret < 0) 10661870d4d7SWenyou Yang return ret; 1067f1dcc19bSSimon Glass macb->bus = miiphy_get_dev_by_name(dev->name); 1068f1dcc19bSSimon Glass #endif 1069f1dcc19bSSimon Glass 1070f1dcc19bSSimon Glass return 0; 1071f1dcc19bSSimon Glass } 1072f1dcc19bSSimon Glass 10731870d4d7SWenyou Yang static int macb_eth_remove(struct udevice *dev) 10741870d4d7SWenyou Yang { 10751870d4d7SWenyou Yang struct macb_device *macb = dev_get_priv(dev); 10761870d4d7SWenyou Yang 10771870d4d7SWenyou Yang #ifdef CONFIG_PHYLIB 10781870d4d7SWenyou Yang free(macb->phydev); 10791870d4d7SWenyou Yang #endif 10801870d4d7SWenyou Yang mdio_unregister(macb->bus); 10811870d4d7SWenyou Yang mdio_free(macb->bus); 10821870d4d7SWenyou Yang 10831870d4d7SWenyou Yang return 0; 10841870d4d7SWenyou Yang } 10851870d4d7SWenyou Yang 1086f1dcc19bSSimon Glass static int macb_eth_ofdata_to_platdata(struct udevice *dev) 1087f1dcc19bSSimon Glass { 1088f1dcc19bSSimon Glass struct eth_pdata *pdata = dev_get_platdata(dev); 1089f1dcc19bSSimon Glass 1090a821c4afSSimon Glass pdata->iobase = devfdt_get_addr(dev); 1091f1dcc19bSSimon Glass return 0; 1092f1dcc19bSSimon Glass } 1093f1dcc19bSSimon Glass 1094f1dcc19bSSimon Glass static const struct udevice_id macb_eth_ids[] = { 1095f1dcc19bSSimon Glass { .compatible = "cdns,macb" }, 109675460253SWenyou Yang { .compatible = "cdns,at91sam9260-macb" }, 109775460253SWenyou Yang { .compatible = "atmel,sama5d2-gem" }, 109875460253SWenyou Yang { .compatible = "atmel,sama5d3-gem" }, 109975460253SWenyou Yang { .compatible = "atmel,sama5d4-gem" }, 1100f1dcc19bSSimon Glass { } 1101f1dcc19bSSimon Glass }; 1102f1dcc19bSSimon Glass 1103f1dcc19bSSimon Glass U_BOOT_DRIVER(eth_macb) = { 1104f1dcc19bSSimon Glass .name = "eth_macb", 1105f1dcc19bSSimon Glass .id = UCLASS_ETH, 1106f1dcc19bSSimon Glass .of_match = macb_eth_ids, 1107f1dcc19bSSimon Glass .ofdata_to_platdata = macb_eth_ofdata_to_platdata, 1108f1dcc19bSSimon Glass .probe = macb_eth_probe, 11091870d4d7SWenyou Yang .remove = macb_eth_remove, 1110f1dcc19bSSimon Glass .ops = &macb_eth_ops, 1111f1dcc19bSSimon Glass .priv_auto_alloc_size = sizeof(struct macb_device), 1112f1dcc19bSSimon Glass .platdata_auto_alloc_size = sizeof(struct eth_pdata), 1113f1dcc19bSSimon Glass }; 1114f1dcc19bSSimon Glass #endif 11152439e4bfSJean-Christophe PLAGNIOL-VILLARD 11162439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 1117