1702c85b0SNobuhiro Iwamatsu /* 2702c85b0SNobuhiro Iwamatsu Ported to U-Boot by Christian Pellegrin <chri@ascensit.com> 3702c85b0SNobuhiro Iwamatsu 4702c85b0SNobuhiro Iwamatsu Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and 5702c85b0SNobuhiro Iwamatsu eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world 6702c85b0SNobuhiro Iwamatsu are GPL, so this is, of course, GPL. 7702c85b0SNobuhiro Iwamatsu 8702c85b0SNobuhiro Iwamatsu ========================================================================== 9702c85b0SNobuhiro Iwamatsu 10702c85b0SNobuhiro Iwamatsu dev/if_dp83902a.c 11702c85b0SNobuhiro Iwamatsu 12702c85b0SNobuhiro Iwamatsu Ethernet device driver for NS DP83902a ethernet controller 13702c85b0SNobuhiro Iwamatsu 14702c85b0SNobuhiro Iwamatsu ========================================================================== 15702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTBEGIN#### 16702c85b0SNobuhiro Iwamatsu ------------------------------------------- 17702c85b0SNobuhiro Iwamatsu This file is part of eCos, the Embedded Configurable Operating System. 18702c85b0SNobuhiro Iwamatsu Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. 19702c85b0SNobuhiro Iwamatsu 20702c85b0SNobuhiro Iwamatsu eCos is free software; you can redistribute it and/or modify it under 21702c85b0SNobuhiro Iwamatsu the terms of the GNU General Public License as published by the Free 22702c85b0SNobuhiro Iwamatsu Software Foundation; either version 2 or (at your option) any later version. 23702c85b0SNobuhiro Iwamatsu 24702c85b0SNobuhiro Iwamatsu eCos is distributed in the hope that it will be useful, but WITHOUT ANY 25702c85b0SNobuhiro Iwamatsu WARRANTY; without even the implied warranty of MERCHANTABILITY or 26702c85b0SNobuhiro Iwamatsu FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 27702c85b0SNobuhiro Iwamatsu for more details. 28702c85b0SNobuhiro Iwamatsu 29702c85b0SNobuhiro Iwamatsu You should have received a copy of the GNU General Public License along 30702c85b0SNobuhiro Iwamatsu with eCos; if not, write to the Free Software Foundation, Inc., 31702c85b0SNobuhiro Iwamatsu 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 32702c85b0SNobuhiro Iwamatsu 33702c85b0SNobuhiro Iwamatsu As a special exception, if other files instantiate templates or use macros 34702c85b0SNobuhiro Iwamatsu or inline functions from this file, or you compile this file and link it 35702c85b0SNobuhiro Iwamatsu with other works to produce a work based on this file, this file does not 36702c85b0SNobuhiro Iwamatsu by itself cause the resulting work to be covered by the GNU General Public 37702c85b0SNobuhiro Iwamatsu License. However the source code for this file must still be made available 38702c85b0SNobuhiro Iwamatsu in accordance with section (3) of the GNU General Public License. 39702c85b0SNobuhiro Iwamatsu 40702c85b0SNobuhiro Iwamatsu This exception does not invalidate any other reasons why a work based on 41702c85b0SNobuhiro Iwamatsu this file might be covered by the GNU General Public License. 42702c85b0SNobuhiro Iwamatsu 43702c85b0SNobuhiro Iwamatsu Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. 44702c85b0SNobuhiro Iwamatsu at http://sources.redhat.com/ecos/ecos-license/ 45702c85b0SNobuhiro Iwamatsu ------------------------------------------- 46702c85b0SNobuhiro Iwamatsu ####ECOSGPLCOPYRIGHTEND#### 47702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTBEGIN#### 48702c85b0SNobuhiro Iwamatsu 49702c85b0SNobuhiro Iwamatsu ------------------------------------------- 50702c85b0SNobuhiro Iwamatsu 51702c85b0SNobuhiro Iwamatsu Portions of this software may have been derived from OpenBSD or other sources, 52702c85b0SNobuhiro Iwamatsu and are covered by the appropriate copyright disclaimers included herein. 53702c85b0SNobuhiro Iwamatsu 54702c85b0SNobuhiro Iwamatsu ------------------------------------------- 55702c85b0SNobuhiro Iwamatsu 56702c85b0SNobuhiro Iwamatsu ####BSDCOPYRIGHTEND#### 57702c85b0SNobuhiro Iwamatsu ========================================================================== 58702c85b0SNobuhiro Iwamatsu #####DESCRIPTIONBEGIN#### 59702c85b0SNobuhiro Iwamatsu 60702c85b0SNobuhiro Iwamatsu Author(s): gthomas 61702c85b0SNobuhiro Iwamatsu Contributors: gthomas, jskov, rsandifo 62702c85b0SNobuhiro Iwamatsu Date: 2001-06-13 63702c85b0SNobuhiro Iwamatsu Purpose: 64702c85b0SNobuhiro Iwamatsu Description: 65702c85b0SNobuhiro Iwamatsu 66702c85b0SNobuhiro Iwamatsu FIXME: Will fail if pinged with large packets (1520 bytes) 67702c85b0SNobuhiro Iwamatsu Add promisc config 68702c85b0SNobuhiro Iwamatsu Add SNMP 69702c85b0SNobuhiro Iwamatsu 70702c85b0SNobuhiro Iwamatsu ####DESCRIPTIONEND#### 71702c85b0SNobuhiro Iwamatsu 72702c85b0SNobuhiro Iwamatsu ========================================================================== 73702c85b0SNobuhiro Iwamatsu */ 74702c85b0SNobuhiro Iwamatsu 75702c85b0SNobuhiro Iwamatsu #include <common.h> 76702c85b0SNobuhiro Iwamatsu #include <command.h> 77702c85b0SNobuhiro Iwamatsu #include <net.h> 78702c85b0SNobuhiro Iwamatsu #include <malloc.h> 79702c85b0SNobuhiro Iwamatsu 80702c85b0SNobuhiro Iwamatsu #define mdelay(n) udelay((n)*1000) 81702c85b0SNobuhiro Iwamatsu /* forward definition of function used for the uboot interface */ 82702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len); 83702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val); 84702c85b0SNobuhiro Iwamatsu 85702c85b0SNobuhiro Iwamatsu /* NE2000 base header file */ 86702c85b0SNobuhiro Iwamatsu #include "ne2000_base.h" 87702c85b0SNobuhiro Iwamatsu 88702c85b0SNobuhiro Iwamatsu #if defined(CONFIG_DRIVER_AX88796L) 89702c85b0SNobuhiro Iwamatsu /* AX88796L support */ 90702c85b0SNobuhiro Iwamatsu #include "ax88796.h" 91702c85b0SNobuhiro Iwamatsu #else 92702c85b0SNobuhiro Iwamatsu /* Basic NE2000 chip support */ 93702c85b0SNobuhiro Iwamatsu #include "ne2000.h" 94702c85b0SNobuhiro Iwamatsu #endif 95702c85b0SNobuhiro Iwamatsu 96702c85b0SNobuhiro Iwamatsu static dp83902a_priv_data_t nic; /* just one instance of the card supported */ 97702c85b0SNobuhiro Iwamatsu 98702c85b0SNobuhiro Iwamatsu static bool 99702c85b0SNobuhiro Iwamatsu dp83902a_init(void) 100702c85b0SNobuhiro Iwamatsu { 101702c85b0SNobuhiro Iwamatsu dp83902a_priv_data_t *dp = &nic; 102702c85b0SNobuhiro Iwamatsu u8* base; 103702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT) 104702c85b0SNobuhiro Iwamatsu int i; 105702c85b0SNobuhiro Iwamatsu #endif 106702c85b0SNobuhiro Iwamatsu 107702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 108702c85b0SNobuhiro Iwamatsu 109702c85b0SNobuhiro Iwamatsu base = dp->base; 110702c85b0SNobuhiro Iwamatsu if (!base) 111702c85b0SNobuhiro Iwamatsu return false; /* No device found */ 112702c85b0SNobuhiro Iwamatsu 113702c85b0SNobuhiro Iwamatsu DEBUG_LINE(); 114702c85b0SNobuhiro Iwamatsu 115702c85b0SNobuhiro Iwamatsu #if defined(NE2000_BASIC_INIT) 116702c85b0SNobuhiro Iwamatsu /* AX88796L doesn't need */ 117702c85b0SNobuhiro Iwamatsu /* Prepare ESA */ 118702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */ 119702c85b0SNobuhiro Iwamatsu /* Use the address from the serial EEPROM */ 120702c85b0SNobuhiro Iwamatsu for (i = 0; i < 6; i++) 121702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_P1_PAR0+i, dp->esa[i]); 122702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */ 123702c85b0SNobuhiro Iwamatsu 124702c85b0SNobuhiro Iwamatsu printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", 125702c85b0SNobuhiro Iwamatsu "eeprom", 126702c85b0SNobuhiro Iwamatsu dp->esa[0], 127702c85b0SNobuhiro Iwamatsu dp->esa[1], 128702c85b0SNobuhiro Iwamatsu dp->esa[2], 129702c85b0SNobuhiro Iwamatsu dp->esa[3], 130702c85b0SNobuhiro Iwamatsu dp->esa[4], 131702c85b0SNobuhiro Iwamatsu dp->esa[5] ); 132702c85b0SNobuhiro Iwamatsu 133702c85b0SNobuhiro Iwamatsu #endif /* NE2000_BASIC_INIT */ 134702c85b0SNobuhiro Iwamatsu return true; 135702c85b0SNobuhiro Iwamatsu } 136702c85b0SNobuhiro Iwamatsu 137702c85b0SNobuhiro Iwamatsu static void 138702c85b0SNobuhiro Iwamatsu dp83902a_stop(void) 139702c85b0SNobuhiro Iwamatsu { 140702c85b0SNobuhiro Iwamatsu dp83902a_priv_data_t *dp = &nic; 141702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 142702c85b0SNobuhiro Iwamatsu 143702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 144702c85b0SNobuhiro Iwamatsu 145702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ 146702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ 147702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */ 148702c85b0SNobuhiro Iwamatsu 149702c85b0SNobuhiro Iwamatsu dp->running = false; 150702c85b0SNobuhiro Iwamatsu } 151702c85b0SNobuhiro Iwamatsu 152702c85b0SNobuhiro Iwamatsu /* 153702c85b0SNobuhiro Iwamatsu * This function is called to "start up" the interface. It may be called 154702c85b0SNobuhiro Iwamatsu * multiple times, even when the hardware is already running. It will be 155702c85b0SNobuhiro Iwamatsu * called whenever something "hardware oriented" changes and should leave 156702c85b0SNobuhiro Iwamatsu * the hardware ready to send/receive packets. 157702c85b0SNobuhiro Iwamatsu */ 158702c85b0SNobuhiro Iwamatsu static void 159702c85b0SNobuhiro Iwamatsu dp83902a_start(u8 * enaddr) 160702c85b0SNobuhiro Iwamatsu { 161702c85b0SNobuhiro Iwamatsu dp83902a_priv_data_t *dp = &nic; 162702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 163702c85b0SNobuhiro Iwamatsu int i; 164702c85b0SNobuhiro Iwamatsu 165702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 166702c85b0SNobuhiro Iwamatsu 167702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */ 168702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_DCR, DP_DCR_INIT); 169702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, 0); /* Remote byte count */ 170702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, 0); 171702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */ 172702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */ 173702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */ 174702c85b0SNobuhiro Iwamatsu dp->tx1 = dp->tx2 = 0; 175702c85b0SNobuhiro Iwamatsu dp->tx_next = dp->tx_buf1; 176702c85b0SNobuhiro Iwamatsu dp->tx_started = false; 177702c85b0SNobuhiro Iwamatsu dp->running = true; 178702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */ 179702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */ 180702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */ 181702c85b0SNobuhiro Iwamatsu dp->rx_next = dp->rx_buf_start - 1; 182702c85b0SNobuhiro Iwamatsu dp->running = true; 183702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */ 184702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */ 185702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */ 186702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */ 187702c85b0SNobuhiro Iwamatsu dp->running = true; 188702c85b0SNobuhiro Iwamatsu for (i = 0; i < ETHER_ADDR_LEN; i++) { 189702c85b0SNobuhiro Iwamatsu /* FIXME */ 190702c85b0SNobuhiro Iwamatsu /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) + 191702c85b0SNobuhiro Iwamatsu * 0x1400)) = enaddr[i];*/ 192702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_P1_PAR0+i, enaddr[i]); 193702c85b0SNobuhiro Iwamatsu } 194702c85b0SNobuhiro Iwamatsu /* Enable and start device */ 195702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 196702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */ 197702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */ 198702c85b0SNobuhiro Iwamatsu dp->running = true; 199702c85b0SNobuhiro Iwamatsu } 200702c85b0SNobuhiro Iwamatsu 201702c85b0SNobuhiro Iwamatsu /* 202702c85b0SNobuhiro Iwamatsu * This routine is called to start the transmitter. It is split out from the 203702c85b0SNobuhiro Iwamatsu * data handling routine so it may be called either when data becomes first 204702c85b0SNobuhiro Iwamatsu * available or when an Tx interrupt occurs 205702c85b0SNobuhiro Iwamatsu */ 206702c85b0SNobuhiro Iwamatsu 207702c85b0SNobuhiro Iwamatsu static void 208702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(int start_page, int len) 209702c85b0SNobuhiro Iwamatsu { 210702c85b0SNobuhiro Iwamatsu dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic; 211702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 212702c85b0SNobuhiro Iwamatsu 213702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 214702c85b0SNobuhiro Iwamatsu 215702c85b0SNobuhiro Iwamatsu #if DEBUG & 1 216702c85b0SNobuhiro Iwamatsu printf("Tx pkt %d len %d\n", start_page, len); 217702c85b0SNobuhiro Iwamatsu if (dp->tx_started) 218702c85b0SNobuhiro Iwamatsu printf("TX already started?!?\n"); 219702c85b0SNobuhiro Iwamatsu #endif 220702c85b0SNobuhiro Iwamatsu 221702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE)); 222702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 223702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TBCL, len & 0xFF); 224702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TBCH, len >> 8); 225702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TPSR, start_page); 226702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); 227702c85b0SNobuhiro Iwamatsu 228702c85b0SNobuhiro Iwamatsu dp->tx_started = true; 229702c85b0SNobuhiro Iwamatsu } 230702c85b0SNobuhiro Iwamatsu 231702c85b0SNobuhiro Iwamatsu /* 232702c85b0SNobuhiro Iwamatsu * This routine is called to send data to the hardware. It is known a-priori 233702c85b0SNobuhiro Iwamatsu * that there is free buffer space (dp->tx_next). 234702c85b0SNobuhiro Iwamatsu */ 235702c85b0SNobuhiro Iwamatsu static void 236702c85b0SNobuhiro Iwamatsu dp83902a_send(u8 *data, int total_len, u32 key) 237702c85b0SNobuhiro Iwamatsu { 238702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 239702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 240702c85b0SNobuhiro Iwamatsu int len, start_page, pkt_len, i, isr; 241702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 242702c85b0SNobuhiro Iwamatsu int dx; 243702c85b0SNobuhiro Iwamatsu #endif 244702c85b0SNobuhiro Iwamatsu 245702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 246702c85b0SNobuhiro Iwamatsu 247702c85b0SNobuhiro Iwamatsu len = pkt_len = total_len; 248702c85b0SNobuhiro Iwamatsu if (pkt_len < IEEE_8023_MIN_FRAME) 249702c85b0SNobuhiro Iwamatsu pkt_len = IEEE_8023_MIN_FRAME; 250702c85b0SNobuhiro Iwamatsu 251702c85b0SNobuhiro Iwamatsu start_page = dp->tx_next; 252702c85b0SNobuhiro Iwamatsu if (dp->tx_next == dp->tx_buf1) { 253702c85b0SNobuhiro Iwamatsu dp->tx1 = start_page; 254702c85b0SNobuhiro Iwamatsu dp->tx1_len = pkt_len; 255702c85b0SNobuhiro Iwamatsu dp->tx1_key = key; 256702c85b0SNobuhiro Iwamatsu dp->tx_next = dp->tx_buf2; 257702c85b0SNobuhiro Iwamatsu } else { 258702c85b0SNobuhiro Iwamatsu dp->tx2 = start_page; 259702c85b0SNobuhiro Iwamatsu dp->tx2_len = pkt_len; 260702c85b0SNobuhiro Iwamatsu dp->tx2_key = key; 261702c85b0SNobuhiro Iwamatsu dp->tx_next = dp->tx_buf1; 262702c85b0SNobuhiro Iwamatsu } 263702c85b0SNobuhiro Iwamatsu 264702c85b0SNobuhiro Iwamatsu #if DEBUG & 5 265702c85b0SNobuhiro Iwamatsu printf("TX prep page %d len %d\n", start_page, pkt_len); 266702c85b0SNobuhiro Iwamatsu #endif 267702c85b0SNobuhiro Iwamatsu 268702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ 269702c85b0SNobuhiro Iwamatsu { 270702c85b0SNobuhiro Iwamatsu /* 271702c85b0SNobuhiro Iwamatsu * Dummy read. The manual sez something slightly different, 272702c85b0SNobuhiro Iwamatsu * but the code is extended a bit to do what Hitachi's monitor 273702c85b0SNobuhiro Iwamatsu * does (i.e., also read data). 274702c85b0SNobuhiro Iwamatsu */ 275702c85b0SNobuhiro Iwamatsu 276702c85b0SNobuhiro Iwamatsu u16 tmp; 277702c85b0SNobuhiro Iwamatsu int len = 1; 278702c85b0SNobuhiro Iwamatsu 279702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAL, 0x100 - len); 280702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff); 281702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, len); 282702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, 0); 283702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START); 284702c85b0SNobuhiro Iwamatsu DP_IN_DATA(dp->data, tmp); 285702c85b0SNobuhiro Iwamatsu } 286702c85b0SNobuhiro Iwamatsu 287702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA 288702c85b0SNobuhiro Iwamatsu /* 289702c85b0SNobuhiro Iwamatsu * Stall for a bit before continuing to work around random data 290702c85b0SNobuhiro Iwamatsu * corruption problems on some platforms. 291702c85b0SNobuhiro Iwamatsu */ 292702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(1); 293702c85b0SNobuhiro Iwamatsu #endif 294702c85b0SNobuhiro Iwamatsu 295702c85b0SNobuhiro Iwamatsu /* Send data to device buffer(s) */ 296702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAL, 0); 297702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAH, start_page); 298702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, pkt_len & 0xFF); 299702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, pkt_len >> 8); 300702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START); 301702c85b0SNobuhiro Iwamatsu 302702c85b0SNobuhiro Iwamatsu /* Put data into buffer */ 303702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 304702c85b0SNobuhiro Iwamatsu printf(" sg buf %08lx len %08x\n ", (u32)data, len); 305702c85b0SNobuhiro Iwamatsu dx = 0; 306702c85b0SNobuhiro Iwamatsu #endif 307702c85b0SNobuhiro Iwamatsu while (len > 0) { 308702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 309702c85b0SNobuhiro Iwamatsu printf(" %02x", *data); 310702c85b0SNobuhiro Iwamatsu if (0 == (++dx % 16)) printf("\n "); 311702c85b0SNobuhiro Iwamatsu #endif 312702c85b0SNobuhiro Iwamatsu 313702c85b0SNobuhiro Iwamatsu DP_OUT_DATA(dp->data, *data++); 314702c85b0SNobuhiro Iwamatsu len--; 315702c85b0SNobuhiro Iwamatsu } 316702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 317702c85b0SNobuhiro Iwamatsu printf("\n"); 318702c85b0SNobuhiro Iwamatsu #endif 319702c85b0SNobuhiro Iwamatsu if (total_len < pkt_len) { 320702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 321702c85b0SNobuhiro Iwamatsu printf(" + %d bytes of padding\n", pkt_len - total_len); 322702c85b0SNobuhiro Iwamatsu #endif 323702c85b0SNobuhiro Iwamatsu /* Padding to 802.3 length was required */ 324702c85b0SNobuhiro Iwamatsu for (i = total_len; i < pkt_len;) { 325702c85b0SNobuhiro Iwamatsu i++; 326702c85b0SNobuhiro Iwamatsu DP_OUT_DATA(dp->data, 0); 327702c85b0SNobuhiro Iwamatsu } 328702c85b0SNobuhiro Iwamatsu } 329702c85b0SNobuhiro Iwamatsu 330702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA 331702c85b0SNobuhiro Iwamatsu /* 332702c85b0SNobuhiro Iwamatsu * After last data write, delay for a bit before accessing the 333702c85b0SNobuhiro Iwamatsu * device again, or we may get random data corruption in the last 334702c85b0SNobuhiro Iwamatsu * datum (on some platforms). 335702c85b0SNobuhiro Iwamatsu */ 336702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(1); 337702c85b0SNobuhiro Iwamatsu #endif 338702c85b0SNobuhiro Iwamatsu 339702c85b0SNobuhiro Iwamatsu /* Wait for DMA to complete */ 340702c85b0SNobuhiro Iwamatsu do { 341702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_ISR, isr); 342702c85b0SNobuhiro Iwamatsu } while ((isr & DP_ISR_RDC) == 0); 343702c85b0SNobuhiro Iwamatsu 344702c85b0SNobuhiro Iwamatsu /* Then disable DMA */ 345702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 346702c85b0SNobuhiro Iwamatsu 347702c85b0SNobuhiro Iwamatsu /* Start transmit if not already going */ 348702c85b0SNobuhiro Iwamatsu if (!dp->tx_started) { 349702c85b0SNobuhiro Iwamatsu if (start_page == dp->tx1) { 350702c85b0SNobuhiro Iwamatsu dp->tx_int = 1; /* Expecting interrupt from BUF1 */ 351702c85b0SNobuhiro Iwamatsu } else { 352702c85b0SNobuhiro Iwamatsu dp->tx_int = 2; /* Expecting interrupt from BUF2 */ 353702c85b0SNobuhiro Iwamatsu } 354702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(start_page, pkt_len); 355702c85b0SNobuhiro Iwamatsu } 356702c85b0SNobuhiro Iwamatsu } 357702c85b0SNobuhiro Iwamatsu 358702c85b0SNobuhiro Iwamatsu /* 359702c85b0SNobuhiro Iwamatsu * This function is called when a packet has been received. It's job is 360702c85b0SNobuhiro Iwamatsu * to prepare to unload the packet from the hardware. Once the length of 361702c85b0SNobuhiro Iwamatsu * the packet is known, the upper layer of the driver can be told. When 362702c85b0SNobuhiro Iwamatsu * the upper layer is ready to unload the packet, the internal function 363702c85b0SNobuhiro Iwamatsu * 'dp83902a_recv' will be called to actually fetch it from the hardware. 364702c85b0SNobuhiro Iwamatsu */ 365702c85b0SNobuhiro Iwamatsu static void 366702c85b0SNobuhiro Iwamatsu dp83902a_RxEvent(void) 367702c85b0SNobuhiro Iwamatsu { 368702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 369702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 370702c85b0SNobuhiro Iwamatsu u8 rsr; 371702c85b0SNobuhiro Iwamatsu u8 rcv_hdr[4]; 372702c85b0SNobuhiro Iwamatsu int i, len, pkt, cur; 373702c85b0SNobuhiro Iwamatsu 374702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 375702c85b0SNobuhiro Iwamatsu 376702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_RSR, rsr); 377702c85b0SNobuhiro Iwamatsu while (true) { 378702c85b0SNobuhiro Iwamatsu /* Read incoming packet header */ 379702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START); 380702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_P1_CURP, cur); 381702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 382702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_BNDRY, pkt); 383702c85b0SNobuhiro Iwamatsu 384702c85b0SNobuhiro Iwamatsu pkt += 1; 385702c85b0SNobuhiro Iwamatsu if (pkt == dp->rx_buf_end) 386702c85b0SNobuhiro Iwamatsu pkt = dp->rx_buf_start; 387702c85b0SNobuhiro Iwamatsu 388702c85b0SNobuhiro Iwamatsu if (pkt == cur) { 389702c85b0SNobuhiro Iwamatsu break; 390702c85b0SNobuhiro Iwamatsu } 391702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, sizeof(rcv_hdr)); 392702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, 0); 393702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAL, 0); 394702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAH, pkt); 395702c85b0SNobuhiro Iwamatsu if (dp->rx_next == pkt) { 396702c85b0SNobuhiro Iwamatsu if (cur == dp->rx_buf_start) 397702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); 398702c85b0SNobuhiro Iwamatsu else 399702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */ 400702c85b0SNobuhiro Iwamatsu return; 401702c85b0SNobuhiro Iwamatsu } 402702c85b0SNobuhiro Iwamatsu dp->rx_next = pkt; 403702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ 404702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); 405702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA 406702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(10); 407702c85b0SNobuhiro Iwamatsu #endif 408702c85b0SNobuhiro Iwamatsu 409702c85b0SNobuhiro Iwamatsu /* read header (get data size)*/ 410702c85b0SNobuhiro Iwamatsu for (i = 0; i < sizeof(rcv_hdr);) { 411702c85b0SNobuhiro Iwamatsu DP_IN_DATA(dp->data, rcv_hdr[i++]); 412702c85b0SNobuhiro Iwamatsu } 413702c85b0SNobuhiro Iwamatsu 414702c85b0SNobuhiro Iwamatsu #if DEBUG & 5 415702c85b0SNobuhiro Iwamatsu printf("rx hdr %02x %02x %02x %02x\n", 416702c85b0SNobuhiro Iwamatsu rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]); 417702c85b0SNobuhiro Iwamatsu #endif 418702c85b0SNobuhiro Iwamatsu len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr); 419702c85b0SNobuhiro Iwamatsu 420702c85b0SNobuhiro Iwamatsu /* data read */ 421702c85b0SNobuhiro Iwamatsu uboot_push_packet_len(len); 422702c85b0SNobuhiro Iwamatsu 423702c85b0SNobuhiro Iwamatsu if (rcv_hdr[1] == dp->rx_buf_start) 424702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); 425702c85b0SNobuhiro Iwamatsu else 426702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */ 427702c85b0SNobuhiro Iwamatsu } 428702c85b0SNobuhiro Iwamatsu } 429702c85b0SNobuhiro Iwamatsu 430702c85b0SNobuhiro Iwamatsu /* 431702c85b0SNobuhiro Iwamatsu * This function is called as a result of the "eth_drv_recv()" call above. 432702c85b0SNobuhiro Iwamatsu * It's job is to actually fetch data for a packet from the hardware once 433702c85b0SNobuhiro Iwamatsu * memory buffers have been allocated for the packet. Note that the buffers 434702c85b0SNobuhiro Iwamatsu * may come in pieces, using a scatter-gather list. This allows for more 435702c85b0SNobuhiro Iwamatsu * efficient processing in the upper layers of the stack. 436702c85b0SNobuhiro Iwamatsu */ 437702c85b0SNobuhiro Iwamatsu static void 438702c85b0SNobuhiro Iwamatsu dp83902a_recv(u8 *data, int len) 439702c85b0SNobuhiro Iwamatsu { 440702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 441702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 442702c85b0SNobuhiro Iwamatsu int i, mlen; 443702c85b0SNobuhiro Iwamatsu u8 saved_char = 0; 444702c85b0SNobuhiro Iwamatsu bool saved; 445702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 446702c85b0SNobuhiro Iwamatsu int dx; 447702c85b0SNobuhiro Iwamatsu #endif 448702c85b0SNobuhiro Iwamatsu 449702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 450702c85b0SNobuhiro Iwamatsu 451702c85b0SNobuhiro Iwamatsu #if DEBUG & 5 452702c85b0SNobuhiro Iwamatsu printf("Rx packet %d length %d\n", dp->rx_next, len); 453702c85b0SNobuhiro Iwamatsu #endif 454702c85b0SNobuhiro Iwamatsu 455702c85b0SNobuhiro Iwamatsu /* Read incoming packet data */ 456702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START); 457702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, len & 0xFF); 458702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, len >> 8); 459702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAL, 4); /* Past header */ 460702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RSAH, dp->rx_next); 461702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */ 462702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START); 463702c85b0SNobuhiro Iwamatsu #ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA 464702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(10); 465702c85b0SNobuhiro Iwamatsu #endif 466702c85b0SNobuhiro Iwamatsu 467702c85b0SNobuhiro Iwamatsu saved = false; 468702c85b0SNobuhiro Iwamatsu for (i = 0; i < 1; i++) { 469702c85b0SNobuhiro Iwamatsu if (data) { 470702c85b0SNobuhiro Iwamatsu mlen = len; 471702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 472702c85b0SNobuhiro Iwamatsu printf(" sg buf %08lx len %08x \n", (u32) data, mlen); 473702c85b0SNobuhiro Iwamatsu dx = 0; 474702c85b0SNobuhiro Iwamatsu #endif 475702c85b0SNobuhiro Iwamatsu while (0 < mlen) { 476702c85b0SNobuhiro Iwamatsu /* Saved byte from previous loop? */ 477702c85b0SNobuhiro Iwamatsu if (saved) { 478702c85b0SNobuhiro Iwamatsu *data++ = saved_char; 479702c85b0SNobuhiro Iwamatsu mlen--; 480702c85b0SNobuhiro Iwamatsu saved = false; 481702c85b0SNobuhiro Iwamatsu continue; 482702c85b0SNobuhiro Iwamatsu } 483702c85b0SNobuhiro Iwamatsu 484702c85b0SNobuhiro Iwamatsu { 485702c85b0SNobuhiro Iwamatsu u8 tmp; 486702c85b0SNobuhiro Iwamatsu DP_IN_DATA(dp->data, tmp); 487702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 488702c85b0SNobuhiro Iwamatsu printf(" %02x", tmp); 489702c85b0SNobuhiro Iwamatsu if (0 == (++dx % 16)) printf("\n "); 490702c85b0SNobuhiro Iwamatsu #endif 491702c85b0SNobuhiro Iwamatsu *data++ = tmp;; 492702c85b0SNobuhiro Iwamatsu mlen--; 493702c85b0SNobuhiro Iwamatsu } 494702c85b0SNobuhiro Iwamatsu } 495702c85b0SNobuhiro Iwamatsu #if DEBUG & 4 496702c85b0SNobuhiro Iwamatsu printf("\n"); 497702c85b0SNobuhiro Iwamatsu #endif 498702c85b0SNobuhiro Iwamatsu } 499702c85b0SNobuhiro Iwamatsu } 500702c85b0SNobuhiro Iwamatsu } 501702c85b0SNobuhiro Iwamatsu 502702c85b0SNobuhiro Iwamatsu static void 503702c85b0SNobuhiro Iwamatsu dp83902a_TxEvent(void) 504702c85b0SNobuhiro Iwamatsu { 505702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 506702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 507702c85b0SNobuhiro Iwamatsu u8 tsr; 508702c85b0SNobuhiro Iwamatsu u32 key; 509702c85b0SNobuhiro Iwamatsu 510702c85b0SNobuhiro Iwamatsu DEBUG_FUNCTION(); 511702c85b0SNobuhiro Iwamatsu 512702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_TSR, tsr); 513702c85b0SNobuhiro Iwamatsu if (dp->tx_int == 1) { 514702c85b0SNobuhiro Iwamatsu key = dp->tx1_key; 515702c85b0SNobuhiro Iwamatsu dp->tx1 = 0; 516702c85b0SNobuhiro Iwamatsu } else { 517702c85b0SNobuhiro Iwamatsu key = dp->tx2_key; 518702c85b0SNobuhiro Iwamatsu dp->tx2 = 0; 519702c85b0SNobuhiro Iwamatsu } 520702c85b0SNobuhiro Iwamatsu /* Start next packet if one is ready */ 521702c85b0SNobuhiro Iwamatsu dp->tx_started = false; 522702c85b0SNobuhiro Iwamatsu if (dp->tx1) { 523702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(dp->tx1, dp->tx1_len); 524702c85b0SNobuhiro Iwamatsu dp->tx_int = 1; 525702c85b0SNobuhiro Iwamatsu } else if (dp->tx2) { 526702c85b0SNobuhiro Iwamatsu dp83902a_start_xmit(dp->tx2, dp->tx2_len); 527702c85b0SNobuhiro Iwamatsu dp->tx_int = 2; 528702c85b0SNobuhiro Iwamatsu } else { 529702c85b0SNobuhiro Iwamatsu dp->tx_int = 0; 530702c85b0SNobuhiro Iwamatsu } 531702c85b0SNobuhiro Iwamatsu /* Tell higher level we sent this packet */ 532702c85b0SNobuhiro Iwamatsu uboot_push_tx_done(key, 0); 533702c85b0SNobuhiro Iwamatsu } 534702c85b0SNobuhiro Iwamatsu 535702c85b0SNobuhiro Iwamatsu /* 536702c85b0SNobuhiro Iwamatsu * Read the tally counters to clear them. Called in response to a CNT 537702c85b0SNobuhiro Iwamatsu * interrupt. 538702c85b0SNobuhiro Iwamatsu */ 539702c85b0SNobuhiro Iwamatsu static void 540702c85b0SNobuhiro Iwamatsu dp83902a_ClearCounters(void) 541702c85b0SNobuhiro Iwamatsu { 542702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 543702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 544702c85b0SNobuhiro Iwamatsu u8 cnt1, cnt2, cnt3; 545702c85b0SNobuhiro Iwamatsu 546702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_FER, cnt1); 547702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_CER, cnt2); 548702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_MISSED, cnt3); 549702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_CNT); 550702c85b0SNobuhiro Iwamatsu } 551702c85b0SNobuhiro Iwamatsu 552702c85b0SNobuhiro Iwamatsu /* 553702c85b0SNobuhiro Iwamatsu * Deal with an overflow condition. This code follows the procedure set 554702c85b0SNobuhiro Iwamatsu * out in section 7.0 of the datasheet. 555702c85b0SNobuhiro Iwamatsu */ 556702c85b0SNobuhiro Iwamatsu static void 557702c85b0SNobuhiro Iwamatsu dp83902a_Overflow(void) 558702c85b0SNobuhiro Iwamatsu { 559702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic; 560702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 561702c85b0SNobuhiro Iwamatsu u8 isr; 562702c85b0SNobuhiro Iwamatsu 563702c85b0SNobuhiro Iwamatsu /* Issue a stop command and wait 1.6ms for it to complete. */ 564702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA); 565702c85b0SNobuhiro Iwamatsu CYGACC_CALL_IF_DELAY_US(1600); 566702c85b0SNobuhiro Iwamatsu 567702c85b0SNobuhiro Iwamatsu /* Clear the remote byte counter registers. */ 568702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCL, 0); 569702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_RBCH, 0); 570702c85b0SNobuhiro Iwamatsu 571702c85b0SNobuhiro Iwamatsu /* Enter loopback mode while we clear the buffer. */ 572702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TCR, DP_TCR_LOCAL); 573702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA); 574702c85b0SNobuhiro Iwamatsu 575702c85b0SNobuhiro Iwamatsu /* 576702c85b0SNobuhiro Iwamatsu * Read in as many packets as we can and acknowledge any and receive 577702c85b0SNobuhiro Iwamatsu * interrupts. Since the buffer has overflowed, a receive event of 578702c85b0SNobuhiro Iwamatsu * some kind will have occured. 579702c85b0SNobuhiro Iwamatsu */ 580702c85b0SNobuhiro Iwamatsu dp83902a_RxEvent(); 581702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE); 582702c85b0SNobuhiro Iwamatsu 583702c85b0SNobuhiro Iwamatsu /* Clear the overflow condition and leave loopback mode. */ 584702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, DP_ISR_OFLW); 585702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_TCR, DP_TCR_NORMAL); 586702c85b0SNobuhiro Iwamatsu 587702c85b0SNobuhiro Iwamatsu /* 588702c85b0SNobuhiro Iwamatsu * If a transmit command was issued, but no transmit event has occured, 589702c85b0SNobuhiro Iwamatsu * restart it here. 590702c85b0SNobuhiro Iwamatsu */ 591702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_ISR, isr); 592702c85b0SNobuhiro Iwamatsu if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) { 593702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START); 594702c85b0SNobuhiro Iwamatsu } 595702c85b0SNobuhiro Iwamatsu } 596702c85b0SNobuhiro Iwamatsu 597702c85b0SNobuhiro Iwamatsu static void 598702c85b0SNobuhiro Iwamatsu dp83902a_poll(void) 599702c85b0SNobuhiro Iwamatsu { 600702c85b0SNobuhiro Iwamatsu struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic; 601702c85b0SNobuhiro Iwamatsu u8 *base = dp->base; 602702c85b0SNobuhiro Iwamatsu u8 isr; 603702c85b0SNobuhiro Iwamatsu 604702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START); 605702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_ISR, isr); 606702c85b0SNobuhiro Iwamatsu while (0 != isr) { 607702c85b0SNobuhiro Iwamatsu /* 608702c85b0SNobuhiro Iwamatsu * The CNT interrupt triggers when the MSB of one of the error 609702c85b0SNobuhiro Iwamatsu * counters is set. We don't much care about these counters, but 610702c85b0SNobuhiro Iwamatsu * we should read their values to reset them. 611702c85b0SNobuhiro Iwamatsu */ 612702c85b0SNobuhiro Iwamatsu if (isr & DP_ISR_CNT) { 613702c85b0SNobuhiro Iwamatsu dp83902a_ClearCounters(); 614702c85b0SNobuhiro Iwamatsu } 615702c85b0SNobuhiro Iwamatsu /* 616702c85b0SNobuhiro Iwamatsu * Check for overflow. It's a special case, since there's a 617702c85b0SNobuhiro Iwamatsu * particular procedure that must be followed to get back into 618702c85b0SNobuhiro Iwamatsu * a running state.a 619702c85b0SNobuhiro Iwamatsu */ 620702c85b0SNobuhiro Iwamatsu if (isr & DP_ISR_OFLW) { 621702c85b0SNobuhiro Iwamatsu dp83902a_Overflow(); 622702c85b0SNobuhiro Iwamatsu } else { 623702c85b0SNobuhiro Iwamatsu /* 624702c85b0SNobuhiro Iwamatsu * Other kinds of interrupts can be acknowledged simply by 625702c85b0SNobuhiro Iwamatsu * clearing the relevant bits of the ISR. Do that now, then 626702c85b0SNobuhiro Iwamatsu * handle the interrupts we care about. 627702c85b0SNobuhiro Iwamatsu */ 628702c85b0SNobuhiro Iwamatsu DP_OUT(base, DP_ISR, isr); /* Clear set bits */ 629702c85b0SNobuhiro Iwamatsu if (!dp->running) break; /* Is this necessary? */ 630702c85b0SNobuhiro Iwamatsu /* 631702c85b0SNobuhiro Iwamatsu * Check for tx_started on TX event since these may happen 632702c85b0SNobuhiro Iwamatsu * spuriously it seems. 633702c85b0SNobuhiro Iwamatsu */ 634702c85b0SNobuhiro Iwamatsu if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) { 635702c85b0SNobuhiro Iwamatsu dp83902a_TxEvent(); 636702c85b0SNobuhiro Iwamatsu } 637702c85b0SNobuhiro Iwamatsu if (isr & (DP_ISR_RxP|DP_ISR_RxE)) { 638702c85b0SNobuhiro Iwamatsu dp83902a_RxEvent(); 639702c85b0SNobuhiro Iwamatsu } 640702c85b0SNobuhiro Iwamatsu } 641702c85b0SNobuhiro Iwamatsu DP_IN(base, DP_ISR, isr); 642702c85b0SNobuhiro Iwamatsu } 643702c85b0SNobuhiro Iwamatsu } 644702c85b0SNobuhiro Iwamatsu 645702c85b0SNobuhiro Iwamatsu 646702c85b0SNobuhiro Iwamatsu /* U-boot specific routines */ 647702c85b0SNobuhiro Iwamatsu static u8 *pbuf = NULL; 648702c85b0SNobuhiro Iwamatsu 649702c85b0SNobuhiro Iwamatsu static int pkey = -1; 650702c85b0SNobuhiro Iwamatsu static int initialized = 0; 651702c85b0SNobuhiro Iwamatsu 652702c85b0SNobuhiro Iwamatsu void uboot_push_packet_len(int len) { 653702c85b0SNobuhiro Iwamatsu PRINTK("pushed len = %d\n", len); 654702c85b0SNobuhiro Iwamatsu if (len >= 2000) { 655702c85b0SNobuhiro Iwamatsu printf("NE2000: packet too big\n"); 656702c85b0SNobuhiro Iwamatsu return; 657702c85b0SNobuhiro Iwamatsu } 658702c85b0SNobuhiro Iwamatsu dp83902a_recv(&pbuf[0], len); 659702c85b0SNobuhiro Iwamatsu 660702c85b0SNobuhiro Iwamatsu /*Just pass it to the upper layer*/ 661702c85b0SNobuhiro Iwamatsu NetReceive(&pbuf[0], len); 662702c85b0SNobuhiro Iwamatsu } 663702c85b0SNobuhiro Iwamatsu 664702c85b0SNobuhiro Iwamatsu void uboot_push_tx_done(int key, int val) { 665702c85b0SNobuhiro Iwamatsu PRINTK("pushed key = %d\n", key); 666702c85b0SNobuhiro Iwamatsu pkey = key; 667702c85b0SNobuhiro Iwamatsu } 668702c85b0SNobuhiro Iwamatsu 669702c85b0SNobuhiro Iwamatsu int eth_init(bd_t *bd) { 670702c85b0SNobuhiro Iwamatsu int r; 671702c85b0SNobuhiro Iwamatsu u8 dev_addr[6]; 672702c85b0SNobuhiro Iwamatsu char ethaddr[20]; 673702c85b0SNobuhiro Iwamatsu 674702c85b0SNobuhiro Iwamatsu PRINTK("### eth_init\n"); 675702c85b0SNobuhiro Iwamatsu 676702c85b0SNobuhiro Iwamatsu if (!pbuf) { 677702c85b0SNobuhiro Iwamatsu pbuf = malloc(2000); 678702c85b0SNobuhiro Iwamatsu if (!pbuf) { 679702c85b0SNobuhiro Iwamatsu printf("Cannot allocate rx buffer\n"); 680702c85b0SNobuhiro Iwamatsu return -1; 681702c85b0SNobuhiro Iwamatsu } 682702c85b0SNobuhiro Iwamatsu } 683702c85b0SNobuhiro Iwamatsu 684702c85b0SNobuhiro Iwamatsu #ifdef CONFIG_DRIVER_NE2000_CCR 685702c85b0SNobuhiro Iwamatsu { 686702c85b0SNobuhiro Iwamatsu vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR; 687702c85b0SNobuhiro Iwamatsu 688702c85b0SNobuhiro Iwamatsu PRINTK("CCR before is %x\n", *p); 689702c85b0SNobuhiro Iwamatsu *p = CONFIG_DRIVER_NE2000_VAL; 690702c85b0SNobuhiro Iwamatsu PRINTK("CCR after is %x\n", *p); 691702c85b0SNobuhiro Iwamatsu } 692702c85b0SNobuhiro Iwamatsu #endif 693702c85b0SNobuhiro Iwamatsu 694702c85b0SNobuhiro Iwamatsu nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE; 695702c85b0SNobuhiro Iwamatsu 696702c85b0SNobuhiro Iwamatsu r = get_prom(dev_addr, nic.base); 697702c85b0SNobuhiro Iwamatsu if (!r) 698702c85b0SNobuhiro Iwamatsu return -1; 699702c85b0SNobuhiro Iwamatsu 700702c85b0SNobuhiro Iwamatsu sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X", 701702c85b0SNobuhiro Iwamatsu dev_addr[0], dev_addr[1], 702702c85b0SNobuhiro Iwamatsu dev_addr[2], dev_addr[3], 703702c85b0SNobuhiro Iwamatsu dev_addr[4], dev_addr[5]) ; 704702c85b0SNobuhiro Iwamatsu PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr); 705702c85b0SNobuhiro Iwamatsu setenv ("ethaddr", ethaddr); 706702c85b0SNobuhiro Iwamatsu 707702c85b0SNobuhiro Iwamatsu nic.data = nic.base + DP_DATA; 708702c85b0SNobuhiro Iwamatsu nic.tx_buf1 = START_PG; 709702c85b0SNobuhiro Iwamatsu nic.tx_buf2 = START_PG2; 710702c85b0SNobuhiro Iwamatsu nic.rx_buf_start = RX_START; 711702c85b0SNobuhiro Iwamatsu nic.rx_buf_end = RX_END; 712702c85b0SNobuhiro Iwamatsu 713702c85b0SNobuhiro Iwamatsu if (dp83902a_init() == false) 714702c85b0SNobuhiro Iwamatsu return -1; 715702c85b0SNobuhiro Iwamatsu 716702c85b0SNobuhiro Iwamatsu dp83902a_start(dev_addr); 717702c85b0SNobuhiro Iwamatsu initialized = 1; 718702c85b0SNobuhiro Iwamatsu 719702c85b0SNobuhiro Iwamatsu return 0; 720702c85b0SNobuhiro Iwamatsu } 721702c85b0SNobuhiro Iwamatsu 722702c85b0SNobuhiro Iwamatsu void eth_halt() { 723702c85b0SNobuhiro Iwamatsu 724702c85b0SNobuhiro Iwamatsu PRINTK("### eth_halt\n"); 725702c85b0SNobuhiro Iwamatsu if(initialized) 726702c85b0SNobuhiro Iwamatsu dp83902a_stop(); 727702c85b0SNobuhiro Iwamatsu initialized = 0; 728702c85b0SNobuhiro Iwamatsu } 729702c85b0SNobuhiro Iwamatsu 730702c85b0SNobuhiro Iwamatsu int eth_rx() { 731702c85b0SNobuhiro Iwamatsu dp83902a_poll(); 732702c85b0SNobuhiro Iwamatsu return 1; 733702c85b0SNobuhiro Iwamatsu } 734702c85b0SNobuhiro Iwamatsu 735702c85b0SNobuhiro Iwamatsu int eth_send(volatile void *packet, int length) { 736702c85b0SNobuhiro Iwamatsu int tmo; 737702c85b0SNobuhiro Iwamatsu 738702c85b0SNobuhiro Iwamatsu PRINTK("### eth_send\n"); 739702c85b0SNobuhiro Iwamatsu 740702c85b0SNobuhiro Iwamatsu pkey = -1; 741702c85b0SNobuhiro Iwamatsu 742702c85b0SNobuhiro Iwamatsu dp83902a_send((u8 *) packet, length, 666); 743*6d0f6bcfSJean-Christophe PLAGNIOL-VILLARD tmo = get_timer (0) + TOUT * CONFIG_SYS_HZ; 744702c85b0SNobuhiro Iwamatsu while(1) { 745702c85b0SNobuhiro Iwamatsu dp83902a_poll(); 746702c85b0SNobuhiro Iwamatsu if (pkey != -1) { 747702c85b0SNobuhiro Iwamatsu PRINTK("Packet sucesfully sent\n"); 748702c85b0SNobuhiro Iwamatsu return 0; 749702c85b0SNobuhiro Iwamatsu } 750702c85b0SNobuhiro Iwamatsu if (get_timer (0) >= tmo) { 751702c85b0SNobuhiro Iwamatsu printf("transmission error (timoeut)\n"); 752702c85b0SNobuhiro Iwamatsu return 0; 753702c85b0SNobuhiro Iwamatsu } 754702c85b0SNobuhiro Iwamatsu 755702c85b0SNobuhiro Iwamatsu } 756702c85b0SNobuhiro Iwamatsu return 0; 757702c85b0SNobuhiro Iwamatsu } 758