1*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 2*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2005-2006 Atmel Corporation 3*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * 4*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or modify 5*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * it under the terms of the GNU General Public License as published by 6*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * the Free Software Foundation; either version 2 of the License, or 7*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * (at your option) any later version. 8*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * 9*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 10*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 13*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * 14*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 15*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 16*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17*2439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 18*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <common.h> 19*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 20*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_MACB) \ 21*2439e4bfSJean-Christophe PLAGNIOL-VILLARD && (defined(CONFIG_CMD_NET) || defined(CONFIG_CMD_MII)) 22*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 23*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 24*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * The u-boot networking stack is a little weird. It seems like the 25*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * networking core allocates receive buffers up front without any 26*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * regard to the hardware that's supposed to actually receive those 27*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * packets. 28*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * 29*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * The MACB receives packets into 128-byte receive buffers, so the 30*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * buffers allocated by the core isn't very practical to use. We'll 31*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * allocate our own, but we need one such buffer in case a packet 32*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * wraps around the DMA ring so that we have to copy it. 33*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * 34*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * Therefore, define CFG_RX_ETH_BUFFER to 1 in the board-specific 35*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * configuration header. This way, the core allocates one RX buffer 36*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * and one TX buffer, each of which can hold a ethernet packet of 37*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * maximum size. 38*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * 39*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * For some reason, the networking core unconditionally specifies a 40*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * 32-byte packet "alignment" (which really should be called 41*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * "padding"). MACB shouldn't need that, but we'll refrain from any 42*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * core modifications here... 43*2439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 44*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 45*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <net.h> 46*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <malloc.h> 47*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 48*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <linux/mii.h> 49*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/io.h> 50*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/dma-mapping.h> 51*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/clk.h> 52*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 53*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #include "macb.h" 54*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 55*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define barrier() asm volatile("" ::: "memory") 56*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 57*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_RX_BUFFER_SIZE 4096 58*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_RX_RING_SIZE (CFG_MACB_RX_BUFFER_SIZE / 128) 59*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_TX_RING_SIZE 16 60*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_TX_TIMEOUT 1000 61*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define CFG_MACB_AUTONEG_TIMEOUT 5000000 62*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 63*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc { 64*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 addr; 65*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ctrl; 66*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }; 67*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 68*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_USED 0x00000001 69*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXADDR_WRAP 0x00000002 70*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 71*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRMLEN_MASK 0x00000fff 72*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_START 0x00004000 73*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_FRAME_END 0x00008000 74*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_TYPEID_MATCH 0x00400000 75*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR4_MATCH 0x00800000 76*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR3_MATCH 0x01000000 77*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR2_MATCH 0x02000000 78*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_ADDR1_MATCH 0x04000000 79*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define RXBUF_BROADCAST 0x80000000 80*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 81*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRMLEN_MASK 0x000007ff 82*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_FRAME_END 0x00008000 83*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_NOCRC 0x00010000 84*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_EXHAUSTED 0x08000000 85*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_UNDERRUN 0x10000000 86*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_MAXRETRY 0x20000000 87*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_WRAP 0x40000000 88*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define TXBUF_USED 0x80000000 89*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 90*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device { 91*2439e4bfSJean-Christophe PLAGNIOL-VILLARD void *regs; 92*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 93*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int rx_tail; 94*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_head; 95*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_tail; 96*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 97*2439e4bfSJean-Christophe PLAGNIOL-VILLARD void *rx_buffer; 98*2439e4bfSJean-Christophe PLAGNIOL-VILLARD void *tx_buffer; 99*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc *rx_ring; 100*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_dma_desc *tx_ring; 101*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 102*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long rx_buffer_dma; 103*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long rx_ring_dma; 104*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long tx_ring_dma; 105*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 106*2439e4bfSJean-Christophe PLAGNIOL-VILLARD const struct device *dev; 107*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device netdev; 108*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned short phy_addr; 109*2439e4bfSJean-Christophe PLAGNIOL-VILLARD }; 110*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #define to_macb(_nd) container_of(_nd, struct macb_device, netdev) 111*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 112*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) 113*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 114*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 115*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 116*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 117*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 118*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 119*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 120*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 121*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 122*2439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 123*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 1) 124*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, macb->phy_addr) 125*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 126*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2) 127*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(DATA, value)); 128*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, MAN, frame); 129*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 130*2439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 131*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(macb, NSR); 132*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 133*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 134*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 135*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 136*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 137*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 138*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 139*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static u16 macb_mdio_read(struct macb_device *macb, u8 reg) 140*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 141*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 142*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 143*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 144*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 145*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 146*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 147*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 148*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 149*2439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 150*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 2) 151*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, macb->phy_addr) 152*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 153*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2)); 154*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, MAN, frame); 155*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 156*2439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 157*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(macb, NSR); 158*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 159*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 160*2439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = macb_readl(macb, MAN); 161*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 162*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(macb, NCR); 163*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 164*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, netctl); 165*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 166*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return MACB_BFEXT(DATA, frame); 167*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 168*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 169*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_NET) 170*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 171*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_send(struct eth_device *netdev, volatile void *packet, 172*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int length) 173*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 174*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb = to_macb(netdev); 175*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long paddr, ctrl; 176*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int tx_head = macb->tx_head; 177*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 178*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 179*2439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr = dma_map_single(packet, length, DMA_TO_DEVICE); 180*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 181*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl = length & TXBUF_FRMLEN_MASK; 182*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl |= TXBUF_FRAME_END; 183*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (tx_head == (CFG_MACB_TX_RING_SIZE - 1)) { 184*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl |= TXBUF_WRAP; 185*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_head = 0; 186*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } else 187*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_head++; 188*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 189*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[tx_head].ctrl = ctrl; 190*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[tx_head].addr = paddr; 191*2439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 192*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART)); 193*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 194*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 195*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * I guess this is necessary because the networking core may 196*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * re-use the transmit buffer as soon as we return... 197*2439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 198*2439e4bfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i <= CFG_MACB_TX_TIMEOUT; i++) { 199*2439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 200*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ctrl = macb->tx_ring[tx_head].ctrl; 201*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_USED) 202*2439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 203*2439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(1); 204*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 205*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 206*2439e4bfSJean-Christophe PLAGNIOL-VILLARD dma_unmap_single(packet, length, paddr); 207*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 208*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (i <= CFG_MACB_TX_TIMEOUT) { 209*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_UNDERRUN) 210*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: TX underrun\n", netdev->name); 211*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (ctrl & TXBUF_EXHAUSTED) 212*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: TX buffers exhausted in mid frame\n", 213*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->name); 214*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 215*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: TX timeout\n", netdev->name); 216*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 217*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 218*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* No one cares anyway */ 219*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 220*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 221*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 222*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void reclaim_rx_buffers(struct macb_device *macb, 223*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int new_tail) 224*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 225*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int i; 226*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 227*2439e4bfSJean-Christophe PLAGNIOL-VILLARD i = macb->rx_tail; 228*2439e4bfSJean-Christophe PLAGNIOL-VILLARD while (i > new_tail) { 229*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr &= ~RXADDR_USED; 230*2439e4bfSJean-Christophe PLAGNIOL-VILLARD i++; 231*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (i > CFG_MACB_RX_RING_SIZE) 232*2439e4bfSJean-Christophe PLAGNIOL-VILLARD i = 0; 233*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 234*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 235*2439e4bfSJean-Christophe PLAGNIOL-VILLARD while (i < new_tail) { 236*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr &= ~RXADDR_USED; 237*2439e4bfSJean-Christophe PLAGNIOL-VILLARD i++; 238*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 239*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 240*2439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 241*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_tail = new_tail; 242*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 243*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 244*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_recv(struct eth_device *netdev) 245*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 246*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb = to_macb(netdev); 247*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int rx_tail = macb->rx_tail; 248*2439e4bfSJean-Christophe PLAGNIOL-VILLARD void *buffer; 249*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int length; 250*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int wrapped = 0; 251*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 status; 252*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 253*2439e4bfSJean-Christophe PLAGNIOL-VILLARD for (;;) { 254*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED)) 255*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return -1; 256*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 257*2439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb->rx_ring[rx_tail].ctrl; 258*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & RXBUF_FRAME_START) { 259*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (rx_tail != macb->rx_tail) 260*2439e4bfSJean-Christophe PLAGNIOL-VILLARD reclaim_rx_buffers(macb, rx_tail); 261*2439e4bfSJean-Christophe PLAGNIOL-VILLARD wrapped = 0; 262*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 263*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 264*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & RXBUF_FRAME_END) { 265*2439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer = macb->rx_buffer + 128 * macb->rx_tail; 266*2439e4bfSJean-Christophe PLAGNIOL-VILLARD length = status & RXBUF_FRMLEN_MASK; 267*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (wrapped) { 268*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned int headlen, taillen; 269*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 270*2439e4bfSJean-Christophe PLAGNIOL-VILLARD headlen = 128 * (CFG_MACB_RX_RING_SIZE 271*2439e4bfSJean-Christophe PLAGNIOL-VILLARD - macb->rx_tail); 272*2439e4bfSJean-Christophe PLAGNIOL-VILLARD taillen = length - headlen; 273*2439e4bfSJean-Christophe PLAGNIOL-VILLARD memcpy((void *)NetRxPackets[0], 274*2439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer, headlen); 275*2439e4bfSJean-Christophe PLAGNIOL-VILLARD memcpy((void *)NetRxPackets[0] + headlen, 276*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_buffer, taillen); 277*2439e4bfSJean-Christophe PLAGNIOL-VILLARD buffer = (void *)NetRxPackets[0]; 278*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 279*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 280*2439e4bfSJean-Christophe PLAGNIOL-VILLARD NetReceive(buffer, length); 281*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (++rx_tail >= CFG_MACB_RX_RING_SIZE) 282*2439e4bfSJean-Christophe PLAGNIOL-VILLARD rx_tail = 0; 283*2439e4bfSJean-Christophe PLAGNIOL-VILLARD reclaim_rx_buffers(macb, rx_tail); 284*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 285*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (++rx_tail >= CFG_MACB_RX_RING_SIZE) { 286*2439e4bfSJean-Christophe PLAGNIOL-VILLARD wrapped = 1; 287*2439e4bfSJean-Christophe PLAGNIOL-VILLARD rx_tail = 0; 288*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 289*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 290*2439e4bfSJean-Christophe PLAGNIOL-VILLARD barrier(); 291*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 292*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 293*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 294*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 295*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 296*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_phy_reset(struct macb_device *macb) 297*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 298*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device *netdev = &macb->netdev; 299*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 300*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 status, adv; 301*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 302*2439e4bfSJean-Christophe PLAGNIOL-VILLARD adv = ADVERTISE_CSMA | ADVERTISE_ALL; 303*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_mdio_write(macb, MII_ADVERTISE, adv); 304*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: Starting autonegotiation...\n", netdev->name); 305*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE 306*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | BMCR_ANRESTART)); 307*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 308*2439e4bfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) { 309*2439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 310*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_ANEGCOMPLETE) 311*2439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 312*2439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(100); 313*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 314*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 315*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_ANEGCOMPLETE) 316*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: Autonegotiation complete\n", netdev->name); 317*2439e4bfSJean-Christophe PLAGNIOL-VILLARD else 318*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: Autonegotiation timed out (status=0x%04x)\n", 319*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->name, status); 320*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 321*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 322*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_phy_init(struct macb_device *macb) 323*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 324*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device *netdev = &macb->netdev; 325*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncfgr; 326*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 phy_id, status, adv, lpa; 327*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int media, speed, duplex; 328*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 329*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 330*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Check if the PHY is up to snuff... */ 331*2439e4bfSJean-Christophe PLAGNIOL-VILLARD phy_id = macb_mdio_read(macb, MII_PHYSID1); 332*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (phy_id == 0xffff) { 333*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: No PHY present\n", netdev->name); 334*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 335*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 336*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 337*2439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 338*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(status & BMSR_LSTATUS)) { 339*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Try to re-negotiate if we don't have link already. */ 340*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_phy_reset(macb); 341*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 342*2439e4bfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MACB_AUTONEG_TIMEOUT / 100; i++) { 343*2439e4bfSJean-Christophe PLAGNIOL-VILLARD status = macb_mdio_read(macb, MII_BMSR); 344*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (status & BMSR_LSTATUS) 345*2439e4bfSJean-Christophe PLAGNIOL-VILLARD break; 346*2439e4bfSJean-Christophe PLAGNIOL-VILLARD udelay(100); 347*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 348*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 349*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 350*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!(status & BMSR_LSTATUS)) { 351*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: link down (status: 0x%04x)\n", 352*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->name, status); 353*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 354*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } else { 355*2439e4bfSJean-Christophe PLAGNIOL-VILLARD adv = macb_mdio_read(macb, MII_ADVERTISE); 356*2439e4bfSJean-Christophe PLAGNIOL-VILLARD lpa = macb_mdio_read(macb, MII_LPA); 357*2439e4bfSJean-Christophe PLAGNIOL-VILLARD media = mii_nway_result(lpa & adv); 358*2439e4bfSJean-Christophe PLAGNIOL-VILLARD speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) 359*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ? 1 : 0); 360*2439e4bfSJean-Christophe PLAGNIOL-VILLARD duplex = (media & ADVERTISE_FULL) ? 1 : 0; 361*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", 362*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->name, 363*2439e4bfSJean-Christophe PLAGNIOL-VILLARD speed ? "100" : "10", 364*2439e4bfSJean-Christophe PLAGNIOL-VILLARD duplex ? "full" : "half", 365*2439e4bfSJean-Christophe PLAGNIOL-VILLARD lpa); 366*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 367*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = macb_readl(macb, NCFGR); 368*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); 369*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (speed) 370*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr |= MACB_BIT(SPD); 371*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (duplex) 372*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr |= MACB_BIT(FD); 373*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCFGR, ncfgr); 374*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 1; 375*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 376*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 377*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 378*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static int macb_init(struct eth_device *netdev, bd_t *bd) 379*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 380*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb = to_macb(netdev); 381*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long paddr; 382*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 hwaddr_bottom; 383*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u16 hwaddr_top; 384*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int i; 385*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 386*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 387*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * macb_halt should have been called at some point before now, 388*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * so we'll assume the controller is idle. 389*2439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 390*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 391*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* initialize DMA descriptors */ 392*2439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr = macb->rx_buffer_dma; 393*2439e4bfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MACB_RX_RING_SIZE; i++) { 394*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (i == (CFG_MACB_RX_RING_SIZE - 1)) 395*2439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr |= RXADDR_WRAP; 396*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].addr = paddr; 397*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring[i].ctrl = 0; 398*2439e4bfSJean-Christophe PLAGNIOL-VILLARD paddr += 128; 399*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 400*2439e4bfSJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < CFG_MACB_TX_RING_SIZE; i++) { 401*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].addr = 0; 402*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (i == (CFG_MACB_TX_RING_SIZE - 1)) 403*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP; 404*2439e4bfSJean-Christophe PLAGNIOL-VILLARD else 405*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring[i].ctrl = TXBUF_USED; 406*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 407*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_tail = macb->tx_head = macb->tx_tail = 0; 408*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 409*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, RBQP, macb->rx_ring_dma); 410*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, TBQP, macb->tx_ring_dma); 411*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 412*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* set hardware address */ 413*2439e4bfSJean-Christophe PLAGNIOL-VILLARD hwaddr_bottom = cpu_to_le32(*((u32 *)netdev->enetaddr)); 414*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, SA1B, hwaddr_bottom); 415*2439e4bfSJean-Christophe PLAGNIOL-VILLARD hwaddr_top = cpu_to_le16(*((u16 *)(netdev->enetaddr + 4))); 416*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, SA1T, hwaddr_top); 417*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 418*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* choose RMII or MII mode. This depends on the board */ 419*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #ifdef CONFIG_RMII 420*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, USRIO, 0); 421*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #else 422*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, USRIO, MACB_BIT(MII)); 423*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 424*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 425*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!macb_phy_init(macb)) 426*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 427*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 428*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Enable TX and RX */ 429*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE)); 430*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 431*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 1; 432*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 433*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 434*2439e4bfSJean-Christophe PLAGNIOL-VILLARD static void macb_halt(struct eth_device *netdev) 435*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 436*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb = to_macb(netdev); 437*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncr, tsr; 438*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 439*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Halt the controller and wait for any ongoing transmission to end. */ 440*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncr = macb_readl(macb, NCR); 441*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncr |= MACB_BIT(THALT); 442*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, ncr); 443*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 444*2439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 445*2439e4bfSJean-Christophe PLAGNIOL-VILLARD tsr = macb_readl(macb, TSR); 446*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (tsr & MACB_BIT(TGO)); 447*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 448*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* Disable TX and RX, and clear statistics */ 449*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCR, MACB_BIT(CLRSTAT)); 450*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 451*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 452*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) 453*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 454*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct macb_device *macb; 455*2439e4bfSJean-Christophe PLAGNIOL-VILLARD struct eth_device *netdev; 456*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long macb_hz; 457*2439e4bfSJean-Christophe PLAGNIOL-VILLARD u32 ncfgr; 458*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 459*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb = malloc(sizeof(struct macb_device)); 460*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (!macb) { 461*2439e4bfSJean-Christophe PLAGNIOL-VILLARD printf("Error: Failed to allocate memory for MACB%d\n", id); 462*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return -1; 463*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 464*2439e4bfSJean-Christophe PLAGNIOL-VILLARD memset(macb, 0, sizeof(struct macb_device)); 465*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 466*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev = &macb->netdev; 467*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 468*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_buffer = dma_alloc_coherent(CFG_MACB_RX_BUFFER_SIZE, 469*2439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->rx_buffer_dma); 470*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->rx_ring = dma_alloc_coherent(CFG_MACB_RX_RING_SIZE 471*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * sizeof(struct macb_dma_desc), 472*2439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->rx_ring_dma); 473*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->tx_ring = dma_alloc_coherent(CFG_MACB_TX_RING_SIZE 474*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * sizeof(struct macb_dma_desc), 475*2439e4bfSJean-Christophe PLAGNIOL-VILLARD &macb->tx_ring_dma); 476*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 477*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->regs = regs; 478*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb->phy_addr = phy_addr; 479*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 480*2439e4bfSJean-Christophe PLAGNIOL-VILLARD sprintf(netdev->name, "macb%d", id); 481*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->init = macb_init; 482*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->halt = macb_halt; 483*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->send = macb_send; 484*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netdev->recv = macb_recv; 485*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 486*2439e4bfSJean-Christophe PLAGNIOL-VILLARD /* 487*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * Do some basic initialization so that we at least can talk 488*2439e4bfSJean-Christophe PLAGNIOL-VILLARD * to the PHY 489*2439e4bfSJean-Christophe PLAGNIOL-VILLARD */ 490*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_hz = get_macb_pclk_rate(id); 491*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (macb_hz < 20000000) 492*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = MACB_BF(CLK, MACB_CLK_DIV8); 493*2439e4bfSJean-Christophe PLAGNIOL-VILLARD else if (macb_hz < 40000000) 494*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = MACB_BF(CLK, MACB_CLK_DIV16); 495*2439e4bfSJean-Christophe PLAGNIOL-VILLARD else if (macb_hz < 80000000) 496*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = MACB_BF(CLK, MACB_CLK_DIV32); 497*2439e4bfSJean-Christophe PLAGNIOL-VILLARD else 498*2439e4bfSJean-Christophe PLAGNIOL-VILLARD ncfgr = MACB_BF(CLK, MACB_CLK_DIV64); 499*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 500*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(macb, NCFGR, ncfgr); 501*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 502*2439e4bfSJean-Christophe PLAGNIOL-VILLARD eth_register(netdev); 503*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 504*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 505*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 506*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 507*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 508*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 509*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_MII) 510*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 511*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value) 512*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 513*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 514*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 515*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 516*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int iflag; 517*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 518*2439e4bfSJean-Christophe PLAGNIOL-VILLARD iflag = disable_interrupts(); 519*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(&macb, EMACB_NCR); 520*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 521*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_NCR, netctl); 522*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (iflag) 523*2439e4bfSJean-Christophe PLAGNIOL-VILLARD enable_interrupts(); 524*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 525*2439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 526*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 2) 527*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, addr) 528*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 529*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2)); 530*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_MAN, frame); 531*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 532*2439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 533*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(&macb, EMACB_NSR); 534*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 535*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 536*2439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = macb_readl(&macb, EMACB_MAN); 537*2439e4bfSJean-Christophe PLAGNIOL-VILLARD *value = MACB_BFEXT(DATA, frame); 538*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 539*2439e4bfSJean-Christophe PLAGNIOL-VILLARD iflag = disable_interrupts(); 540*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(&macb, EMACB_NCR); 541*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 542*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_NCR, netctl); 543*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (iflag) 544*2439e4bfSJean-Christophe PLAGNIOL-VILLARD enable_interrupts(); 545*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 546*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 547*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 548*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 549*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value) 550*2439e4bfSJean-Christophe PLAGNIOL-VILLARD { 551*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netctl; 552*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long netstat; 553*2439e4bfSJean-Christophe PLAGNIOL-VILLARD unsigned long frame; 554*2439e4bfSJean-Christophe PLAGNIOL-VILLARD int iflag; 555*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 556*2439e4bfSJean-Christophe PLAGNIOL-VILLARD iflag = disable_interrupts(); 557*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(&macb, EMACB_NCR); 558*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl |= MACB_BIT(MPE); 559*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_NCR, netctl); 560*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (iflag) 561*2439e4bfSJean-Christophe PLAGNIOL-VILLARD enable_interrupts(); 562*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 563*2439e4bfSJean-Christophe PLAGNIOL-VILLARD frame = (MACB_BF(SOF, 1) 564*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(RW, 1) 565*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(PHYA, addr) 566*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(REGA, reg) 567*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(CODE, 2) 568*2439e4bfSJean-Christophe PLAGNIOL-VILLARD | MACB_BF(DATA, value)); 569*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_MAN, frame); 570*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 571*2439e4bfSJean-Christophe PLAGNIOL-VILLARD do { 572*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netstat = macb_readl(&macb, EMACB_NSR); 573*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } while (!(netstat & MACB_BIT(IDLE))); 574*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 575*2439e4bfSJean-Christophe PLAGNIOL-VILLARD iflag = disable_interrupts(); 576*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl = macb_readl(&macb, EMACB_NCR); 577*2439e4bfSJean-Christophe PLAGNIOL-VILLARD netctl &= ~MACB_BIT(MPE); 578*2439e4bfSJean-Christophe PLAGNIOL-VILLARD macb_writel(&macb, EMACB_NCR, netctl); 579*2439e4bfSJean-Christophe PLAGNIOL-VILLARD if (iflag) 580*2439e4bfSJean-Christophe PLAGNIOL-VILLARD enable_interrupts(); 581*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 582*2439e4bfSJean-Christophe PLAGNIOL-VILLARD return 0; 583*2439e4bfSJean-Christophe PLAGNIOL-VILLARD } 584*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 585*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif 586*2439e4bfSJean-Christophe PLAGNIOL-VILLARD 587*2439e4bfSJean-Christophe PLAGNIOL-VILLARD #endif /* CONFIG_MACB */ 588