12439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 22439e4bfSJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2005-2006 Atmel Corporation 32439e4bfSJean-Christophe PLAGNIOL-VILLARD * 42439e4bfSJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or modify 52439e4bfSJean-Christophe PLAGNIOL-VILLARD * it under the terms of the GNU General Public License as published by 62439e4bfSJean-Christophe PLAGNIOL-VILLARD * the Free Software Foundation; either version 2 of the License, or 72439e4bfSJean-Christophe PLAGNIOL-VILLARD * (at your option) any later version. 82439e4bfSJean-Christophe PLAGNIOL-VILLARD * 92439e4bfSJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 102439e4bfSJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 112439e4bfSJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 122439e4bfSJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 132439e4bfSJean-Christophe PLAGNIOL-VILLARD * 142439e4bfSJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 152439e4bfSJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 162439e4bfSJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 172439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 182439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h> 192439e4bfSJean-Christophe PLAGNIOL-VILLARD 202439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 212439e4bfSJean-Christophe PLAGNIOL-VILLARD * The u-boot networking stack is a little weird. It seems like the 222439e4bfSJean-Christophe PLAGNIOL-VILLARD * networking core allocates receive buffers up front without any 232439e4bfSJean-Christophe PLAGNIOL-VILLARD * regard to the hardware that's supposed to actually receive those 242439e4bfSJean-Christophe PLAGNIOL-VILLARD * packets. 252439e4bfSJean-Christophe PLAGNIOL-VILLARD * 262439e4bfSJean-Christophe PLAGNIOL-VILLARD * The MACB receives packets into 128-byte receive buffers, so the 272439e4bfSJean-Christophe PLAGNIOL-VILLARD * buffers allocated by the core isn't very practical to use. We'll 282439e4bfSJean-Christophe PLAGNIOL-VILLARD * allocate our own, but we need one such buffer in case a packet 292439e4bfSJean-Christophe PLAGNIOL-VILLARD * wraps around the DMA ring so that we have to copy it. 302439e4bfSJean-Christophe PLAGNIOL-VILLARD * 316d0f6bcfSJean-Christophe PLAGNIOL-VILLARD * Therefore, define CONFIG_SYS_RX_ETH_BUFFER to 1 in the board-specific 322439e4bfSJean-Christophe PLAGNIOL-VILLARD * configuration header. This way, the core allocates one RX buffer 332439e4bfSJean-Christophe PLAGNIOL-VILLARD * and one TX buffer, each of which can hold a ethernet packet of 342439e4bfSJean-Christophe PLAGNIOL-VILLARD * maximum size. 352439e4bfSJean-Christophe PLAGNIOL-VILLARD * 362439e4bfSJean-Christophe PLAGNIOL-VILLARD * For some reason, the networking core unconditionally specifies a 372439e4bfSJean-Christophe PLAGNIOL-VILLARD * 32-byte packet "alignment" (which really should be called 382439e4bfSJean-Christophe PLAGNIOL-VILLARD * "padding"). MACB shouldn't need that, but we'll refrain from any 392439e4bfSJean-Christophe PLAGNIOL-VILLARD * core modifications here... 402439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 412439e4bfSJean-Christophe PLAGNIOL-VILLARD 422439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h> 4389973f8aSBen Warren #include <netdev.h> 442439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h> 452439e4bfSJean-Christophe PLAGNIOL-VILLARD 462439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <linux/mii.h> 472439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 482439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/dma-mapping.h> 492439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/clk.h> 502439e4bfSJean-Christophe PLAGNIOL-VILLARD 512439e4bfSJean-Christophe PLAGNIOL-VILLARD #include "macb.h" 522439e4bfSJean-Christophe PLAGNIOL-VILLARD 532439e4bfSJean-Christophe PLAGNIOL-VILLARD #define barrier() asm volatile("" ::: "memory") 542439e4bfSJean-Christophe PLAGNIOL-VILLARD 556d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_MACB_RX_BUFFER_SIZE 4096 566d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_MACB_RX_RING_SIZE (CONFIG_SYS_MACB_RX_BUFFER_SIZE / 128) 576d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_MACB_TX_RING_SIZE 16 586d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_MACB_TX_TIMEOUT 1000 596d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define CONFIG_SYS_MACB_AUTONEG_TIMEOUT 5000000 602439e4bfSJean-Christophe PLAGNIOL-VILLARD 612439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc { 622439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 addr; 632439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ctrl; 642439e4bfSJean-Christophe PLAGNIOL-VILLARD }; 652439e4bfSJean-Christophe PLAGNIOL-VILLARD 662439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_USED 0x00000001 672439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_WRAP 0x00000002 682439e4bfSJean-Christophe PLAGNIOL-VILLARD 692439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRMLEN_MASK 0x00000fff 702439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_START 0x00004000 712439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_END 0x00008000 722439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_TYPEID_MATCH 0x00400000 732439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR4_MATCH 0x00800000 742439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR3_MATCH 0x01000000 752439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR2_MATCH 0x02000000 762439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR1_MATCH 0x04000000 772439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_BROADCAST 0x80000000 782439e4bfSJean-Christophe PLAGNIOL-VILLARD 792439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRMLEN_MASK 0x000007ff 802439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRAME_END 0x00008000 812439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_NOCRC 0x00010000 822439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_EXHAUSTED 0x08000000 832439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_UNDERRUN 0x10000000 842439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_MAXRETRY 0x20000000 852439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_WRAP 0x40000000 862439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_USED 0x80000000 872439e4bfSJean-Christophe PLAGNIOL-VILLARD 882439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device { 892439e4bfSJean-Christophe PLAGNIOL-VILLARD void *regs; 902439e4bfSJean-Christophe PLAGNIOL-VILLARD 912439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int rx_tail; 922439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_head; 932439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_tail; 942439e4bfSJean-Christophe PLAGNIOL-VILLARD 952439e4bfSJean-Christophe PLAGNIOL-VILLARD void *rx_buffer; 962439e4bfSJean-Christophe PLAGNIOL-VILLARD void *tx_buffer; 972439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc *rx_ring; 982439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc *tx_ring; 992439e4bfSJean-Christophe PLAGNIOL-VILLARD 1002439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long rx_buffer_dma; 1012439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long rx_ring_dma; 1022439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long tx_ring_dma; 1032439e4bfSJean-Christophe PLAGNIOL-VILLARD 1042439e4bfSJean-Christophe PLAGNIOL-VILLARD const struct device *dev; 1052439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device netdev; 1062439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned short phy_addr; 1072439e4bfSJean-Christophe PLAGNIOL-VILLARD }; 1082439e4bfSJean-Christophe PLAGNIOL-VILLARD #define to_macb(_nd) container_of(_nd, struct macb_device, netdev) 1092439e4bfSJean-Christophe PLAGNIOL-VILLARD 1102439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) 1112439e4bfSJean-Christophe PLAGNIOL-VILLARD { 1122439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 1132439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 1142439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 1152439e4bfSJean-Christophe PLAGNIOL-VILLARD 1162439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1172439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 1182439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1192439e4bfSJean-Christophe PLAGNIOL-VILLARD 1202439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 1212439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 1) 1222439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, macb->phy_addr) 1232439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 1242439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2) 1252439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(DATA, value)); 1262439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, MAN, frame); 1272439e4bfSJean-Christophe PLAGNIOL-VILLARD 1282439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 1292439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(macb, NSR); 1302439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 1312439e4bfSJean-Christophe PLAGNIOL-VILLARD 1322439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1332439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 1342439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1352439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1362439e4bfSJean-Christophe PLAGNIOL-VILLARD 1372439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 macb_mdio_read(struct macb_device *macb, u8 reg) 1382439e4bfSJean-Christophe PLAGNIOL-VILLARD { 1392439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 1402439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 1412439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 1422439e4bfSJean-Christophe PLAGNIOL-VILLARD 1432439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1442439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 1452439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1462439e4bfSJean-Christophe PLAGNIOL-VILLARD 1472439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 1482439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 2) 1492439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, macb->phy_addr) 1502439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 1512439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2)); 1522439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, MAN, frame); 1532439e4bfSJean-Christophe PLAGNIOL-VILLARD 1542439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 1552439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(macb, NSR); 1562439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 1572439e4bfSJean-Christophe PLAGNIOL-VILLARD 1582439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = macb_readl(macb, MAN); 1592439e4bfSJean-Christophe PLAGNIOL-VILLARD 1602439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 1612439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 1622439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 1632439e4bfSJean-Christophe PLAGNIOL-VILLARD 1642439e4bfSJean-Christophe PLAGNIOL-VILLARD return MACB_BFEXT(DATA, frame); 1652439e4bfSJean-Christophe PLAGNIOL-VILLARD } 1662439e4bfSJean-Christophe PLAGNIOL-VILLARD 1672439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_NET) 1682439e4bfSJean-Christophe PLAGNIOL-VILLARD 1692439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_send(struct eth_device *netdev, volatile void *packet, 1702439e4bfSJean-Christophe PLAGNIOL-VILLARD int length) 1712439e4bfSJean-Christophe PLAGNIOL-VILLARD { 1722439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb = to_macb(netdev); 1732439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long paddr, ctrl; 1742439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_head = macb->tx_head; 1752439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 1762439e4bfSJean-Christophe PLAGNIOL-VILLARD 1772439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr = dma_map_single(packet, length, DMA_TO_DEVICE); 1782439e4bfSJean-Christophe PLAGNIOL-VILLARD 1792439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl = length & TXBUF_FRMLEN_MASK; 1802439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl |= TXBUF_FRAME_END; 1816d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (tx_head == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) { 1822439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl |= TXBUF_WRAP; 1832439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_head = 0; 1842439e4bfSJean-Christophe PLAGNIOL-VILLARD } else 1852439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_head++; 1862439e4bfSJean-Christophe PLAGNIOL-VILLARD 1872439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[tx_head].ctrl = ctrl; 1882439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[tx_head].addr = paddr; 1892439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 1902439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); 1912439e4bfSJean-Christophe PLAGNIOL-VILLARD 1922439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 1932439e4bfSJean-Christophe PLAGNIOL-VILLARD * I guess this is necessary because the networking core may 1942439e4bfSJean-Christophe PLAGNIOL-VILLARD * re-use the transmit buffer as soon as we return... 1952439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 1966d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i <= CONFIG_SYS_MACB_TX_TIMEOUT; i++) { 1972439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 1982439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl = macb->tx_ring[tx_head].ctrl; 1992439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_USED) 2002439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 2012439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(1); 2022439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2032439e4bfSJean-Christophe PLAGNIOL-VILLARD 2042439e4bfSJean-Christophe PLAGNIOL-VILLARD dma_unmap_single(packet, length, paddr); 2052439e4bfSJean-Christophe PLAGNIOL-VILLARD 2066d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (i <= CONFIG_SYS_MACB_TX_TIMEOUT) { 2072439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_UNDERRUN) 2082439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: TX underrun\n", netdev->name); 2092439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_EXHAUSTED) 2102439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: TX buffers exhausted in mid frame\n", 2112439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->name); 2122439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 2132439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: TX timeout\n", netdev->name); 2142439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2152439e4bfSJean-Christophe PLAGNIOL-VILLARD 2162439e4bfSJean-Christophe PLAGNIOL-VILLARD /* No one cares anyway */ 2172439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 2182439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2192439e4bfSJean-Christophe PLAGNIOL-VILLARD 2202439e4bfSJean-Christophe PLAGNIOL-VILLARD static void reclaim_rx_buffers(struct macb_device *macb, 2212439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int new_tail) 2222439e4bfSJean-Christophe PLAGNIOL-VILLARD { 2232439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int i; 2242439e4bfSJean-Christophe PLAGNIOL-VILLARD 2252439e4bfSJean-Christophe PLAGNIOL-VILLARD i = macb->rx_tail; 2262439e4bfSJean-Christophe PLAGNIOL-VILLARD while (i > new_tail) { 2272439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr &= ~RXADDR_USED; 2282439e4bfSJean-Christophe PLAGNIOL-VILLARD i++; 2296d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (i > CONFIG_SYS_MACB_RX_RING_SIZE) 2302439e4bfSJean-Christophe PLAGNIOL-VILLARD i = 0; 2312439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2322439e4bfSJean-Christophe PLAGNIOL-VILLARD 2332439e4bfSJean-Christophe PLAGNIOL-VILLARD while (i < new_tail) { 2342439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr &= ~RXADDR_USED; 2352439e4bfSJean-Christophe PLAGNIOL-VILLARD i++; 2362439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2372439e4bfSJean-Christophe PLAGNIOL-VILLARD 2382439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 2392439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_tail = new_tail; 2402439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2412439e4bfSJean-Christophe PLAGNIOL-VILLARD 2422439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_recv(struct eth_device *netdev) 2432439e4bfSJean-Christophe PLAGNIOL-VILLARD { 2442439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb = to_macb(netdev); 2452439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int rx_tail = macb->rx_tail; 2462439e4bfSJean-Christophe PLAGNIOL-VILLARD void *buffer; 2472439e4bfSJean-Christophe PLAGNIOL-VILLARD int length; 2482439e4bfSJean-Christophe PLAGNIOL-VILLARD int wrapped = 0; 2492439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 status; 2502439e4bfSJean-Christophe PLAGNIOL-VILLARD 2512439e4bfSJean-Christophe PLAGNIOL-VILLARD for (;;) { 2522439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED)) 2532439e4bfSJean-Christophe PLAGNIOL-VILLARD return -1; 2542439e4bfSJean-Christophe PLAGNIOL-VILLARD 2552439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb->rx_ring[rx_tail].ctrl; 2562439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & RXBUF_FRAME_START) { 2572439e4bfSJean-Christophe PLAGNIOL-VILLARD if (rx_tail != macb->rx_tail) 2582439e4bfSJean-Christophe PLAGNIOL-VILLARD reclaim_rx_buffers(macb, rx_tail); 2592439e4bfSJean-Christophe PLAGNIOL-VILLARD wrapped = 0; 2602439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2612439e4bfSJean-Christophe PLAGNIOL-VILLARD 2622439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & RXBUF_FRAME_END) { 2632439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer = macb->rx_buffer + 128 * macb->rx_tail; 2642439e4bfSJean-Christophe PLAGNIOL-VILLARD length = status & RXBUF_FRMLEN_MASK; 2652439e4bfSJean-Christophe PLAGNIOL-VILLARD if (wrapped) { 2662439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int headlen, taillen; 2672439e4bfSJean-Christophe PLAGNIOL-VILLARD 2686d0f6bcfSJean-Christophe PLAGNIOL-VILLARD headlen = 128 * (CONFIG_SYS_MACB_RX_RING_SIZE 2692439e4bfSJean-Christophe PLAGNIOL-VILLARD - macb->rx_tail); 2702439e4bfSJean-Christophe PLAGNIOL-VILLARD taillen = length - headlen; 2712439e4bfSJean-Christophe PLAGNIOL-VILLARD memcpy((void *)NetRxPackets[0], 2722439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer, headlen); 2732439e4bfSJean-Christophe PLAGNIOL-VILLARD memcpy((void *)NetRxPackets[0] + headlen, 2742439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_buffer, taillen); 2752439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer = (void *)NetRxPackets[0]; 2762439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2772439e4bfSJean-Christophe PLAGNIOL-VILLARD 2782439e4bfSJean-Christophe PLAGNIOL-VILLARD NetReceive(buffer, length); 2796d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) 2802439e4bfSJean-Christophe PLAGNIOL-VILLARD rx_tail = 0; 2812439e4bfSJean-Christophe PLAGNIOL-VILLARD reclaim_rx_buffers(macb, rx_tail); 2822439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 2836d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) { 2842439e4bfSJean-Christophe PLAGNIOL-VILLARD wrapped = 1; 2852439e4bfSJean-Christophe PLAGNIOL-VILLARD rx_tail = 0; 2862439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2872439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2882439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 2892439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2902439e4bfSJean-Christophe PLAGNIOL-VILLARD 2912439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 2922439e4bfSJean-Christophe PLAGNIOL-VILLARD } 2932439e4bfSJean-Christophe PLAGNIOL-VILLARD 2942439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_phy_reset(struct macb_device *macb) 2952439e4bfSJean-Christophe PLAGNIOL-VILLARD { 2962439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device *netdev = &macb->netdev; 2972439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 2982439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 status, adv; 2992439e4bfSJean-Christophe PLAGNIOL-VILLARD 3002439e4bfSJean-Christophe PLAGNIOL-VILLARD adv = ADVERTISE_CSMA | ADVERTISE_ALL; 3012439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_mdio_write(macb, MII_ADVERTISE, adv); 3022439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: Starting autonegotiation...\n", netdev->name); 3032439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE 3042439e4bfSJean-Christophe PLAGNIOL-VILLARD | BMCR_ANRESTART)); 3052439e4bfSJean-Christophe PLAGNIOL-VILLARD 3066d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) { 3072439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 3082439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_ANEGCOMPLETE) 3092439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 3102439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(100); 3112439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3122439e4bfSJean-Christophe PLAGNIOL-VILLARD 3132439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_ANEGCOMPLETE) 3142439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: Autonegotiation complete\n", netdev->name); 3152439e4bfSJean-Christophe PLAGNIOL-VILLARD else 3162439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: Autonegotiation timed out (status=0x%04x)\n", 3172439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->name, status); 3182439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3192439e4bfSJean-Christophe PLAGNIOL-VILLARD 320*fc01ea1eSGunnar Rangoy #ifdef CONFIG_MACB_SEARCH_PHY 321*fc01ea1eSGunnar Rangoy static int macb_phy_find(struct macb_device *macb) 322*fc01ea1eSGunnar Rangoy { 323*fc01ea1eSGunnar Rangoy int i; 324*fc01ea1eSGunnar Rangoy u16 phy_id; 325*fc01ea1eSGunnar Rangoy 326*fc01ea1eSGunnar Rangoy /* Search for PHY... */ 327*fc01ea1eSGunnar Rangoy for (i = 0; i < 32; i++) { 328*fc01ea1eSGunnar Rangoy macb->phy_addr = i; 329*fc01ea1eSGunnar Rangoy phy_id = macb_mdio_read(macb, MII_PHYSID1); 330*fc01ea1eSGunnar Rangoy if (phy_id != 0xffff) { 331*fc01ea1eSGunnar Rangoy printf("%s: PHY present at %d\n", macb->netdev.name, i); 332*fc01ea1eSGunnar Rangoy return 1; 333*fc01ea1eSGunnar Rangoy } 334*fc01ea1eSGunnar Rangoy } 335*fc01ea1eSGunnar Rangoy 336*fc01ea1eSGunnar Rangoy /* PHY isn't up to snuff */ 337*fc01ea1eSGunnar Rangoy printf("%s: PHY not found", macb->netdev.name); 338*fc01ea1eSGunnar Rangoy 339*fc01ea1eSGunnar Rangoy return 0; 340*fc01ea1eSGunnar Rangoy } 341*fc01ea1eSGunnar Rangoy #endif /* CONFIG_MACB_SEARCH_PHY */ 342*fc01ea1eSGunnar Rangoy 343*fc01ea1eSGunnar Rangoy 3442439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_phy_init(struct macb_device *macb) 3452439e4bfSJean-Christophe PLAGNIOL-VILLARD { 3462439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device *netdev = &macb->netdev; 3472439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncfgr; 3482439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 phy_id, status, adv, lpa; 3492439e4bfSJean-Christophe PLAGNIOL-VILLARD int media, speed, duplex; 3502439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 3512439e4bfSJean-Christophe PLAGNIOL-VILLARD 352*fc01ea1eSGunnar Rangoy #ifdef CONFIG_MACB_SEARCH_PHY 353*fc01ea1eSGunnar Rangoy /* Auto-detect phy_addr */ 354*fc01ea1eSGunnar Rangoy if (!macb_phy_find(macb)) { 355*fc01ea1eSGunnar Rangoy return 0; 356*fc01ea1eSGunnar Rangoy } 357*fc01ea1eSGunnar Rangoy #endif /* CONFIG_MACB_SEARCH_PHY */ 358*fc01ea1eSGunnar Rangoy 3592439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Check if the PHY is up to snuff... */ 3602439e4bfSJean-Christophe PLAGNIOL-VILLARD phy_id = macb_mdio_read(macb, MII_PHYSID1); 3612439e4bfSJean-Christophe PLAGNIOL-VILLARD if (phy_id == 0xffff) { 3622439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: No PHY present\n", netdev->name); 3632439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 3642439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3652439e4bfSJean-Christophe PLAGNIOL-VILLARD 3662439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 3672439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(status & BMSR_LSTATUS)) { 3682439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Try to re-negotiate if we don't have link already. */ 3692439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_phy_reset(macb); 3702439e4bfSJean-Christophe PLAGNIOL-VILLARD 3716d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) { 3722439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 3732439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_LSTATUS) 3742439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 3752439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(100); 3762439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3772439e4bfSJean-Christophe PLAGNIOL-VILLARD } 3782439e4bfSJean-Christophe PLAGNIOL-VILLARD 3792439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(status & BMSR_LSTATUS)) { 3802439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: link down (status: 0x%04x)\n", 3812439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->name, status); 3822439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 3832439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 3842439e4bfSJean-Christophe PLAGNIOL-VILLARD adv = macb_mdio_read(macb, MII_ADVERTISE); 3852439e4bfSJean-Christophe PLAGNIOL-VILLARD lpa = macb_mdio_read(macb, MII_LPA); 3862439e4bfSJean-Christophe PLAGNIOL-VILLARD media = mii_nway_result(lpa & adv); 3872439e4bfSJean-Christophe PLAGNIOL-VILLARD speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) 3882439e4bfSJean-Christophe PLAGNIOL-VILLARD ? 1 : 0); 3892439e4bfSJean-Christophe PLAGNIOL-VILLARD duplex = (media & ADVERTISE_FULL) ? 1 : 0; 3902439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", 3912439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->name, 3922439e4bfSJean-Christophe PLAGNIOL-VILLARD speed ? "100" : "10", 3932439e4bfSJean-Christophe PLAGNIOL-VILLARD duplex ? "full" : "half", 3942439e4bfSJean-Christophe PLAGNIOL-VILLARD lpa); 3952439e4bfSJean-Christophe PLAGNIOL-VILLARD 3962439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = macb_readl(macb, NCFGR); 3972439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); 3982439e4bfSJean-Christophe PLAGNIOL-VILLARD if (speed) 3992439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr |= MACB_BIT(SPD); 4002439e4bfSJean-Christophe PLAGNIOL-VILLARD if (duplex) 4012439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr |= MACB_BIT(FD); 4022439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCFGR, ncfgr); 4032439e4bfSJean-Christophe PLAGNIOL-VILLARD return 1; 4042439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4052439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4062439e4bfSJean-Christophe PLAGNIOL-VILLARD 4072439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_init(struct eth_device *netdev, bd_t *bd) 4082439e4bfSJean-Christophe PLAGNIOL-VILLARD { 4092439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb = to_macb(netdev); 4102439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long paddr; 4112439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 hwaddr_bottom; 4122439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 hwaddr_top; 4132439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 4142439e4bfSJean-Christophe PLAGNIOL-VILLARD 4152439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 4162439e4bfSJean-Christophe PLAGNIOL-VILLARD * macb_halt should have been called at some point before now, 4172439e4bfSJean-Christophe PLAGNIOL-VILLARD * so we'll assume the controller is idle. 4182439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 4192439e4bfSJean-Christophe PLAGNIOL-VILLARD 4202439e4bfSJean-Christophe PLAGNIOL-VILLARD /* initialize DMA descriptors */ 4212439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr = macb->rx_buffer_dma; 4226d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MACB_RX_RING_SIZE; i++) { 4236d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (i == (CONFIG_SYS_MACB_RX_RING_SIZE - 1)) 4242439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr |= RXADDR_WRAP; 4252439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr = paddr; 4262439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].ctrl = 0; 4272439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr += 128; 4282439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4296d0f6bcfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CONFIG_SYS_MACB_TX_RING_SIZE; i++) { 4302439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].addr = 0; 4316d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (i == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) 4322439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP; 4332439e4bfSJean-Christophe PLAGNIOL-VILLARD else 4342439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].ctrl = TXBUF_USED; 4352439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4362439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_tail = macb->tx_head = macb->tx_tail = 0; 4372439e4bfSJean-Christophe PLAGNIOL-VILLARD 4382439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, RBQP, macb->rx_ring_dma); 4392439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, TBQP, macb->tx_ring_dma); 4402439e4bfSJean-Christophe PLAGNIOL-VILLARD 4412439e4bfSJean-Christophe PLAGNIOL-VILLARD /* set hardware address */ 4422439e4bfSJean-Christophe PLAGNIOL-VILLARD hwaddr_bottom = cpu_to_le32(*((u32 *)netdev->enetaddr)); 4432439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, SA1B, hwaddr_bottom); 4442439e4bfSJean-Christophe PLAGNIOL-VILLARD hwaddr_top = cpu_to_le16(*((u16 *)(netdev->enetaddr + 4))); 4452439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, SA1T, hwaddr_top); 4462439e4bfSJean-Christophe PLAGNIOL-VILLARD 4472439e4bfSJean-Christophe PLAGNIOL-VILLARD /* choose RMII or MII mode. This depends on the board */ 4482439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_RMII 4498e429b3eSStelian Pop #if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \ 4508e429b3eSStelian Pop defined(CONFIG_AT91SAM9263) 4517263ef19SStelian Pop macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN)); 4527263ef19SStelian Pop #else 4532439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, USRIO, 0); 4547263ef19SStelian Pop #endif 4557263ef19SStelian Pop #else 4568e429b3eSStelian Pop #if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \ 4578e429b3eSStelian Pop defined(CONFIG_AT91SAM9263) 4587263ef19SStelian Pop macb_writel(macb, USRIO, MACB_BIT(CLKEN)); 4592439e4bfSJean-Christophe PLAGNIOL-VILLARD #else 4602439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, USRIO, MACB_BIT(MII)); 4612439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 4627263ef19SStelian Pop #endif /* CONFIG_RMII */ 4632439e4bfSJean-Christophe PLAGNIOL-VILLARD 4642439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!macb_phy_init(macb)) 465422b1a01SBen Warren return -1; 4662439e4bfSJean-Christophe PLAGNIOL-VILLARD 4672439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Enable TX and RX */ 4682439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE)); 4692439e4bfSJean-Christophe PLAGNIOL-VILLARD 470422b1a01SBen Warren return 0; 4712439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4722439e4bfSJean-Christophe PLAGNIOL-VILLARD 4732439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_halt(struct eth_device *netdev) 4742439e4bfSJean-Christophe PLAGNIOL-VILLARD { 4752439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb = to_macb(netdev); 4762439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncr, tsr; 4772439e4bfSJean-Christophe PLAGNIOL-VILLARD 4782439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Halt the controller and wait for any ongoing transmission to end. */ 4792439e4bfSJean-Christophe PLAGNIOL-VILLARD ncr = macb_readl(macb, NCR); 4802439e4bfSJean-Christophe PLAGNIOL-VILLARD ncr |= MACB_BIT(THALT); 4812439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, ncr); 4822439e4bfSJean-Christophe PLAGNIOL-VILLARD 4832439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 4842439e4bfSJean-Christophe PLAGNIOL-VILLARD tsr = macb_readl(macb, TSR); 4852439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (tsr & MACB_BIT(TGO)); 4862439e4bfSJean-Christophe PLAGNIOL-VILLARD 4872439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Disable TX and RX, and clear statistics */ 4882439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(CLRSTAT)); 4892439e4bfSJean-Christophe PLAGNIOL-VILLARD } 4902439e4bfSJean-Christophe PLAGNIOL-VILLARD 4912439e4bfSJean-Christophe PLAGNIOL-VILLARD int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) 4922439e4bfSJean-Christophe PLAGNIOL-VILLARD { 4932439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb; 4942439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device *netdev; 4952439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long macb_hz; 4962439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncfgr; 4972439e4bfSJean-Christophe PLAGNIOL-VILLARD 4982439e4bfSJean-Christophe PLAGNIOL-VILLARD macb = malloc(sizeof(struct macb_device)); 4992439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!macb) { 5002439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("Error: Failed to allocate memory for MACB%d\n", id); 5012439e4bfSJean-Christophe PLAGNIOL-VILLARD return -1; 5022439e4bfSJean-Christophe PLAGNIOL-VILLARD } 5032439e4bfSJean-Christophe PLAGNIOL-VILLARD memset(macb, 0, sizeof(struct macb_device)); 5042439e4bfSJean-Christophe PLAGNIOL-VILLARD 5052439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev = &macb->netdev; 5062439e4bfSJean-Christophe PLAGNIOL-VILLARD 5076d0f6bcfSJean-Christophe PLAGNIOL-VILLARD macb->rx_buffer = dma_alloc_coherent(CONFIG_SYS_MACB_RX_BUFFER_SIZE, 5082439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->rx_buffer_dma); 5096d0f6bcfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_RX_RING_SIZE 5102439e4bfSJean-Christophe PLAGNIOL-VILLARD * sizeof(struct macb_dma_desc), 5112439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->rx_ring_dma); 5126d0f6bcfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_TX_RING_SIZE 5132439e4bfSJean-Christophe PLAGNIOL-VILLARD * sizeof(struct macb_dma_desc), 5142439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->tx_ring_dma); 5152439e4bfSJean-Christophe PLAGNIOL-VILLARD 5162439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->regs = regs; 5172439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->phy_addr = phy_addr; 5182439e4bfSJean-Christophe PLAGNIOL-VILLARD 5192439e4bfSJean-Christophe PLAGNIOL-VILLARD sprintf(netdev->name, "macb%d", id); 5202439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->init = macb_init; 5212439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->halt = macb_halt; 5222439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->send = macb_send; 5232439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->recv = macb_recv; 5242439e4bfSJean-Christophe PLAGNIOL-VILLARD 5252439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 5262439e4bfSJean-Christophe PLAGNIOL-VILLARD * Do some basic initialization so that we at least can talk 5272439e4bfSJean-Christophe PLAGNIOL-VILLARD * to the PHY 5282439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 5292439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_hz = get_macb_pclk_rate(id); 5302439e4bfSJean-Christophe PLAGNIOL-VILLARD if (macb_hz < 20000000) 5312439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = MACB_BF(CLK, MACB_CLK_DIV8); 5322439e4bfSJean-Christophe PLAGNIOL-VILLARD else if (macb_hz < 40000000) 5332439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = MACB_BF(CLK, MACB_CLK_DIV16); 5342439e4bfSJean-Christophe PLAGNIOL-VILLARD else if (macb_hz < 80000000) 5352439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = MACB_BF(CLK, MACB_CLK_DIV32); 5362439e4bfSJean-Christophe PLAGNIOL-VILLARD else 5372439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = MACB_BF(CLK, MACB_CLK_DIV64); 5382439e4bfSJean-Christophe PLAGNIOL-VILLARD 5392439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCFGR, ncfgr); 5402439e4bfSJean-Christophe PLAGNIOL-VILLARD 5412439e4bfSJean-Christophe PLAGNIOL-VILLARD eth_register(netdev); 5422439e4bfSJean-Christophe PLAGNIOL-VILLARD 5432439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 5442439e4bfSJean-Christophe PLAGNIOL-VILLARD } 5452439e4bfSJean-Christophe PLAGNIOL-VILLARD 5462439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 5472439e4bfSJean-Christophe PLAGNIOL-VILLARD 5482439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_MII) 5492439e4bfSJean-Christophe PLAGNIOL-VILLARD 5502439e4bfSJean-Christophe PLAGNIOL-VILLARD int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value) 5512439e4bfSJean-Christophe PLAGNIOL-VILLARD { 5522439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 5532439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 5542439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 5552439e4bfSJean-Christophe PLAGNIOL-VILLARD int iflag; 5562439e4bfSJean-Christophe PLAGNIOL-VILLARD 5572439e4bfSJean-Christophe PLAGNIOL-VILLARD iflag = disable_interrupts(); 5582439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(&macb, EMACB_NCR); 5592439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 5602439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_NCR, netctl); 5612439e4bfSJean-Christophe PLAGNIOL-VILLARD if (iflag) 5622439e4bfSJean-Christophe PLAGNIOL-VILLARD enable_interrupts(); 5632439e4bfSJean-Christophe PLAGNIOL-VILLARD 5642439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 5652439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 2) 5662439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, addr) 5672439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 5682439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2)); 5692439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_MAN, frame); 5702439e4bfSJean-Christophe PLAGNIOL-VILLARD 5712439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 5722439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(&macb, EMACB_NSR); 5732439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 5742439e4bfSJean-Christophe PLAGNIOL-VILLARD 5752439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = macb_readl(&macb, EMACB_MAN); 5762439e4bfSJean-Christophe PLAGNIOL-VILLARD *value = MACB_BFEXT(DATA, frame); 5772439e4bfSJean-Christophe PLAGNIOL-VILLARD 5782439e4bfSJean-Christophe PLAGNIOL-VILLARD iflag = disable_interrupts(); 5792439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(&macb, EMACB_NCR); 5802439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 5812439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_NCR, netctl); 5822439e4bfSJean-Christophe PLAGNIOL-VILLARD if (iflag) 5832439e4bfSJean-Christophe PLAGNIOL-VILLARD enable_interrupts(); 5842439e4bfSJean-Christophe PLAGNIOL-VILLARD 5852439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 5862439e4bfSJean-Christophe PLAGNIOL-VILLARD } 5872439e4bfSJean-Christophe PLAGNIOL-VILLARD 5882439e4bfSJean-Christophe PLAGNIOL-VILLARD int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value) 5892439e4bfSJean-Christophe PLAGNIOL-VILLARD { 5902439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 5912439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 5922439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 5932439e4bfSJean-Christophe PLAGNIOL-VILLARD int iflag; 5942439e4bfSJean-Christophe PLAGNIOL-VILLARD 5952439e4bfSJean-Christophe PLAGNIOL-VILLARD iflag = disable_interrupts(); 5962439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(&macb, EMACB_NCR); 5972439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 5982439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_NCR, netctl); 5992439e4bfSJean-Christophe PLAGNIOL-VILLARD if (iflag) 6002439e4bfSJean-Christophe PLAGNIOL-VILLARD enable_interrupts(); 6012439e4bfSJean-Christophe PLAGNIOL-VILLARD 6022439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 6032439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 1) 6042439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, addr) 6052439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 6062439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2) 6072439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(DATA, value)); 6082439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_MAN, frame); 6092439e4bfSJean-Christophe PLAGNIOL-VILLARD 6102439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 6112439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(&macb, EMACB_NSR); 6122439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 6132439e4bfSJean-Christophe PLAGNIOL-VILLARD 6142439e4bfSJean-Christophe PLAGNIOL-VILLARD iflag = disable_interrupts(); 6152439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(&macb, EMACB_NCR); 6162439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 6172439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_NCR, netctl); 6182439e4bfSJean-Christophe PLAGNIOL-VILLARD if (iflag) 6192439e4bfSJean-Christophe PLAGNIOL-VILLARD enable_interrupts(); 6202439e4bfSJean-Christophe PLAGNIOL-VILLARD 6212439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 6222439e4bfSJean-Christophe PLAGNIOL-VILLARD } 6232439e4bfSJean-Christophe PLAGNIOL-VILLARD 6242439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 625