1*f6569884SThomas Chou /* 2*f6569884SThomas Chou * Opencore 10/100 ethernet mac driver 3*f6569884SThomas Chou * 4*f6569884SThomas Chou * Copyright (C) 2007-2008 Avionic Design Development GmbH 5*f6569884SThomas Chou * Copyright (C) 2008-2009 Avionic Design GmbH 6*f6569884SThomas Chou * Thierry Reding <thierry.reding@avionic-design.de> 7*f6569884SThomas Chou * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> 8*f6569884SThomas Chou * 9*f6569884SThomas Chou * This program is free software; you can redistribute it and/or modify 10*f6569884SThomas Chou * it under the terms of the GNU General Public License version 2 as 11*f6569884SThomas Chou * published by the Free Software Foundation. 12*f6569884SThomas Chou */ 13*f6569884SThomas Chou 14*f6569884SThomas Chou #include <common.h> 15*f6569884SThomas Chou #include <command.h> 16*f6569884SThomas Chou #include <malloc.h> 17*f6569884SThomas Chou #include <net.h> 18*f6569884SThomas Chou #include <miiphy.h> 19*f6569884SThomas Chou #include <asm/io.h> 20*f6569884SThomas Chou #include <asm/cache.h> 21*f6569884SThomas Chou 22*f6569884SThomas Chou /* register offsets */ 23*f6569884SThomas Chou #define MODER 0x00 24*f6569884SThomas Chou #define INT_SOURCE 0x04 25*f6569884SThomas Chou #define INT_MASK 0x08 26*f6569884SThomas Chou #define IPGT 0x0c 27*f6569884SThomas Chou #define IPGR1 0x10 28*f6569884SThomas Chou #define IPGR2 0x14 29*f6569884SThomas Chou #define PACKETLEN 0x18 30*f6569884SThomas Chou #define COLLCONF 0x1c 31*f6569884SThomas Chou #define TX_BD_NUM 0x20 32*f6569884SThomas Chou #define CTRLMODER 0x24 33*f6569884SThomas Chou #define MIIMODER 0x28 34*f6569884SThomas Chou #define MIICOMMAND 0x2c 35*f6569884SThomas Chou #define MIIADDRESS 0x30 36*f6569884SThomas Chou #define MIITX_DATA 0x34 37*f6569884SThomas Chou #define MIIRX_DATA 0x38 38*f6569884SThomas Chou #define MIISTATUS 0x3c 39*f6569884SThomas Chou #define MAC_ADDR0 0x40 40*f6569884SThomas Chou #define MAC_ADDR1 0x44 41*f6569884SThomas Chou #define ETH_HASH0 0x48 42*f6569884SThomas Chou #define ETH_HASH1 0x4c 43*f6569884SThomas Chou #define ETH_TXCTRL 0x50 44*f6569884SThomas Chou 45*f6569884SThomas Chou /* mode register */ 46*f6569884SThomas Chou #define MODER_RXEN (1 << 0) /* receive enable */ 47*f6569884SThomas Chou #define MODER_TXEN (1 << 1) /* transmit enable */ 48*f6569884SThomas Chou #define MODER_NOPRE (1 << 2) /* no preamble */ 49*f6569884SThomas Chou #define MODER_BRO (1 << 3) /* broadcast address */ 50*f6569884SThomas Chou #define MODER_IAM (1 << 4) /* individual address mode */ 51*f6569884SThomas Chou #define MODER_PRO (1 << 5) /* promiscuous mode */ 52*f6569884SThomas Chou #define MODER_IFG (1 << 6) /* interframe gap for incoming frames */ 53*f6569884SThomas Chou #define MODER_LOOP (1 << 7) /* loopback */ 54*f6569884SThomas Chou #define MODER_NBO (1 << 8) /* no back-off */ 55*f6569884SThomas Chou #define MODER_EDE (1 << 9) /* excess defer enable */ 56*f6569884SThomas Chou #define MODER_FULLD (1 << 10) /* full duplex */ 57*f6569884SThomas Chou #define MODER_RESET (1 << 11) /* FIXME: reset (undocumented) */ 58*f6569884SThomas Chou #define MODER_DCRC (1 << 12) /* delayed CRC enable */ 59*f6569884SThomas Chou #define MODER_CRC (1 << 13) /* CRC enable */ 60*f6569884SThomas Chou #define MODER_HUGE (1 << 14) /* huge packets enable */ 61*f6569884SThomas Chou #define MODER_PAD (1 << 15) /* padding enabled */ 62*f6569884SThomas Chou #define MODER_RSM (1 << 16) /* receive small packets */ 63*f6569884SThomas Chou 64*f6569884SThomas Chou /* interrupt source and mask registers */ 65*f6569884SThomas Chou #define INT_MASK_TXF (1 << 0) /* transmit frame */ 66*f6569884SThomas Chou #define INT_MASK_TXE (1 << 1) /* transmit error */ 67*f6569884SThomas Chou #define INT_MASK_RXF (1 << 2) /* receive frame */ 68*f6569884SThomas Chou #define INT_MASK_RXE (1 << 3) /* receive error */ 69*f6569884SThomas Chou #define INT_MASK_BUSY (1 << 4) 70*f6569884SThomas Chou #define INT_MASK_TXC (1 << 5) /* transmit control frame */ 71*f6569884SThomas Chou #define INT_MASK_RXC (1 << 6) /* receive control frame */ 72*f6569884SThomas Chou 73*f6569884SThomas Chou #define INT_MASK_TX (INT_MASK_TXF | INT_MASK_TXE) 74*f6569884SThomas Chou #define INT_MASK_RX (INT_MASK_RXF | INT_MASK_RXE) 75*f6569884SThomas Chou 76*f6569884SThomas Chou #define INT_MASK_ALL ( \ 77*f6569884SThomas Chou INT_MASK_TXF | INT_MASK_TXE | \ 78*f6569884SThomas Chou INT_MASK_RXF | INT_MASK_RXE | \ 79*f6569884SThomas Chou INT_MASK_TXC | INT_MASK_RXC | \ 80*f6569884SThomas Chou INT_MASK_BUSY \ 81*f6569884SThomas Chou ) 82*f6569884SThomas Chou 83*f6569884SThomas Chou /* packet length register */ 84*f6569884SThomas Chou #define PACKETLEN_MIN(min) (((min) & 0xffff) << 16) 85*f6569884SThomas Chou #define PACKETLEN_MAX(max) (((max) & 0xffff) << 0) 86*f6569884SThomas Chou #define PACKETLEN_MIN_MAX(min, max) (PACKETLEN_MIN(min) | \ 87*f6569884SThomas Chou PACKETLEN_MAX(max)) 88*f6569884SThomas Chou 89*f6569884SThomas Chou /* transmit buffer number register */ 90*f6569884SThomas Chou #define TX_BD_NUM_VAL(x) (((x) <= 0x80) ? (x) : 0x80) 91*f6569884SThomas Chou 92*f6569884SThomas Chou /* control module mode register */ 93*f6569884SThomas Chou #define CTRLMODER_PASSALL (1 << 0) /* pass all receive frames */ 94*f6569884SThomas Chou #define CTRLMODER_RXFLOW (1 << 1) /* receive control flow */ 95*f6569884SThomas Chou #define CTRLMODER_TXFLOW (1 << 2) /* transmit control flow */ 96*f6569884SThomas Chou 97*f6569884SThomas Chou /* MII mode register */ 98*f6569884SThomas Chou #define MIIMODER_CLKDIV(x) ((x) & 0xfe) /* needs to be an even number */ 99*f6569884SThomas Chou #define MIIMODER_NOPRE (1 << 8) /* no preamble */ 100*f6569884SThomas Chou 101*f6569884SThomas Chou /* MII command register */ 102*f6569884SThomas Chou #define MIICOMMAND_SCAN (1 << 0) /* scan status */ 103*f6569884SThomas Chou #define MIICOMMAND_READ (1 << 1) /* read status */ 104*f6569884SThomas Chou #define MIICOMMAND_WRITE (1 << 2) /* write control data */ 105*f6569884SThomas Chou 106*f6569884SThomas Chou /* MII address register */ 107*f6569884SThomas Chou #define MIIADDRESS_FIAD(x) (((x) & 0x1f) << 0) 108*f6569884SThomas Chou #define MIIADDRESS_RGAD(x) (((x) & 0x1f) << 8) 109*f6569884SThomas Chou #define MIIADDRESS_ADDR(phy, reg) (MIIADDRESS_FIAD(phy) | \ 110*f6569884SThomas Chou MIIADDRESS_RGAD(reg)) 111*f6569884SThomas Chou 112*f6569884SThomas Chou /* MII transmit data register */ 113*f6569884SThomas Chou #define MIITX_DATA_VAL(x) ((x) & 0xffff) 114*f6569884SThomas Chou 115*f6569884SThomas Chou /* MII receive data register */ 116*f6569884SThomas Chou #define MIIRX_DATA_VAL(x) ((x) & 0xffff) 117*f6569884SThomas Chou 118*f6569884SThomas Chou /* MII status register */ 119*f6569884SThomas Chou #define MIISTATUS_LINKFAIL (1 << 0) 120*f6569884SThomas Chou #define MIISTATUS_BUSY (1 << 1) 121*f6569884SThomas Chou #define MIISTATUS_INVALID (1 << 2) 122*f6569884SThomas Chou 123*f6569884SThomas Chou /* TX buffer descriptor */ 124*f6569884SThomas Chou #define TX_BD_CS (1 << 0) /* carrier sense lost */ 125*f6569884SThomas Chou #define TX_BD_DF (1 << 1) /* defer indication */ 126*f6569884SThomas Chou #define TX_BD_LC (1 << 2) /* late collision */ 127*f6569884SThomas Chou #define TX_BD_RL (1 << 3) /* retransmission limit */ 128*f6569884SThomas Chou #define TX_BD_RETRY_MASK (0x00f0) 129*f6569884SThomas Chou #define TX_BD_RETRY(x) (((x) & 0x00f0) >> 4) 130*f6569884SThomas Chou #define TX_BD_UR (1 << 8) /* transmitter underrun */ 131*f6569884SThomas Chou #define TX_BD_CRC (1 << 11) /* TX CRC enable */ 132*f6569884SThomas Chou #define TX_BD_PAD (1 << 12) /* pad enable */ 133*f6569884SThomas Chou #define TX_BD_WRAP (1 << 13) 134*f6569884SThomas Chou #define TX_BD_IRQ (1 << 14) /* interrupt request enable */ 135*f6569884SThomas Chou #define TX_BD_READY (1 << 15) /* TX buffer ready */ 136*f6569884SThomas Chou #define TX_BD_LEN(x) (((x) & 0xffff) << 16) 137*f6569884SThomas Chou #define TX_BD_LEN_MASK (0xffff << 16) 138*f6569884SThomas Chou 139*f6569884SThomas Chou #define TX_BD_STATS (TX_BD_CS | TX_BD_DF | TX_BD_LC | \ 140*f6569884SThomas Chou TX_BD_RL | TX_BD_RETRY_MASK | TX_BD_UR) 141*f6569884SThomas Chou 142*f6569884SThomas Chou /* RX buffer descriptor */ 143*f6569884SThomas Chou #define RX_BD_LC (1 << 0) /* late collision */ 144*f6569884SThomas Chou #define RX_BD_CRC (1 << 1) /* RX CRC error */ 145*f6569884SThomas Chou #define RX_BD_SF (1 << 2) /* short frame */ 146*f6569884SThomas Chou #define RX_BD_TL (1 << 3) /* too long */ 147*f6569884SThomas Chou #define RX_BD_DN (1 << 4) /* dribble nibble */ 148*f6569884SThomas Chou #define RX_BD_IS (1 << 5) /* invalid symbol */ 149*f6569884SThomas Chou #define RX_BD_OR (1 << 6) /* receiver overrun */ 150*f6569884SThomas Chou #define RX_BD_MISS (1 << 7) 151*f6569884SThomas Chou #define RX_BD_CF (1 << 8) /* control frame */ 152*f6569884SThomas Chou #define RX_BD_WRAP (1 << 13) 153*f6569884SThomas Chou #define RX_BD_IRQ (1 << 14) /* interrupt request enable */ 154*f6569884SThomas Chou #define RX_BD_EMPTY (1 << 15) 155*f6569884SThomas Chou #define RX_BD_LEN(x) (((x) & 0xffff) << 16) 156*f6569884SThomas Chou 157*f6569884SThomas Chou #define RX_BD_STATS (RX_BD_LC | RX_BD_CRC | RX_BD_SF | RX_BD_TL | \ 158*f6569884SThomas Chou RX_BD_DN | RX_BD_IS | RX_BD_OR | RX_BD_MISS) 159*f6569884SThomas Chou 160*f6569884SThomas Chou #define ETHOC_BUFSIZ 1536 161*f6569884SThomas Chou #define ETHOC_ZLEN 64 162*f6569884SThomas Chou #define ETHOC_BD_BASE 0x400 163*f6569884SThomas Chou #define ETHOC_TIMEOUT (HZ / 2) 164*f6569884SThomas Chou #define ETHOC_MII_TIMEOUT (1 + (HZ / 5)) 165*f6569884SThomas Chou 166*f6569884SThomas Chou /** 167*f6569884SThomas Chou * struct ethoc - driver-private device structure 168*f6569884SThomas Chou * @num_tx: number of send buffers 169*f6569884SThomas Chou * @cur_tx: last send buffer written 170*f6569884SThomas Chou * @dty_tx: last buffer actually sent 171*f6569884SThomas Chou * @num_rx: number of receive buffers 172*f6569884SThomas Chou * @cur_rx: current receive buffer 173*f6569884SThomas Chou */ 174*f6569884SThomas Chou struct ethoc { 175*f6569884SThomas Chou u32 num_tx; 176*f6569884SThomas Chou u32 cur_tx; 177*f6569884SThomas Chou u32 dty_tx; 178*f6569884SThomas Chou u32 num_rx; 179*f6569884SThomas Chou u32 cur_rx; 180*f6569884SThomas Chou }; 181*f6569884SThomas Chou 182*f6569884SThomas Chou /** 183*f6569884SThomas Chou * struct ethoc_bd - buffer descriptor 184*f6569884SThomas Chou * @stat: buffer statistics 185*f6569884SThomas Chou * @addr: physical memory address 186*f6569884SThomas Chou */ 187*f6569884SThomas Chou struct ethoc_bd { 188*f6569884SThomas Chou u32 stat; 189*f6569884SThomas Chou u32 addr; 190*f6569884SThomas Chou }; 191*f6569884SThomas Chou 192*f6569884SThomas Chou static inline u32 ethoc_read(struct eth_device *dev, loff_t offset) 193*f6569884SThomas Chou { 194*f6569884SThomas Chou return readl(dev->iobase + offset); 195*f6569884SThomas Chou } 196*f6569884SThomas Chou 197*f6569884SThomas Chou static inline void ethoc_write(struct eth_device *dev, loff_t offset, u32 data) 198*f6569884SThomas Chou { 199*f6569884SThomas Chou writel(data, dev->iobase + offset); 200*f6569884SThomas Chou } 201*f6569884SThomas Chou 202*f6569884SThomas Chou static inline void ethoc_read_bd(struct eth_device *dev, int index, 203*f6569884SThomas Chou struct ethoc_bd *bd) 204*f6569884SThomas Chou { 205*f6569884SThomas Chou loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd)); 206*f6569884SThomas Chou bd->stat = ethoc_read(dev, offset + 0); 207*f6569884SThomas Chou bd->addr = ethoc_read(dev, offset + 4); 208*f6569884SThomas Chou } 209*f6569884SThomas Chou 210*f6569884SThomas Chou static inline void ethoc_write_bd(struct eth_device *dev, int index, 211*f6569884SThomas Chou const struct ethoc_bd *bd) 212*f6569884SThomas Chou { 213*f6569884SThomas Chou loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd)); 214*f6569884SThomas Chou ethoc_write(dev, offset + 0, bd->stat); 215*f6569884SThomas Chou ethoc_write(dev, offset + 4, bd->addr); 216*f6569884SThomas Chou } 217*f6569884SThomas Chou 218*f6569884SThomas Chou static inline void ethoc_set_mac_address(struct eth_device *dev) 219*f6569884SThomas Chou { 220*f6569884SThomas Chou u8 *mac = dev->enetaddr; 221*f6569884SThomas Chou 222*f6569884SThomas Chou ethoc_write(dev, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) | 223*f6569884SThomas Chou (mac[4] << 8) | (mac[5] << 0)); 224*f6569884SThomas Chou ethoc_write(dev, MAC_ADDR1, (mac[0] << 8) | (mac[1] << 0)); 225*f6569884SThomas Chou } 226*f6569884SThomas Chou 227*f6569884SThomas Chou static inline void ethoc_ack_irq(struct eth_device *dev, u32 mask) 228*f6569884SThomas Chou { 229*f6569884SThomas Chou ethoc_write(dev, INT_SOURCE, mask); 230*f6569884SThomas Chou } 231*f6569884SThomas Chou 232*f6569884SThomas Chou static inline void ethoc_enable_rx_and_tx(struct eth_device *dev) 233*f6569884SThomas Chou { 234*f6569884SThomas Chou u32 mode = ethoc_read(dev, MODER); 235*f6569884SThomas Chou mode |= MODER_RXEN | MODER_TXEN; 236*f6569884SThomas Chou ethoc_write(dev, MODER, mode); 237*f6569884SThomas Chou } 238*f6569884SThomas Chou 239*f6569884SThomas Chou static inline void ethoc_disable_rx_and_tx(struct eth_device *dev) 240*f6569884SThomas Chou { 241*f6569884SThomas Chou u32 mode = ethoc_read(dev, MODER); 242*f6569884SThomas Chou mode &= ~(MODER_RXEN | MODER_TXEN); 243*f6569884SThomas Chou ethoc_write(dev, MODER, mode); 244*f6569884SThomas Chou } 245*f6569884SThomas Chou 246*f6569884SThomas Chou static int ethoc_init_ring(struct eth_device *dev) 247*f6569884SThomas Chou { 248*f6569884SThomas Chou struct ethoc *priv = (struct ethoc *)dev->priv; 249*f6569884SThomas Chou struct ethoc_bd bd; 250*f6569884SThomas Chou int i; 251*f6569884SThomas Chou 252*f6569884SThomas Chou priv->cur_tx = 0; 253*f6569884SThomas Chou priv->dty_tx = 0; 254*f6569884SThomas Chou priv->cur_rx = 0; 255*f6569884SThomas Chou 256*f6569884SThomas Chou /* setup transmission buffers */ 257*f6569884SThomas Chou bd.stat = TX_BD_IRQ | TX_BD_CRC; 258*f6569884SThomas Chou 259*f6569884SThomas Chou for (i = 0; i < priv->num_tx; i++) { 260*f6569884SThomas Chou if (i == priv->num_tx - 1) 261*f6569884SThomas Chou bd.stat |= TX_BD_WRAP; 262*f6569884SThomas Chou 263*f6569884SThomas Chou ethoc_write_bd(dev, i, &bd); 264*f6569884SThomas Chou } 265*f6569884SThomas Chou 266*f6569884SThomas Chou bd.stat = RX_BD_EMPTY | RX_BD_IRQ; 267*f6569884SThomas Chou 268*f6569884SThomas Chou for (i = 0; i < priv->num_rx; i++) { 269*f6569884SThomas Chou bd.addr = (u32)NetRxPackets[i]; 270*f6569884SThomas Chou if (i == priv->num_rx - 1) 271*f6569884SThomas Chou bd.stat |= RX_BD_WRAP; 272*f6569884SThomas Chou 273*f6569884SThomas Chou flush_dcache(bd.addr, PKTSIZE_ALIGN); 274*f6569884SThomas Chou ethoc_write_bd(dev, priv->num_tx + i, &bd); 275*f6569884SThomas Chou } 276*f6569884SThomas Chou 277*f6569884SThomas Chou return 0; 278*f6569884SThomas Chou } 279*f6569884SThomas Chou 280*f6569884SThomas Chou static int ethoc_reset(struct eth_device *dev) 281*f6569884SThomas Chou { 282*f6569884SThomas Chou u32 mode; 283*f6569884SThomas Chou 284*f6569884SThomas Chou /* TODO: reset controller? */ 285*f6569884SThomas Chou 286*f6569884SThomas Chou ethoc_disable_rx_and_tx(dev); 287*f6569884SThomas Chou 288*f6569884SThomas Chou /* TODO: setup registers */ 289*f6569884SThomas Chou 290*f6569884SThomas Chou /* enable FCS generation and automatic padding */ 291*f6569884SThomas Chou mode = ethoc_read(dev, MODER); 292*f6569884SThomas Chou mode |= MODER_CRC | MODER_PAD; 293*f6569884SThomas Chou ethoc_write(dev, MODER, mode); 294*f6569884SThomas Chou 295*f6569884SThomas Chou /* set full-duplex mode */ 296*f6569884SThomas Chou mode = ethoc_read(dev, MODER); 297*f6569884SThomas Chou mode |= MODER_FULLD; 298*f6569884SThomas Chou ethoc_write(dev, MODER, mode); 299*f6569884SThomas Chou ethoc_write(dev, IPGT, 0x15); 300*f6569884SThomas Chou 301*f6569884SThomas Chou ethoc_ack_irq(dev, INT_MASK_ALL); 302*f6569884SThomas Chou ethoc_enable_rx_and_tx(dev); 303*f6569884SThomas Chou return 0; 304*f6569884SThomas Chou } 305*f6569884SThomas Chou 306*f6569884SThomas Chou static int ethoc_init(struct eth_device *dev, bd_t * bd) 307*f6569884SThomas Chou { 308*f6569884SThomas Chou struct ethoc *priv = (struct ethoc *)dev->priv; 309*f6569884SThomas Chou printf("ethoc\n"); 310*f6569884SThomas Chou 311*f6569884SThomas Chou ethoc_set_mac_address(dev); 312*f6569884SThomas Chou 313*f6569884SThomas Chou priv->num_tx = 1; 314*f6569884SThomas Chou priv->num_rx = PKTBUFSRX; 315*f6569884SThomas Chou ethoc_write(dev, TX_BD_NUM, priv->num_tx); 316*f6569884SThomas Chou ethoc_init_ring(dev); 317*f6569884SThomas Chou ethoc_reset(dev); 318*f6569884SThomas Chou 319*f6569884SThomas Chou return 0; 320*f6569884SThomas Chou } 321*f6569884SThomas Chou 322*f6569884SThomas Chou static int ethoc_update_rx_stats(struct ethoc_bd *bd) 323*f6569884SThomas Chou { 324*f6569884SThomas Chou int ret = 0; 325*f6569884SThomas Chou 326*f6569884SThomas Chou if (bd->stat & RX_BD_TL) { 327*f6569884SThomas Chou debug("ETHOC: " "RX: frame too long\n"); 328*f6569884SThomas Chou ret++; 329*f6569884SThomas Chou } 330*f6569884SThomas Chou 331*f6569884SThomas Chou if (bd->stat & RX_BD_SF) { 332*f6569884SThomas Chou debug("ETHOC: " "RX: frame too short\n"); 333*f6569884SThomas Chou ret++; 334*f6569884SThomas Chou } 335*f6569884SThomas Chou 336*f6569884SThomas Chou if (bd->stat & RX_BD_DN) 337*f6569884SThomas Chou debug("ETHOC: " "RX: dribble nibble\n"); 338*f6569884SThomas Chou 339*f6569884SThomas Chou if (bd->stat & RX_BD_CRC) { 340*f6569884SThomas Chou debug("ETHOC: " "RX: wrong CRC\n"); 341*f6569884SThomas Chou ret++; 342*f6569884SThomas Chou } 343*f6569884SThomas Chou 344*f6569884SThomas Chou if (bd->stat & RX_BD_OR) { 345*f6569884SThomas Chou debug("ETHOC: " "RX: overrun\n"); 346*f6569884SThomas Chou ret++; 347*f6569884SThomas Chou } 348*f6569884SThomas Chou 349*f6569884SThomas Chou if (bd->stat & RX_BD_LC) { 350*f6569884SThomas Chou debug("ETHOC: " "RX: late collision\n"); 351*f6569884SThomas Chou ret++; 352*f6569884SThomas Chou } 353*f6569884SThomas Chou 354*f6569884SThomas Chou return ret; 355*f6569884SThomas Chou } 356*f6569884SThomas Chou 357*f6569884SThomas Chou static int ethoc_rx(struct eth_device *dev, int limit) 358*f6569884SThomas Chou { 359*f6569884SThomas Chou struct ethoc *priv = (struct ethoc *)dev->priv; 360*f6569884SThomas Chou int count; 361*f6569884SThomas Chou 362*f6569884SThomas Chou for (count = 0; count < limit; ++count) { 363*f6569884SThomas Chou u32 entry; 364*f6569884SThomas Chou struct ethoc_bd bd; 365*f6569884SThomas Chou 366*f6569884SThomas Chou entry = priv->num_tx + (priv->cur_rx % priv->num_rx); 367*f6569884SThomas Chou ethoc_read_bd(dev, entry, &bd); 368*f6569884SThomas Chou if (bd.stat & RX_BD_EMPTY) 369*f6569884SThomas Chou break; 370*f6569884SThomas Chou 371*f6569884SThomas Chou debug("%s(): RX buffer %d, %x received\n", 372*f6569884SThomas Chou __func__, priv->cur_rx, bd.stat); 373*f6569884SThomas Chou if (ethoc_update_rx_stats(&bd) == 0) { 374*f6569884SThomas Chou int size = bd.stat >> 16; 375*f6569884SThomas Chou size -= 4; /* strip the CRC */ 376*f6569884SThomas Chou NetReceive((void *)bd.addr, size); 377*f6569884SThomas Chou } 378*f6569884SThomas Chou 379*f6569884SThomas Chou /* clear the buffer descriptor so it can be reused */ 380*f6569884SThomas Chou flush_dcache(bd.addr, PKTSIZE_ALIGN); 381*f6569884SThomas Chou bd.stat &= ~RX_BD_STATS; 382*f6569884SThomas Chou bd.stat |= RX_BD_EMPTY; 383*f6569884SThomas Chou ethoc_write_bd(dev, entry, &bd); 384*f6569884SThomas Chou priv->cur_rx++; 385*f6569884SThomas Chou } 386*f6569884SThomas Chou 387*f6569884SThomas Chou return count; 388*f6569884SThomas Chou } 389*f6569884SThomas Chou 390*f6569884SThomas Chou static int ethoc_update_tx_stats(struct ethoc_bd *bd) 391*f6569884SThomas Chou { 392*f6569884SThomas Chou if (bd->stat & TX_BD_LC) 393*f6569884SThomas Chou debug("ETHOC: " "TX: late collision\n"); 394*f6569884SThomas Chou 395*f6569884SThomas Chou if (bd->stat & TX_BD_RL) 396*f6569884SThomas Chou debug("ETHOC: " "TX: retransmit limit\n"); 397*f6569884SThomas Chou 398*f6569884SThomas Chou if (bd->stat & TX_BD_UR) 399*f6569884SThomas Chou debug("ETHOC: " "TX: underrun\n"); 400*f6569884SThomas Chou 401*f6569884SThomas Chou if (bd->stat & TX_BD_CS) 402*f6569884SThomas Chou debug("ETHOC: " "TX: carrier sense lost\n"); 403*f6569884SThomas Chou 404*f6569884SThomas Chou return 0; 405*f6569884SThomas Chou } 406*f6569884SThomas Chou 407*f6569884SThomas Chou static void ethoc_tx(struct eth_device *dev) 408*f6569884SThomas Chou { 409*f6569884SThomas Chou struct ethoc *priv = (struct ethoc *)dev->priv; 410*f6569884SThomas Chou u32 entry = priv->dty_tx % priv->num_tx; 411*f6569884SThomas Chou struct ethoc_bd bd; 412*f6569884SThomas Chou 413*f6569884SThomas Chou ethoc_read_bd(dev, entry, &bd); 414*f6569884SThomas Chou if ((bd.stat & TX_BD_READY) == 0) 415*f6569884SThomas Chou (void)ethoc_update_tx_stats(&bd); 416*f6569884SThomas Chou } 417*f6569884SThomas Chou 418*f6569884SThomas Chou static int ethoc_send(struct eth_device *dev, volatile void *packet, int length) 419*f6569884SThomas Chou { 420*f6569884SThomas Chou struct ethoc *priv = (struct ethoc *)dev->priv; 421*f6569884SThomas Chou struct ethoc_bd bd; 422*f6569884SThomas Chou u32 entry; 423*f6569884SThomas Chou u32 pending; 424*f6569884SThomas Chou int tmo; 425*f6569884SThomas Chou 426*f6569884SThomas Chou entry = priv->cur_tx % priv->num_tx; 427*f6569884SThomas Chou ethoc_read_bd(dev, entry, &bd); 428*f6569884SThomas Chou if (unlikely(length < ETHOC_ZLEN)) 429*f6569884SThomas Chou bd.stat |= TX_BD_PAD; 430*f6569884SThomas Chou else 431*f6569884SThomas Chou bd.stat &= ~TX_BD_PAD; 432*f6569884SThomas Chou bd.addr = (u32)packet; 433*f6569884SThomas Chou 434*f6569884SThomas Chou flush_dcache(bd.addr, length); 435*f6569884SThomas Chou bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK); 436*f6569884SThomas Chou bd.stat |= TX_BD_LEN(length); 437*f6569884SThomas Chou ethoc_write_bd(dev, entry, &bd); 438*f6569884SThomas Chou 439*f6569884SThomas Chou /* start transmit */ 440*f6569884SThomas Chou bd.stat |= TX_BD_READY; 441*f6569884SThomas Chou ethoc_write_bd(dev, entry, &bd); 442*f6569884SThomas Chou 443*f6569884SThomas Chou /* wait for transfer to succeed */ 444*f6569884SThomas Chou tmo = get_timer(0) + 5 * CONFIG_SYS_HZ; 445*f6569884SThomas Chou while (1) { 446*f6569884SThomas Chou pending = ethoc_read(dev, INT_SOURCE); 447*f6569884SThomas Chou ethoc_ack_irq(dev, pending & ~INT_MASK_RX); 448*f6569884SThomas Chou if (pending & INT_MASK_BUSY) 449*f6569884SThomas Chou debug("%s(): packet dropped\n", __func__); 450*f6569884SThomas Chou 451*f6569884SThomas Chou if (pending & INT_MASK_TX) { 452*f6569884SThomas Chou ethoc_tx(dev); 453*f6569884SThomas Chou break; 454*f6569884SThomas Chou } 455*f6569884SThomas Chou if (get_timer(0) >= tmo) { 456*f6569884SThomas Chou debug("%s(): timed out\n", __func__); 457*f6569884SThomas Chou return -1; 458*f6569884SThomas Chou } 459*f6569884SThomas Chou } 460*f6569884SThomas Chou 461*f6569884SThomas Chou debug("%s(): packet sent\n", __func__); 462*f6569884SThomas Chou return 0; 463*f6569884SThomas Chou } 464*f6569884SThomas Chou 465*f6569884SThomas Chou static void ethoc_halt(struct eth_device *dev) 466*f6569884SThomas Chou { 467*f6569884SThomas Chou ethoc_disable_rx_and_tx(dev); 468*f6569884SThomas Chou } 469*f6569884SThomas Chou 470*f6569884SThomas Chou static int ethoc_recv(struct eth_device *dev) 471*f6569884SThomas Chou { 472*f6569884SThomas Chou u32 pending; 473*f6569884SThomas Chou 474*f6569884SThomas Chou pending = ethoc_read(dev, INT_SOURCE); 475*f6569884SThomas Chou ethoc_ack_irq(dev, pending); 476*f6569884SThomas Chou if (pending & INT_MASK_BUSY) 477*f6569884SThomas Chou debug("%s(): packet dropped\n", __func__); 478*f6569884SThomas Chou if (pending & INT_MASK_RX) { 479*f6569884SThomas Chou debug("%s(): rx irq\n", __func__); 480*f6569884SThomas Chou ethoc_rx(dev, PKTBUFSRX); 481*f6569884SThomas Chou } 482*f6569884SThomas Chou 483*f6569884SThomas Chou return 0; 484*f6569884SThomas Chou } 485*f6569884SThomas Chou 486*f6569884SThomas Chou int ethoc_initialize(u8 dev_num, int base_addr) 487*f6569884SThomas Chou { 488*f6569884SThomas Chou struct ethoc *priv; 489*f6569884SThomas Chou struct eth_device *dev; 490*f6569884SThomas Chou 491*f6569884SThomas Chou priv = malloc(sizeof(*priv)); 492*f6569884SThomas Chou if (!priv) 493*f6569884SThomas Chou return 0; 494*f6569884SThomas Chou dev = malloc(sizeof(*dev)); 495*f6569884SThomas Chou if (!dev) { 496*f6569884SThomas Chou free(priv); 497*f6569884SThomas Chou return 0; 498*f6569884SThomas Chou } 499*f6569884SThomas Chou 500*f6569884SThomas Chou memset(dev, 0, sizeof(*dev)); 501*f6569884SThomas Chou dev->priv = priv; 502*f6569884SThomas Chou dev->iobase = base_addr; 503*f6569884SThomas Chou dev->init = ethoc_init; 504*f6569884SThomas Chou dev->halt = ethoc_halt; 505*f6569884SThomas Chou dev->send = ethoc_send; 506*f6569884SThomas Chou dev->recv = ethoc_recv; 507*f6569884SThomas Chou sprintf(dev->name, "%s-%hu", "ETHOC", dev_num); 508*f6569884SThomas Chou 509*f6569884SThomas Chou eth_register(dev); 510*f6569884SThomas Chou return 1; 511*f6569884SThomas Chou } 512