1*702c85b0SNobuhiro Iwamatsu /* 2*702c85b0SNobuhiro Iwamatsu Ported to U-Boot by Christian Pellegrin <chri@ascensit.com> 3*702c85b0SNobuhiro Iwamatsu 4*702c85b0SNobuhiro Iwamatsu Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and 5*702c85b0SNobuhiro Iwamatsu eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world 6*702c85b0SNobuhiro Iwamatsu are GPL, so this is, of course, GPL. 7*702c85b0SNobuhiro Iwamatsu 8*702c85b0SNobuhiro Iwamatsu ========================================================================== 9*702c85b0SNobuhiro Iwamatsu 10*702c85b0SNobuhiro Iwamatsu dev/if_dp83902a.c 11*702c85b0SNobuhiro Iwamatsu 12*702c85b0SNobuhiro Iwamatsu Ethernet device driver for NS DP83902a ethernet controller 13*702c85b0SNobuhiro Iwamatsu 14*702c85b0SNobuhiro Iwamatsu ========================================================================== 15*702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTBEGIN#### 16*702c85b0SNobuhiro Iwamatsu ------------------------------------------- 17*702c85b0SNobuhiro Iwamatsu This file is part of eCos, the Embedded Configurable Operating System. 18*702c85b0SNobuhiro Iwamatsu Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. 19*702c85b0SNobuhiro Iwamatsu 20*702c85b0SNobuhiro Iwamatsu eCos is free software; you can redistribute it and/or modify it under 21*702c85b0SNobuhiro Iwamatsu the terms of the GNU General Public License as published by the Free 22*702c85b0SNobuhiro Iwamatsu Software Foundation; either version 2 or (at your option) any later version. 23*702c85b0SNobuhiro Iwamatsu 24*702c85b0SNobuhiro Iwamatsu eCos is distributed in the hope that it will be useful, but WITHOUT ANY 25*702c85b0SNobuhiro Iwamatsu WARRANTY; without even the implied warranty of MERCHANTABILITY or 26*702c85b0SNobuhiro Iwamatsu FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27*702c85b0SNobuhiro Iwamatsu for more details. 28*702c85b0SNobuhiro Iwamatsu 29*702c85b0SNobuhiro Iwamatsu You should have received a copy of the GNU General Public License along 30*702c85b0SNobuhiro Iwamatsu with eCos; if not, write to the Free Software Foundation, Inc., 31*702c85b0SNobuhiro Iwamatsu 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 32*702c85b0SNobuhiro Iwamatsu 33*702c85b0SNobuhiro Iwamatsu As a special exception, if other files instantiate templates or use macros 34*702c85b0SNobuhiro Iwamatsu or inline functions from this file, or you compile this file and link it 35*702c85b0SNobuhiro Iwamatsu with other works to produce a work based on this file, this file does not 36*702c85b0SNobuhiro Iwamatsu by itself cause the resulting work to be covered by the GNU General Public 37*702c85b0SNobuhiro Iwamatsu License. However the source code for this file must still be made available 38*702c85b0SNobuhiro Iwamatsu in accordance with section (3) of the GNU General Public License. 39*702c85b0SNobuhiro Iwamatsu 40*702c85b0SNobuhiro Iwamatsu This exception does not invalidate any other reasons why a work based on 41*702c85b0SNobuhiro Iwamatsu this file might be covered by the GNU General Public License. 42*702c85b0SNobuhiro Iwamatsu 43*702c85b0SNobuhiro Iwamatsu Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. 44*702c85b0SNobuhiro Iwamatsu at http://sources.redhat.com/ecos/ecos-license/ 45*702c85b0SNobuhiro Iwamatsu ------------------------------------------- 46*702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTEND#### 47*702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTBEGIN#### 48*702c85b0SNobuhiro Iwamatsu 49*702c85b0SNobuhiro Iwamatsu ------------------------------------------- 50*702c85b0SNobuhiro Iwamatsu 51*702c85b0SNobuhiro Iwamatsu Portions of this software may have been derived from OpenBSD or other sources, 52*702c85b0SNobuhiro Iwamatsu and are covered by the appropriate copyright disclaimers included herein. 53*702c85b0SNobuhiro Iwamatsu 54*702c85b0SNobuhiro Iwamatsu ------------------------------------------- 55*702c85b0SNobuhiro Iwamatsu 56*702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTEND#### 57*702c85b0SNobuhiro Iwamatsu ========================================================================== 58*702c85b0SNobuhiro Iwamatsu #####DESCRIPTIONBEGIN#### 59*702c85b0SNobuhiro Iwamatsu 60*702c85b0SNobuhiro Iwamatsu Author(s): gthomas 61*702c85b0SNobuhiro Iwamatsu Contributors: gthomas, jskov, rsandifo 62*702c85b0SNobuhiro Iwamatsu Date: 2001-06-13 63*702c85b0SNobuhiro Iwamatsu Purpose: 64*702c85b0SNobuhiro Iwamatsu Description: 65*702c85b0SNobuhiro Iwamatsu 66*702c85b0SNobuhiro Iwamatsu FIXME: Will fail if pinged with large packets (1520 bytes) 67*702c85b0SNobuhiro Iwamatsu Add promisc config 68*702c85b0SNobuhiro Iwamatsu Add SNMP 69*702c85b0SNobuhiro Iwamatsu 70*702c85b0SNobuhiro Iwamatsu ####DESCRIPTIONEND#### 71*702c85b0SNobuhiro Iwamatsu 72*702c85b0SNobuhiro Iwamatsu ========================================================================== 73*702c85b0SNobuhiro Iwamatsu */ 74*702c85b0SNobuhiro Iwamatsu 75*702c85b0SNobuhiro Iwamatsu #include <common.h> 76*702c85b0SNobuhiro Iwamatsu #include <command.h> 77*702c85b0SNobuhiro Iwamatsu #include <net.h> 78*702c85b0SNobuhiro Iwamatsu #include <malloc.h> 79*702c85b0SNobuhiro Iwamatsu 80*702c85b0SNobuhiro Iwamatsu #define mdelay(n) udelay((n)*1000) 81*702c85b0SNobuhiro Iwamatsu /* forward definition of function used for the uboot interface */ 82*702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len); 83*702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val); 84*702c85b0SNobuhiro Iwamatsu 85*702c85b0SNobuhiro Iwamatsu /* NE2000 base header file */ 86*702c85b0SNobuhiro Iwamatsu #include "ne2000_base.h" 87*702c85b0SNobuhiro Iwamatsu 88*702c85b0SNobuhiro Iwamatsu #if defined(CONFIG_DRIVER_AX88796L) 89*702c85b0SNobuhiro Iwamatsu /* AX88796L support */ 90*702c85b0SNobuhiro Iwamatsu #include "ax88796.h" 91*702c85b0SNobuhiro Iwamatsu #else 92*702c85b0SNobuhiro Iwamatsu /* Basic NE2000 chip support */ 93*702c85b0SNobuhiro Iwamatsu #include "ne2000.h" 94*702c85b0SNobuhiro Iwamatsu #endif 95*702c85b0SNobuhiro Iwamatsu 96*702c85b0SNobuhiro Iwamatsu static dp83902a_priv_data_t nic; /* just one instance of the card supported */ 97*702c85b0SNobuhiro Iwamatsu 98*702c85b0SNobuhiro Iwamatsu static bool 99*702c85b0SNobuhiro Iwamatsu dp83902a_init(void) 100*702c85b0SNobuhiro Iwamatsu { 101*702c85b0SNobuhiro Iwamatsu dp83902a_priv_data_t *dp = &nic; 102*702c85b0SNobuhiro Iwamatsu u8* base; 103*702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT) 104*702c85b0SNobuhiro Iwamatsu int i; 105*702c85b0SNobuhiro Iwamatsu #endif 106*702c85b0SNobuhiro Iwamatsu 107*702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 108*702c85b0SNobuhiro Iwamatsu 109*702c85b0SNobuhiro Iwamatsu base = dp->base; 110*702c85b0SNobuhiro Iwamatsu if (!base) 111*702c85b0SNobuhiro Iwamatsu return false; /* No device found */ 112*702c85b0SNobuhiro Iwamatsu 113*702c85b0SNobuhiro Iwamatsu DEBUG_LINE(); 114*702c85b0SNobuhiro Iwamatsu 115*702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT) 116*702c85b0SNobuhiro Iwamatsu /* AX88796L doesn't need */ 117*702c85b0SNobuhiro Iwamatsu /* Prepare ESA */ 118*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */ 119*702c85b0SNobuhiro Iwamatsu /* Use the address from the serial EEPROM */ 120*702c85b0SNobuhiro Iwamatsu for (i = 0; i < 6; i++) 121*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_P1_PAR0+i, dp->esa[i]); 122*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */ 123*702c85b0SNobuhiro Iwamatsu 124*702c85b0SNobuhiro Iwamatsu printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", 125*702c85b0SNobuhiro Iwamatsu "eeprom", 126*702c85b0SNobuhiro Iwamatsu dp->esa[0], 127*702c85b0SNobuhiro Iwamatsu dp->esa[1], 128*702c85b0SNobuhiro Iwamatsu dp->esa[2], 129*702c85b0SNobuhiro Iwamatsu dp->esa[3], 130*702c85b0SNobuhiro Iwamatsu dp->esa[4], 131*702c85b0SNobuhiro Iwamatsu dp->esa[5] ); 132*702c85b0SNobuhiro Iwamatsu 133*702c85b0SNobuhiro Iwamatsu #endif /* NE2000_BASIC_INIT */ 134*702c85b0SNobuhiro Iwamatsu return true; 135*702c85b0SNobuhiro Iwamatsu } 136*702c85b0SNobuhiro Iwamatsu 137*702c85b0SNobuhiro Iwamatsu static void 138*702c85b0SNobuhiro Iwamatsu dp83902a_stop(void) 139*702c85b0SNobuhiro Iwamatsu { 140*702c85b0SNobuhiro Iwamatsu dp83902a_priv_data_t *dp = &nic; 141*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 142*702c85b0SNobuhiro Iwamatsu 143*702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 144*702c85b0SNobuhiro Iwamatsu 145*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ 146*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ 147*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */ 148*702c85b0SNobuhiro Iwamatsu 149*702c85b0SNobuhiro Iwamatsu dp->running = false; 150*702c85b0SNobuhiro Iwamatsu } 151*702c85b0SNobuhiro Iwamatsu 152*702c85b0SNobuhiro Iwamatsu /* 153*702c85b0SNobuhiro Iwamatsu * This function is called to "start up" the interface. It may be called 154*702c85b0SNobuhiro Iwamatsu * multiple times, even when the hardware is already running. It will be 155*702c85b0SNobuhiro Iwamatsu * called whenever something "hardware oriented" changes and should leave 156*702c85b0SNobuhiro Iwamatsu * the hardware ready to send/receive packets. 157*702c85b0SNobuhiro Iwamatsu */ 158*702c85b0SNobuhiro Iwamatsu static void 159*702c85b0SNobuhiro Iwamatsu dp83902a_start(u8 * enaddr) 160*702c85b0SNobuhiro Iwamatsu { 161*702c85b0SNobuhiro Iwamatsu dp83902a_priv_data_t *dp = &nic; 162*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 163*702c85b0SNobuhiro Iwamatsu int i; 164*702c85b0SNobuhiro Iwamatsu 165*702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 166*702c85b0SNobuhiro Iwamatsu 167*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ 168*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_DCR, DP_DCR_INIT); 169*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, 0); /* Remote byte count */ 170*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, 0); 171*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */ 172*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */ 173*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */ 174*702c85b0SNobuhiro Iwamatsu dp->tx1 = dp->tx2 = 0; 175*702c85b0SNobuhiro Iwamatsu dp->tx_next = dp->tx_buf1; 176*702c85b0SNobuhiro Iwamatsu dp->tx_started = false; 177*702c85b0SNobuhiro Iwamatsu dp->running = true; 178*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */ 179*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */ 180*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */ 181*702c85b0SNobuhiro Iwamatsu dp->rx_next = dp->rx_buf_start - 1; 182*702c85b0SNobuhiro Iwamatsu dp->running = true; 183*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ 184*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */ 185*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */ 186*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */ 187*702c85b0SNobuhiro Iwamatsu dp->running = true; 188*702c85b0SNobuhiro Iwamatsu for (i = 0; i < ETHER_ADDR_LEN; i++) { 189*702c85b0SNobuhiro Iwamatsu /* FIXME */ 190*702c85b0SNobuhiro Iwamatsu /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) + 191*702c85b0SNobuhiro Iwamatsu * 0x1400)) = enaddr[i];*/ 192*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_P1_PAR0+i, enaddr[i]); 193*702c85b0SNobuhiro Iwamatsu } 194*702c85b0SNobuhiro Iwamatsu /* Enable and start device */ 195*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 196*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */ 197*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */ 198*702c85b0SNobuhiro Iwamatsu dp->running = true; 199*702c85b0SNobuhiro Iwamatsu } 200*702c85b0SNobuhiro Iwamatsu 201*702c85b0SNobuhiro Iwamatsu /* 202*702c85b0SNobuhiro Iwamatsu * This routine is called to start the transmitter. It is split out from the 203*702c85b0SNobuhiro Iwamatsu * data handling routine so it may be called either when data becomes first 204*702c85b0SNobuhiro Iwamatsu * available or when an Tx interrupt occurs 205*702c85b0SNobuhiro Iwamatsu */ 206*702c85b0SNobuhiro Iwamatsu 207*702c85b0SNobuhiro Iwamatsu static void 208*702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(int start_page, int len) 209*702c85b0SNobuhiro Iwamatsu { 210*702c85b0SNobuhiro Iwamatsu dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic; 211*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 212*702c85b0SNobuhiro Iwamatsu 213*702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 214*702c85b0SNobuhiro Iwamatsu 215*702c85b0SNobuhiro Iwamatsu #if DEBUG & 1 216*702c85b0SNobuhiro Iwamatsu printf("Tx pkt %d len %d\n", start_page, len); 217*702c85b0SNobuhiro Iwamatsu if (dp->tx_started) 218*702c85b0SNobuhiro Iwamatsu printf("TX already started?!?\n"); 219*702c85b0SNobuhiro Iwamatsu #endif 220*702c85b0SNobuhiro Iwamatsu 221*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE)); 222*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 223*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TBCL, len & 0xFF); 224*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TBCH, len >> 8); 225*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TPSR, start_page); 226*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); 227*702c85b0SNobuhiro Iwamatsu 228*702c85b0SNobuhiro Iwamatsu dp->tx_started = true; 229*702c85b0SNobuhiro Iwamatsu } 230*702c85b0SNobuhiro Iwamatsu 231*702c85b0SNobuhiro Iwamatsu /* 232*702c85b0SNobuhiro Iwamatsu * This routine is called to send data to the hardware. It is known a-priori 233*702c85b0SNobuhiro Iwamatsu * that there is free buffer space (dp->tx_next). 234*702c85b0SNobuhiro Iwamatsu */ 235*702c85b0SNobuhiro Iwamatsu static void 236*702c85b0SNobuhiro Iwamatsu dp83902a_send(u8 *data, int total_len, u32 key) 237*702c85b0SNobuhiro Iwamatsu { 238*702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 239*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 240*702c85b0SNobuhiro Iwamatsu int len, start_page, pkt_len, i, isr; 241*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 242*702c85b0SNobuhiro Iwamatsu int dx; 243*702c85b0SNobuhiro Iwamatsu #endif 244*702c85b0SNobuhiro Iwamatsu 245*702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 246*702c85b0SNobuhiro Iwamatsu 247*702c85b0SNobuhiro Iwamatsu len = pkt_len = total_len; 248*702c85b0SNobuhiro Iwamatsu if (pkt_len < IEEE_8023_MIN_FRAME) 249*702c85b0SNobuhiro Iwamatsu pkt_len = IEEE_8023_MIN_FRAME; 250*702c85b0SNobuhiro Iwamatsu 251*702c85b0SNobuhiro Iwamatsu start_page = dp->tx_next; 252*702c85b0SNobuhiro Iwamatsu if (dp->tx_next == dp->tx_buf1) { 253*702c85b0SNobuhiro Iwamatsu dp->tx1 = start_page; 254*702c85b0SNobuhiro Iwamatsu dp->tx1_len = pkt_len; 255*702c85b0SNobuhiro Iwamatsu dp->tx1_key = key; 256*702c85b0SNobuhiro Iwamatsu dp->tx_next = dp->tx_buf2; 257*702c85b0SNobuhiro Iwamatsu } else { 258*702c85b0SNobuhiro Iwamatsu dp->tx2 = start_page; 259*702c85b0SNobuhiro Iwamatsu dp->tx2_len = pkt_len; 260*702c85b0SNobuhiro Iwamatsu dp->tx2_key = key; 261*702c85b0SNobuhiro Iwamatsu dp->tx_next = dp->tx_buf1; 262*702c85b0SNobuhiro Iwamatsu } 263*702c85b0SNobuhiro Iwamatsu 264*702c85b0SNobuhiro Iwamatsu #if DEBUG & 5 265*702c85b0SNobuhiro Iwamatsu printf("TX prep page %d len %d\n", start_page, pkt_len); 266*702c85b0SNobuhiro Iwamatsu #endif 267*702c85b0SNobuhiro Iwamatsu 268*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ 269*702c85b0SNobuhiro Iwamatsu { 270*702c85b0SNobuhiro Iwamatsu /* 271*702c85b0SNobuhiro Iwamatsu * Dummy read. The manual sez something slightly different, 272*702c85b0SNobuhiro Iwamatsu * but the code is extended a bit to do what Hitachi's monitor 273*702c85b0SNobuhiro Iwamatsu * does (i.e., also read data). 274*702c85b0SNobuhiro Iwamatsu */ 275*702c85b0SNobuhiro Iwamatsu 276*702c85b0SNobuhiro Iwamatsu u16 tmp; 277*702c85b0SNobuhiro Iwamatsu int len = 1; 278*702c85b0SNobuhiro Iwamatsu 279*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAL, 0x100 - len); 280*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff); 281*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, len); 282*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, 0); 283*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START); 284*702c85b0SNobuhiro Iwamatsu DP_IN_DATA(dp->data, tmp); 285*702c85b0SNobuhiro Iwamatsu } 286*702c85b0SNobuhiro Iwamatsu 287*702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA 288*702c85b0SNobuhiro Iwamatsu /* 289*702c85b0SNobuhiro Iwamatsu * Stall for a bit before continuing to work around random data 290*702c85b0SNobuhiro Iwamatsu * corruption problems on some platforms. 291*702c85b0SNobuhiro Iwamatsu */ 292*702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(1); 293*702c85b0SNobuhiro Iwamatsu #endif 294*702c85b0SNobuhiro Iwamatsu 295*702c85b0SNobuhiro Iwamatsu /* Send data to device buffer(s) */ 296*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAL, 0); 297*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAH, start_page); 298*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, pkt_len & 0xFF); 299*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, pkt_len >> 8); 300*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START); 301*702c85b0SNobuhiro Iwamatsu 302*702c85b0SNobuhiro Iwamatsu /* Put data into buffer */ 303*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 304*702c85b0SNobuhiro Iwamatsu printf(" sg buf %08lx len %08x\n ", (u32)data, len); 305*702c85b0SNobuhiro Iwamatsu dx = 0; 306*702c85b0SNobuhiro Iwamatsu #endif 307*702c85b0SNobuhiro Iwamatsu while (len > 0) { 308*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 309*702c85b0SNobuhiro Iwamatsu printf(" %02x", *data); 310*702c85b0SNobuhiro Iwamatsu if (0 == (++dx % 16)) printf("\n "); 311*702c85b0SNobuhiro Iwamatsu #endif 312*702c85b0SNobuhiro Iwamatsu 313*702c85b0SNobuhiro Iwamatsu DP_OUT_DATA(dp->data, *data++); 314*702c85b0SNobuhiro Iwamatsu len--; 315*702c85b0SNobuhiro Iwamatsu } 316*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 317*702c85b0SNobuhiro Iwamatsu printf("\n"); 318*702c85b0SNobuhiro Iwamatsu #endif 319*702c85b0SNobuhiro Iwamatsu if (total_len < pkt_len) { 320*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 321*702c85b0SNobuhiro Iwamatsu printf(" + %d bytes of padding\n", pkt_len - total_len); 322*702c85b0SNobuhiro Iwamatsu #endif 323*702c85b0SNobuhiro Iwamatsu /* Padding to 802.3 length was required */ 324*702c85b0SNobuhiro Iwamatsu for (i = total_len; i < pkt_len;) { 325*702c85b0SNobuhiro Iwamatsu i++; 326*702c85b0SNobuhiro Iwamatsu DP_OUT_DATA(dp->data, 0); 327*702c85b0SNobuhiro Iwamatsu } 328*702c85b0SNobuhiro Iwamatsu } 329*702c85b0SNobuhiro Iwamatsu 330*702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA 331*702c85b0SNobuhiro Iwamatsu /* 332*702c85b0SNobuhiro Iwamatsu * After last data write, delay for a bit before accessing the 333*702c85b0SNobuhiro Iwamatsu * device again, or we may get random data corruption in the last 334*702c85b0SNobuhiro Iwamatsu * datum (on some platforms). 335*702c85b0SNobuhiro Iwamatsu */ 336*702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(1); 337*702c85b0SNobuhiro Iwamatsu #endif 338*702c85b0SNobuhiro Iwamatsu 339*702c85b0SNobuhiro Iwamatsu /* Wait for DMA to complete */ 340*702c85b0SNobuhiro Iwamatsu do { 341*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_ISR, isr); 342*702c85b0SNobuhiro Iwamatsu } while ((isr & DP_ISR_RDC) == 0); 343*702c85b0SNobuhiro Iwamatsu 344*702c85b0SNobuhiro Iwamatsu /* Then disable DMA */ 345*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 346*702c85b0SNobuhiro Iwamatsu 347*702c85b0SNobuhiro Iwamatsu /* Start transmit if not already going */ 348*702c85b0SNobuhiro Iwamatsu if (!dp->tx_started) { 349*702c85b0SNobuhiro Iwamatsu if (start_page == dp->tx1) { 350*702c85b0SNobuhiro Iwamatsu dp->tx_int = 1; /* Expecting interrupt from BUF1 */ 351*702c85b0SNobuhiro Iwamatsu } else { 352*702c85b0SNobuhiro Iwamatsu dp->tx_int = 2; /* Expecting interrupt from BUF2 */ 353*702c85b0SNobuhiro Iwamatsu } 354*702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(start_page, pkt_len); 355*702c85b0SNobuhiro Iwamatsu } 356*702c85b0SNobuhiro Iwamatsu } 357*702c85b0SNobuhiro Iwamatsu 358*702c85b0SNobuhiro Iwamatsu /* 359*702c85b0SNobuhiro Iwamatsu * This function is called when a packet has been received. It's job is 360*702c85b0SNobuhiro Iwamatsu * to prepare to unload the packet from the hardware. Once the length of 361*702c85b0SNobuhiro Iwamatsu * the packet is known, the upper layer of the driver can be told. When 362*702c85b0SNobuhiro Iwamatsu * the upper layer is ready to unload the packet, the internal function 363*702c85b0SNobuhiro Iwamatsu * 'dp83902a_recv' will be called to actually fetch it from the hardware. 364*702c85b0SNobuhiro Iwamatsu */ 365*702c85b0SNobuhiro Iwamatsu static void 366*702c85b0SNobuhiro Iwamatsu dp83902a_RxEvent(void) 367*702c85b0SNobuhiro Iwamatsu { 368*702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 369*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 370*702c85b0SNobuhiro Iwamatsu u8 rsr; 371*702c85b0SNobuhiro Iwamatsu u8 rcv_hdr[4]; 372*702c85b0SNobuhiro Iwamatsu int i, len, pkt, cur; 373*702c85b0SNobuhiro Iwamatsu 374*702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 375*702c85b0SNobuhiro Iwamatsu 376*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_RSR, rsr); 377*702c85b0SNobuhiro Iwamatsu while (true) { 378*702c85b0SNobuhiro Iwamatsu /* Read incoming packet header */ 379*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START); 380*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_P1_CURP, cur); 381*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 382*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_BNDRY, pkt); 383*702c85b0SNobuhiro Iwamatsu 384*702c85b0SNobuhiro Iwamatsu pkt += 1; 385*702c85b0SNobuhiro Iwamatsu if (pkt == dp->rx_buf_end) 386*702c85b0SNobuhiro Iwamatsu pkt = dp->rx_buf_start; 387*702c85b0SNobuhiro Iwamatsu 388*702c85b0SNobuhiro Iwamatsu if (pkt == cur) { 389*702c85b0SNobuhiro Iwamatsu break; 390*702c85b0SNobuhiro Iwamatsu } 391*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, sizeof(rcv_hdr)); 392*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, 0); 393*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAL, 0); 394*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAH, pkt); 395*702c85b0SNobuhiro Iwamatsu if (dp->rx_next == pkt) { 396*702c85b0SNobuhiro Iwamatsu if (cur == dp->rx_buf_start) 397*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); 398*702c85b0SNobuhiro Iwamatsu else 399*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */ 400*702c85b0SNobuhiro Iwamatsu return; 401*702c85b0SNobuhiro Iwamatsu } 402*702c85b0SNobuhiro Iwamatsu dp->rx_next = pkt; 403*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ 404*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); 405*702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA 406*702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(10); 407*702c85b0SNobuhiro Iwamatsu #endif 408*702c85b0SNobuhiro Iwamatsu 409*702c85b0SNobuhiro Iwamatsu /* read header (get data size)*/ 410*702c85b0SNobuhiro Iwamatsu for (i = 0; i < sizeof(rcv_hdr);) { 411*702c85b0SNobuhiro Iwamatsu DP_IN_DATA(dp->data, rcv_hdr[i++]); 412*702c85b0SNobuhiro Iwamatsu } 413*702c85b0SNobuhiro Iwamatsu 414*702c85b0SNobuhiro Iwamatsu #if DEBUG & 5 415*702c85b0SNobuhiro Iwamatsu printf("rx hdr %02x %02x %02x %02x\n", 416*702c85b0SNobuhiro Iwamatsu rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]); 417*702c85b0SNobuhiro Iwamatsu #endif 418*702c85b0SNobuhiro Iwamatsu len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); 419*702c85b0SNobuhiro Iwamatsu 420*702c85b0SNobuhiro Iwamatsu /* data read */ 421*702c85b0SNobuhiro Iwamatsu uboot_push_packet_len(len); 422*702c85b0SNobuhiro Iwamatsu 423*702c85b0SNobuhiro Iwamatsu if (rcv_hdr[1] == dp->rx_buf_start) 424*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); 425*702c85b0SNobuhiro Iwamatsu else 426*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */ 427*702c85b0SNobuhiro Iwamatsu } 428*702c85b0SNobuhiro Iwamatsu } 429*702c85b0SNobuhiro Iwamatsu 430*702c85b0SNobuhiro Iwamatsu /* 431*702c85b0SNobuhiro Iwamatsu * This function is called as a result of the "eth_drv_recv()" call above. 432*702c85b0SNobuhiro Iwamatsu * It's job is to actually fetch data for a packet from the hardware once 433*702c85b0SNobuhiro Iwamatsu * memory buffers have been allocated for the packet. Note that the buffers 434*702c85b0SNobuhiro Iwamatsu * may come in pieces, using a scatter-gather list. This allows for more 435*702c85b0SNobuhiro Iwamatsu * efficient processing in the upper layers of the stack. 436*702c85b0SNobuhiro Iwamatsu */ 437*702c85b0SNobuhiro Iwamatsu static void 438*702c85b0SNobuhiro Iwamatsu dp83902a_recv(u8 *data, int len) 439*702c85b0SNobuhiro Iwamatsu { 440*702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 441*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 442*702c85b0SNobuhiro Iwamatsu int i, mlen; 443*702c85b0SNobuhiro Iwamatsu u8 saved_char = 0; 444*702c85b0SNobuhiro Iwamatsu bool saved; 445*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 446*702c85b0SNobuhiro Iwamatsu int dx; 447*702c85b0SNobuhiro Iwamatsu #endif 448*702c85b0SNobuhiro Iwamatsu 449*702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 450*702c85b0SNobuhiro Iwamatsu 451*702c85b0SNobuhiro Iwamatsu #if DEBUG & 5 452*702c85b0SNobuhiro Iwamatsu printf("Rx packet %d length %d\n", dp->rx_next, len); 453*702c85b0SNobuhiro Iwamatsu #endif 454*702c85b0SNobuhiro Iwamatsu 455*702c85b0SNobuhiro Iwamatsu /* Read incoming packet data */ 456*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 457*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, len & 0xFF); 458*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, len >> 8); 459*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAL, 4); /* Past header */ 460*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAH, dp->rx_next); 461*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ 462*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); 463*702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA 464*702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(10); 465*702c85b0SNobuhiro Iwamatsu #endif 466*702c85b0SNobuhiro Iwamatsu 467*702c85b0SNobuhiro Iwamatsu saved = false; 468*702c85b0SNobuhiro Iwamatsu for (i = 0; i < 1; i++) { 469*702c85b0SNobuhiro Iwamatsu if (data) { 470*702c85b0SNobuhiro Iwamatsu mlen = len; 471*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 472*702c85b0SNobuhiro Iwamatsu printf(" sg buf %08lx len %08x \n", (u32) data, mlen); 473*702c85b0SNobuhiro Iwamatsu dx = 0; 474*702c85b0SNobuhiro Iwamatsu #endif 475*702c85b0SNobuhiro Iwamatsu while (0 < mlen) { 476*702c85b0SNobuhiro Iwamatsu /* Saved byte from previous loop? */ 477*702c85b0SNobuhiro Iwamatsu if (saved) { 478*702c85b0SNobuhiro Iwamatsu *data++ = saved_char; 479*702c85b0SNobuhiro Iwamatsu mlen--; 480*702c85b0SNobuhiro Iwamatsu saved = false; 481*702c85b0SNobuhiro Iwamatsu continue; 482*702c85b0SNobuhiro Iwamatsu } 483*702c85b0SNobuhiro Iwamatsu 484*702c85b0SNobuhiro Iwamatsu { 485*702c85b0SNobuhiro Iwamatsu u8 tmp; 486*702c85b0SNobuhiro Iwamatsu DP_IN_DATA(dp->data, tmp); 487*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 488*702c85b0SNobuhiro Iwamatsu printf(" %02x", tmp); 489*702c85b0SNobuhiro Iwamatsu if (0 == (++dx % 16)) printf("\n "); 490*702c85b0SNobuhiro Iwamatsu #endif 491*702c85b0SNobuhiro Iwamatsu *data++ = tmp;; 492*702c85b0SNobuhiro Iwamatsu mlen--; 493*702c85b0SNobuhiro Iwamatsu } 494*702c85b0SNobuhiro Iwamatsu } 495*702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 496*702c85b0SNobuhiro Iwamatsu printf("\n"); 497*702c85b0SNobuhiro Iwamatsu #endif 498*702c85b0SNobuhiro Iwamatsu } 499*702c85b0SNobuhiro Iwamatsu } 500*702c85b0SNobuhiro Iwamatsu } 501*702c85b0SNobuhiro Iwamatsu 502*702c85b0SNobuhiro Iwamatsu static void 503*702c85b0SNobuhiro Iwamatsu dp83902a_TxEvent(void) 504*702c85b0SNobuhiro Iwamatsu { 505*702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 506*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 507*702c85b0SNobuhiro Iwamatsu u8 tsr; 508*702c85b0SNobuhiro Iwamatsu u32 key; 509*702c85b0SNobuhiro Iwamatsu 510*702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 511*702c85b0SNobuhiro Iwamatsu 512*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_TSR, tsr); 513*702c85b0SNobuhiro Iwamatsu if (dp->tx_int == 1) { 514*702c85b0SNobuhiro Iwamatsu key = dp->tx1_key; 515*702c85b0SNobuhiro Iwamatsu dp->tx1 = 0; 516*702c85b0SNobuhiro Iwamatsu } else { 517*702c85b0SNobuhiro Iwamatsu key = dp->tx2_key; 518*702c85b0SNobuhiro Iwamatsu dp->tx2 = 0; 519*702c85b0SNobuhiro Iwamatsu } 520*702c85b0SNobuhiro Iwamatsu /* Start next packet if one is ready */ 521*702c85b0SNobuhiro Iwamatsu dp->tx_started = false; 522*702c85b0SNobuhiro Iwamatsu if (dp->tx1) { 523*702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(dp->tx1, dp->tx1_len); 524*702c85b0SNobuhiro Iwamatsu dp->tx_int = 1; 525*702c85b0SNobuhiro Iwamatsu } else if (dp->tx2) { 526*702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(dp->tx2, dp->tx2_len); 527*702c85b0SNobuhiro Iwamatsu dp->tx_int = 2; 528*702c85b0SNobuhiro Iwamatsu } else { 529*702c85b0SNobuhiro Iwamatsu dp->tx_int = 0; 530*702c85b0SNobuhiro Iwamatsu } 531*702c85b0SNobuhiro Iwamatsu /* Tell higher level we sent this packet */ 532*702c85b0SNobuhiro Iwamatsu uboot_push_tx_done(key, 0); 533*702c85b0SNobuhiro Iwamatsu } 534*702c85b0SNobuhiro Iwamatsu 535*702c85b0SNobuhiro Iwamatsu /* 536*702c85b0SNobuhiro Iwamatsu * Read the tally counters to clear them. Called in response to a CNT 537*702c85b0SNobuhiro Iwamatsu * interrupt. 538*702c85b0SNobuhiro Iwamatsu */ 539*702c85b0SNobuhiro Iwamatsu static void 540*702c85b0SNobuhiro Iwamatsu dp83902a_ClearCounters(void) 541*702c85b0SNobuhiro Iwamatsu { 542*702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 543*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 544*702c85b0SNobuhiro Iwamatsu u8 cnt1, cnt2, cnt3; 545*702c85b0SNobuhiro Iwamatsu 546*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_FER, cnt1); 547*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_CER, cnt2); 548*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_MISSED, cnt3); 549*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_CNT); 550*702c85b0SNobuhiro Iwamatsu } 551*702c85b0SNobuhiro Iwamatsu 552*702c85b0SNobuhiro Iwamatsu /* 553*702c85b0SNobuhiro Iwamatsu * Deal with an overflow condition. This code follows the procedure set 554*702c85b0SNobuhiro Iwamatsu * out in section 7.0 of the datasheet. 555*702c85b0SNobuhiro Iwamatsu */ 556*702c85b0SNobuhiro Iwamatsu static void 557*702c85b0SNobuhiro Iwamatsu dp83902a_Overflow(void) 558*702c85b0SNobuhiro Iwamatsu { 559*702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic; 560*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 561*702c85b0SNobuhiro Iwamatsu u8 isr; 562*702c85b0SNobuhiro Iwamatsu 563*702c85b0SNobuhiro Iwamatsu /* Issue a stop command and wait 1.6ms for it to complete. */ 564*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA); 565*702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(1600); 566*702c85b0SNobuhiro Iwamatsu 567*702c85b0SNobuhiro Iwamatsu /* Clear the remote byte counter registers. */ 568*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, 0); 569*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, 0); 570*702c85b0SNobuhiro Iwamatsu 571*702c85b0SNobuhiro Iwamatsu /* Enter loopback mode while we clear the buffer. */ 572*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TCR, DP_TCR_LOCAL); 573*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA); 574*702c85b0SNobuhiro Iwamatsu 575*702c85b0SNobuhiro Iwamatsu /* 576*702c85b0SNobuhiro Iwamatsu * Read in as many packets as we can and acknowledge any and receive 577*702c85b0SNobuhiro Iwamatsu * interrupts. Since the buffer has overflowed, a receive event of 578*702c85b0SNobuhiro Iwamatsu * some kind will have occured. 579*702c85b0SNobuhiro Iwamatsu */ 580*702c85b0SNobuhiro Iwamatsu dp83902a_RxEvent(); 581*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE); 582*702c85b0SNobuhiro Iwamatsu 583*702c85b0SNobuhiro Iwamatsu /* Clear the overflow condition and leave loopback mode. */ 584*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_OFLW); 585*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TCR, DP_TCR_NORMAL); 586*702c85b0SNobuhiro Iwamatsu 587*702c85b0SNobuhiro Iwamatsu /* 588*702c85b0SNobuhiro Iwamatsu * If a transmit command was issued, but no transmit event has occured, 589*702c85b0SNobuhiro Iwamatsu * restart it here. 590*702c85b0SNobuhiro Iwamatsu */ 591*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_ISR, isr); 592*702c85b0SNobuhiro Iwamatsu if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) { 593*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); 594*702c85b0SNobuhiro Iwamatsu } 595*702c85b0SNobuhiro Iwamatsu } 596*702c85b0SNobuhiro Iwamatsu 597*702c85b0SNobuhiro Iwamatsu static void 598*702c85b0SNobuhiro Iwamatsu dp83902a_poll(void) 599*702c85b0SNobuhiro Iwamatsu { 600*702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 601*702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 602*702c85b0SNobuhiro Iwamatsu u8 isr; 603*702c85b0SNobuhiro Iwamatsu 604*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); 605*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_ISR, isr); 606*702c85b0SNobuhiro Iwamatsu while (0 != isr) { 607*702c85b0SNobuhiro Iwamatsu /* 608*702c85b0SNobuhiro Iwamatsu * The CNT interrupt triggers when the MSB of one of the error 609*702c85b0SNobuhiro Iwamatsu * counters is set. We don't much care about these counters, but 610*702c85b0SNobuhiro Iwamatsu * we should read their values to reset them. 611*702c85b0SNobuhiro Iwamatsu */ 612*702c85b0SNobuhiro Iwamatsu if (isr & DP_ISR_CNT) { 613*702c85b0SNobuhiro Iwamatsu dp83902a_ClearCounters(); 614*702c85b0SNobuhiro Iwamatsu } 615*702c85b0SNobuhiro Iwamatsu /* 616*702c85b0SNobuhiro Iwamatsu * Check for overflow. It's a special case, since there's a 617*702c85b0SNobuhiro Iwamatsu * particular procedure that must be followed to get back into 618*702c85b0SNobuhiro Iwamatsu * a running state.a 619*702c85b0SNobuhiro Iwamatsu */ 620*702c85b0SNobuhiro Iwamatsu if (isr & DP_ISR_OFLW) { 621*702c85b0SNobuhiro Iwamatsu dp83902a_Overflow(); 622*702c85b0SNobuhiro Iwamatsu } else { 623*702c85b0SNobuhiro Iwamatsu /* 624*702c85b0SNobuhiro Iwamatsu * Other kinds of interrupts can be acknowledged simply by 625*702c85b0SNobuhiro Iwamatsu * clearing the relevant bits of the ISR. Do that now, then 626*702c85b0SNobuhiro Iwamatsu * handle the interrupts we care about. 627*702c85b0SNobuhiro Iwamatsu */ 628*702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, isr); /* Clear set bits */ 629*702c85b0SNobuhiro Iwamatsu if (!dp->running) break; /* Is this necessary? */ 630*702c85b0SNobuhiro Iwamatsu /* 631*702c85b0SNobuhiro Iwamatsu * Check for tx_started on TX event since these may happen 632*702c85b0SNobuhiro Iwamatsu * spuriously it seems. 633*702c85b0SNobuhiro Iwamatsu */ 634*702c85b0SNobuhiro Iwamatsu if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { 635*702c85b0SNobuhiro Iwamatsu dp83902a_TxEvent(); 636*702c85b0SNobuhiro Iwamatsu } 637*702c85b0SNobuhiro Iwamatsu if (isr & (DP_ISR_RxP|DP_ISR_RxE)) { 638*702c85b0SNobuhiro Iwamatsu dp83902a_RxEvent(); 639*702c85b0SNobuhiro Iwamatsu } 640*702c85b0SNobuhiro Iwamatsu } 641*702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_ISR, isr); 642*702c85b0SNobuhiro Iwamatsu } 643*702c85b0SNobuhiro Iwamatsu } 644*702c85b0SNobuhiro Iwamatsu 645*702c85b0SNobuhiro Iwamatsu 646*702c85b0SNobuhiro Iwamatsu /* U-boot specific routines */ 647*702c85b0SNobuhiro Iwamatsu static u8 *pbuf = NULL; 648*702c85b0SNobuhiro Iwamatsu 649*702c85b0SNobuhiro Iwamatsu static int pkey = -1; 650*702c85b0SNobuhiro Iwamatsu static int initialized = 0; 651*702c85b0SNobuhiro Iwamatsu 652*702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len) { 653*702c85b0SNobuhiro Iwamatsu PRINTK("pushed len = %d\n", len); 654*702c85b0SNobuhiro Iwamatsu if (len >= 2000) { 655*702c85b0SNobuhiro Iwamatsu printf("NE2000: packet too big\n"); 656*702c85b0SNobuhiro Iwamatsu return; 657*702c85b0SNobuhiro Iwamatsu } 658*702c85b0SNobuhiro Iwamatsu dp83902a_recv(&pbuf[0], len); 659*702c85b0SNobuhiro Iwamatsu 660*702c85b0SNobuhiro Iwamatsu /*Just pass it to the upper layer*/ 661*702c85b0SNobuhiro Iwamatsu NetReceive(&pbuf[0], len); 662*702c85b0SNobuhiro Iwamatsu } 663*702c85b0SNobuhiro Iwamatsu 664*702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val) { 665*702c85b0SNobuhiro Iwamatsu PRINTK("pushed key = %d\n", key); 666*702c85b0SNobuhiro Iwamatsu pkey = key; 667*702c85b0SNobuhiro Iwamatsu } 668*702c85b0SNobuhiro Iwamatsu 669*702c85b0SNobuhiro Iwamatsu int eth_init(bd_t *bd) { 670*702c85b0SNobuhiro Iwamatsu int r; 671*702c85b0SNobuhiro Iwamatsu u8 dev_addr[6]; 672*702c85b0SNobuhiro Iwamatsu char ethaddr[20]; 673*702c85b0SNobuhiro Iwamatsu 674*702c85b0SNobuhiro Iwamatsu PRINTK("### eth_init\n"); 675*702c85b0SNobuhiro Iwamatsu 676*702c85b0SNobuhiro Iwamatsu if (!pbuf) { 677*702c85b0SNobuhiro Iwamatsu pbuf = malloc(2000); 678*702c85b0SNobuhiro Iwamatsu if (!pbuf) { 679*702c85b0SNobuhiro Iwamatsu printf("Cannot allocate rx buffer\n"); 680*702c85b0SNobuhiro Iwamatsu return -1; 681*702c85b0SNobuhiro Iwamatsu } 682*702c85b0SNobuhiro Iwamatsu } 683*702c85b0SNobuhiro Iwamatsu 684*702c85b0SNobuhiro Iwamatsu #ifdef CONFIG_DRIVER_NE2000_CCR 685*702c85b0SNobuhiro Iwamatsu { 686*702c85b0SNobuhiro Iwamatsu vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR; 687*702c85b0SNobuhiro Iwamatsu 688*702c85b0SNobuhiro Iwamatsu PRINTK("CCR before is %x\n", *p); 689*702c85b0SNobuhiro Iwamatsu *p = CONFIG_DRIVER_NE2000_VAL; 690*702c85b0SNobuhiro Iwamatsu PRINTK("CCR after is %x\n", *p); 691*702c85b0SNobuhiro Iwamatsu } 692*702c85b0SNobuhiro Iwamatsu #endif 693*702c85b0SNobuhiro Iwamatsu 694*702c85b0SNobuhiro Iwamatsu nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE; 695*702c85b0SNobuhiro Iwamatsu 696*702c85b0SNobuhiro Iwamatsu r = get_prom(dev_addr, nic.base); 697*702c85b0SNobuhiro Iwamatsu if (!r) 698*702c85b0SNobuhiro Iwamatsu return -1; 699*702c85b0SNobuhiro Iwamatsu 700*702c85b0SNobuhiro Iwamatsu sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X", 701*702c85b0SNobuhiro Iwamatsu dev_addr[0], dev_addr[1], 702*702c85b0SNobuhiro Iwamatsu dev_addr[2], dev_addr[3], 703*702c85b0SNobuhiro Iwamatsu dev_addr[4], dev_addr[5]) ; 704*702c85b0SNobuhiro Iwamatsu PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr); 705*702c85b0SNobuhiro Iwamatsu setenv ("ethaddr", ethaddr); 706*702c85b0SNobuhiro Iwamatsu 707*702c85b0SNobuhiro Iwamatsu nic.data = nic.base + DP_DATA; 708*702c85b0SNobuhiro Iwamatsu nic.tx_buf1 = START_PG; 709*702c85b0SNobuhiro Iwamatsu nic.tx_buf2 = START_PG2; 710*702c85b0SNobuhiro Iwamatsu nic.rx_buf_start = RX_START; 711*702c85b0SNobuhiro Iwamatsu nic.rx_buf_end = RX_END; 712*702c85b0SNobuhiro Iwamatsu 713*702c85b0SNobuhiro Iwamatsu if (dp83902a_init() == false) 714*702c85b0SNobuhiro Iwamatsu return -1; 715*702c85b0SNobuhiro Iwamatsu 716*702c85b0SNobuhiro Iwamatsu dp83902a_start(dev_addr); 717*702c85b0SNobuhiro Iwamatsu initialized = 1; 718*702c85b0SNobuhiro Iwamatsu 719*702c85b0SNobuhiro Iwamatsu return 0; 720*702c85b0SNobuhiro Iwamatsu } 721*702c85b0SNobuhiro Iwamatsu 722*702c85b0SNobuhiro Iwamatsu void eth_halt() { 723*702c85b0SNobuhiro Iwamatsu 724*702c85b0SNobuhiro Iwamatsu PRINTK("### eth_halt\n"); 725*702c85b0SNobuhiro Iwamatsu if(initialized) 726*702c85b0SNobuhiro Iwamatsu dp83902a_stop(); 727*702c85b0SNobuhiro Iwamatsu initialized = 0; 728*702c85b0SNobuhiro Iwamatsu } 729*702c85b0SNobuhiro Iwamatsu 730*702c85b0SNobuhiro Iwamatsu int eth_rx() { 731*702c85b0SNobuhiro Iwamatsu dp83902a_poll(); 732*702c85b0SNobuhiro Iwamatsu return 1; 733*702c85b0SNobuhiro Iwamatsu } 734*702c85b0SNobuhiro Iwamatsu 735*702c85b0SNobuhiro Iwamatsu int eth_send(volatile void *packet, int length) { 736*702c85b0SNobuhiro Iwamatsu int tmo; 737*702c85b0SNobuhiro Iwamatsu 738*702c85b0SNobuhiro Iwamatsu PRINTK("### eth_send\n"); 739*702c85b0SNobuhiro Iwamatsu 740*702c85b0SNobuhiro Iwamatsu pkey = -1; 741*702c85b0SNobuhiro Iwamatsu 742*702c85b0SNobuhiro Iwamatsu dp83902a_send((u8 *) packet, length, 666); 743*702c85b0SNobuhiro Iwamatsu tmo = get_timer (0) + TOUT * CFG_HZ; 744*702c85b0SNobuhiro Iwamatsu while(1) { 745*702c85b0SNobuhiro Iwamatsu dp83902a_poll(); 746*702c85b0SNobuhiro Iwamatsu if (pkey != -1) { 747*702c85b0SNobuhiro Iwamatsu PRINTK("Packet sucesfully sent\n"); 748*702c85b0SNobuhiro Iwamatsu return 0; 749*702c85b0SNobuhiro Iwamatsu } 750*702c85b0SNobuhiro Iwamatsu if (get_timer (0) >= tmo) { 751*702c85b0SNobuhiro Iwamatsu printf("transmission error (timoeut)\n"); 752*702c85b0SNobuhiro Iwamatsu return 0; 753*702c85b0SNobuhiro Iwamatsu } 754*702c85b0SNobuhiro Iwamatsu 755*702c85b0SNobuhiro Iwamatsu } 756*702c85b0SNobuhiro Iwamatsu return 0; 757*702c85b0SNobuhiro Iwamatsu } 758