blob: d09da782951673b08484e28e076eb10d1693453f [file] [log] [blame]
wdenk8ed96042005-01-09 23:16:25 +00001/*
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +02002Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
wdenk8ed96042005-01-09 23:16:25 +00003
4Based on sources from the Linux kernel (pcnet_cs.c, 8390.h) and
5eCOS(if_dp83902a.c, if_dp83902a.h). Both of these 2 wonderful world
6are GPL, so this is, of course, GPL.
7
wdenk8ed96042005-01-09 23:16:25 +00008==========================================================================
9
10dev/if_dp83902a.c
11
12Ethernet device driver for NS DP83902a ethernet controller
13
14==========================================================================
15####ECOSGPLCOPYRIGHTBEGIN####
16-------------------------------------------
17This file is part of eCos, the Embedded Configurable Operating System.
18Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
19
20eCos is free software; you can redistribute it and/or modify it under
21the terms of the GNU General Public License as published by the Free
22Software Foundation; either version 2 or (at your option) any later version.
23
24eCos is distributed in the hope that it will be useful, but WITHOUT ANY
25WARRANTY; without even the implied warranty of MERCHANTABILITY or
26FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27for more details.
28
29You should have received a copy of the GNU General Public License along
30with eCos; if not, write to the Free Software Foundation, Inc.,
3159 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
32
33As a special exception, if other files instantiate templates or use macros
34or inline functions from this file, or you compile this file and link it
35with other works to produce a work based on this file, this file does not
36by itself cause the resulting work to be covered by the GNU General Public
37License. However the source code for this file must still be made available
38in accordance with section (3) of the GNU General Public License.
39
40This exception does not invalidate any other reasons why a work based on
41this file might be covered by the GNU General Public License.
42
43Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
44at http://sources.redhat.com/ecos/ecos-license/
45-------------------------------------------
46####ECOSGPLCOPYRIGHTEND####
47####BSDCOPYRIGHTBEGIN####
48
49-------------------------------------------
50
51Portions of this software may have been derived from OpenBSD or other sources,
52and are covered by the appropriate copyright disclaimers included herein.
53
54-------------------------------------------
55
56####BSDCOPYRIGHTEND####
57==========================================================================
58#####DESCRIPTIONBEGIN####
59
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +020060Author(s): gthomas
61Contributors: gthomas, jskov, rsandifo
62Date: 2001-06-13
wdenk8ed96042005-01-09 23:16:25 +000063Purpose:
64Description:
65
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +020066FIXME: Will fail if pinged with large packets (1520 bytes)
wdenk8ed96042005-01-09 23:16:25 +000067Add promisc config
68Add SNMP
69
70####DESCRIPTIONEND####
71
wdenk8ed96042005-01-09 23:16:25 +000072==========================================================================
wdenk8ed96042005-01-09 23:16:25 +000073*/
74
75#include <common.h>
76#include <command.h>
77#include <net.h>
78#include <malloc.h>
79
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +020080#define mdelay(n) udelay((n)*1000)
wdenk8ed96042005-01-09 23:16:25 +000081/* forward definition of function used for the uboot interface */
82void uboot_push_packet_len(int len);
83void uboot_push_tx_done(int key, int val);
84
wdenk8ed96042005-01-09 23:16:25 +000085/*
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +020086 * Debugging details
87 *
88 * Set to perms of:
89 * 0 disables all debug output
90 * 1 for process debug output
91 * 2 for added data IO output: get_reg, put_reg
92 * 4 for packet allocation/free output
93 * 8 for only startup status, so we can tell we're installed OK
94 */
95#if 0
96#define DEBUG 0xf
97#else
wdenk8ed96042005-01-09 23:16:25 +000098#define DEBUG 0
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +020099#endif
wdenk8ed96042005-01-09 23:16:25 +0000100
101#if DEBUG & 1
102#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
103#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
goda.yusukee7101852008-03-05 17:08:20 +0900104#define PRINTK(args...) printf(args)
wdenk8ed96042005-01-09 23:16:25 +0000105#else
106#define DEBUG_FUNCTION() do {} while(0)
107#define DEBUG_LINE() do {} while(0)
wdenk8ed96042005-01-09 23:16:25 +0000108#define PRINTK(args...)
109#endif
110
goda.yusukee7101852008-03-05 17:08:20 +0900111/* NE2000 base header file */
112#include "ne2000_base.h"
113
goda.yusuke6a8a5dc2008-03-05 17:08:33 +0900114#if defined(CONFIG_DRIVER_AX88796L)
115/* AX88796L support */
116#include "ax88796.h"
117#else
goda.yusukee7101852008-03-05 17:08:20 +0900118/* Basic NE2000 chip support */
119#include "ne2000.h"
goda.yusuke6a8a5dc2008-03-05 17:08:33 +0900120#endif
goda.yusukee7101852008-03-05 17:08:20 +0900121
wdenk8ed96042005-01-09 23:16:25 +0000122static dp83902a_priv_data_t nic; /* just one instance of the card supported */
123
124static bool
125dp83902a_init(void)
126{
127 dp83902a_priv_data_t *dp = &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900128 u8* base;
wdenk8ed96042005-01-09 23:16:25 +0000129
130 DEBUG_FUNCTION();
131
132 base = dp->base;
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200133 if (!base)
134 return false; /* No device found */
wdenk8ed96042005-01-09 23:16:25 +0000135
136 DEBUG_LINE();
137
goda.yusukee7101852008-03-05 17:08:20 +0900138#if defined(NE2000_BASIC_INIT)
goda.yusuke6a8a5dc2008-03-05 17:08:33 +0900139 /* AX88796L doesn't need */
wdenk8ed96042005-01-09 23:16:25 +0000140 /* Prepare ESA */
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200141 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */
wdenk8ed96042005-01-09 23:16:25 +0000142 /* Use the address from the serial EEPROM */
143 for (i = 0; i < 6; i++)
144 DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200145 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */
wdenk8ed96042005-01-09 23:16:25 +0000146
147 printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200148 "eeprom",
149 dp->esa[0],
150 dp->esa[1],
151 dp->esa[2],
152 dp->esa[3],
153 dp->esa[4],
154 dp->esa[5] );
wdenk8ed96042005-01-09 23:16:25 +0000155
goda.yusukee7101852008-03-05 17:08:20 +0900156#endif /* NE2000_BASIC_INIT */
wdenk8ed96042005-01-09 23:16:25 +0000157 return true;
158}
159
160static void
161dp83902a_stop(void)
162{
163 dp83902a_priv_data_t *dp = &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900164 u8 *base = dp->base;
wdenk8ed96042005-01-09 23:16:25 +0000165
166 DEBUG_FUNCTION();
167
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200168 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
wdenk8ed96042005-01-09 23:16:25 +0000169 DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
170 DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */
171
172 dp->running = false;
173}
174
175/*
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200176 * This function is called to "start up" the interface. It may be called
177 * multiple times, even when the hardware is already running. It will be
178 * called whenever something "hardware oriented" changes and should leave
179 * the hardware ready to send/receive packets.
180 */
wdenk8ed96042005-01-09 23:16:25 +0000181static void
goda.yusukee7101852008-03-05 17:08:20 +0900182dp83902a_start(u8 * enaddr)
wdenk8ed96042005-01-09 23:16:25 +0000183{
184 dp83902a_priv_data_t *dp = &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900185 u8 *base = dp->base;
wdenk8ed96042005-01-09 23:16:25 +0000186 int i;
187
188 DEBUG_FUNCTION();
189
190 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
191 DP_OUT(base, DP_DCR, DP_DCR_INIT);
192 DP_OUT(base, DP_RBCH, 0); /* Remote byte count */
193 DP_OUT(base, DP_RBCL, 0);
194 DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */
195 DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */
196 DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */
197 dp->tx1 = dp->tx2 = 0;
198 dp->tx_next = dp->tx_buf1;
199 dp->tx_started = false;
goda.yusukee7101852008-03-05 17:08:20 +0900200 dp->running = true;
wdenk8ed96042005-01-09 23:16:25 +0000201 DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200202 DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1); /* Receive ring boundary */
wdenk8ed96042005-01-09 23:16:25 +0000203 DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200204 dp->rx_next = dp->rx_buf_start - 1;
goda.yusukee7101852008-03-05 17:08:20 +0900205 dp->running = true;
wdenk8ed96042005-01-09 23:16:25 +0000206 DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
207 DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200208 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */
209 DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */
goda.yusukee7101852008-03-05 17:08:20 +0900210 dp->running = true;
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200211 for (i = 0; i < ETHER_ADDR_LEN; i++) {
goda.yusukee7101852008-03-05 17:08:20 +0900212 /* FIXME */
Wolfgang Denkaa6f6d12008-03-26 00:52:10 +0100213 /*((vu_short*)( base + ((DP_P1_PAR0 + i) * 2) +
214 * 0x1400)) = enaddr[i];*/
wdenk8ed96042005-01-09 23:16:25 +0000215 DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
216 }
217 /* Enable and start device */
218 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
219 DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200220 DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
wdenk8ed96042005-01-09 23:16:25 +0000221 dp->running = true;
222}
223
224/*
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200225 * This routine is called to start the transmitter. It is split out from the
226 * data handling routine so it may be called either when data becomes first
227 * available or when an Tx interrupt occurs
228 */
wdenk8ed96042005-01-09 23:16:25 +0000229
230static void
231dp83902a_start_xmit(int start_page, int len)
232{
233 dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900234 u8 *base = dp->base;
wdenk8ed96042005-01-09 23:16:25 +0000235
236 DEBUG_FUNCTION();
237
238#if DEBUG & 1
239 printf("Tx pkt %d len %d\n", start_page, len);
240 if (dp->tx_started)
241 printf("TX already started?!?\n");
242#endif
243
244 DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
245 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
246 DP_OUT(base, DP_TBCL, len & 0xFF);
247 DP_OUT(base, DP_TBCH, len >> 8);
248 DP_OUT(base, DP_TPSR, start_page);
249 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
250
251 dp->tx_started = true;
252}
253
254/*
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200255 * This routine is called to send data to the hardware. It is known a-priori
256 * that there is free buffer space (dp->tx_next).
257 */
wdenk8ed96042005-01-09 23:16:25 +0000258static void
goda.yusukee7101852008-03-05 17:08:20 +0900259dp83902a_send(u8 *data, int total_len, u32 key)
wdenk8ed96042005-01-09 23:16:25 +0000260{
261 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900262 u8 *base = dp->base;
wdenk8ed96042005-01-09 23:16:25 +0000263 int len, start_page, pkt_len, i, isr;
264#if DEBUG & 4
265 int dx;
266#endif
267
268 DEBUG_FUNCTION();
269
270 len = pkt_len = total_len;
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200271 if (pkt_len < IEEE_8023_MIN_FRAME)
272 pkt_len = IEEE_8023_MIN_FRAME;
wdenk8ed96042005-01-09 23:16:25 +0000273
274 start_page = dp->tx_next;
275 if (dp->tx_next == dp->tx_buf1) {
276 dp->tx1 = start_page;
277 dp->tx1_len = pkt_len;
278 dp->tx1_key = key;
279 dp->tx_next = dp->tx_buf2;
280 } else {
281 dp->tx2 = start_page;
282 dp->tx2_len = pkt_len;
283 dp->tx2_key = key;
284 dp->tx_next = dp->tx_buf1;
285 }
286
287#if DEBUG & 5
288 printf("TX prep page %d len %d\n", start_page, pkt_len);
289#endif
290
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200291 DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
wdenk8ed96042005-01-09 23:16:25 +0000292 {
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200293 /*
294 * Dummy read. The manual sez something slightly different,
295 * but the code is extended a bit to do what Hitachi's monitor
296 * does (i.e., also read data).
297 */
wdenk8ed96042005-01-09 23:16:25 +0000298
goda.yusukee7101852008-03-05 17:08:20 +0900299 u16 tmp;
wdenk8ed96042005-01-09 23:16:25 +0000300 int len = 1;
301
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200302 DP_OUT(base, DP_RSAL, 0x100 - len);
303 DP_OUT(base, DP_RSAH, (start_page - 1) & 0xff);
wdenk8ed96042005-01-09 23:16:25 +0000304 DP_OUT(base, DP_RBCL, len);
305 DP_OUT(base, DP_RBCH, 0);
306 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
307 DP_IN_DATA(dp->data, tmp);
308 }
309
310#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200311 /*
312 * Stall for a bit before continuing to work around random data
313 * corruption problems on some platforms.
314 */
wdenk8ed96042005-01-09 23:16:25 +0000315 CYGACC_CALL_IF_DELAY_US(1);
316#endif
317
318 /* Send data to device buffer(s) */
319 DP_OUT(base, DP_RSAL, 0);
320 DP_OUT(base, DP_RSAH, start_page);
321 DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
322 DP_OUT(base, DP_RBCH, pkt_len >> 8);
323 DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
324
325 /* Put data into buffer */
326#if DEBUG & 4
goda.yusukee7101852008-03-05 17:08:20 +0900327 printf(" sg buf %08lx len %08x\n ", (u32)data, len);
wdenk8ed96042005-01-09 23:16:25 +0000328 dx = 0;
329#endif
330 while (len > 0) {
331#if DEBUG & 4
332 printf(" %02x", *data);
333 if (0 == (++dx % 16)) printf("\n ");
334#endif
goda.yusukee7101852008-03-05 17:08:20 +0900335
wdenk8ed96042005-01-09 23:16:25 +0000336 DP_OUT_DATA(dp->data, *data++);
337 len--;
338 }
339#if DEBUG & 4
340 printf("\n");
341#endif
342 if (total_len < pkt_len) {
343#if DEBUG & 4
344 printf(" + %d bytes of padding\n", pkt_len - total_len);
345#endif
346 /* Padding to 802.3 length was required */
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200347 for (i = total_len; i < pkt_len;) {
wdenk8ed96042005-01-09 23:16:25 +0000348 i++;
349 DP_OUT_DATA(dp->data, 0);
350 }
351 }
352
353#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200354 /*
355 * After last data write, delay for a bit before accessing the
356 * device again, or we may get random data corruption in the last
357 * datum (on some platforms).
358 */
wdenk8ed96042005-01-09 23:16:25 +0000359 CYGACC_CALL_IF_DELAY_US(1);
360#endif
361
362 /* Wait for DMA to complete */
363 do {
364 DP_IN(base, DP_ISR, isr);
365 } while ((isr & DP_ISR_RDC) == 0);
goda.yusukee7101852008-03-05 17:08:20 +0900366
wdenk8ed96042005-01-09 23:16:25 +0000367 /* Then disable DMA */
368 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
369
370 /* Start transmit if not already going */
371 if (!dp->tx_started) {
372 if (start_page == dp->tx1) {
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200373 dp->tx_int = 1; /* Expecting interrupt from BUF1 */
wdenk8ed96042005-01-09 23:16:25 +0000374 } else {
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200375 dp->tx_int = 2; /* Expecting interrupt from BUF2 */
wdenk8ed96042005-01-09 23:16:25 +0000376 }
377 dp83902a_start_xmit(start_page, pkt_len);
378 }
379}
380
381/*
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200382 * This function is called when a packet has been received. It's job is
383 * to prepare to unload the packet from the hardware. Once the length of
384 * the packet is known, the upper layer of the driver can be told. When
385 * the upper layer is ready to unload the packet, the internal function
386 * 'dp83902a_recv' will be called to actually fetch it from the hardware.
387 */
wdenk8ed96042005-01-09 23:16:25 +0000388static void
389dp83902a_RxEvent(void)
390{
391 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900392 u8 *base = dp->base;
393 u8 rsr;
394 u8 rcv_hdr[4];
wdenk8ed96042005-01-09 23:16:25 +0000395 int i, len, pkt, cur;
396
397 DEBUG_FUNCTION();
398
399 DP_IN(base, DP_RSR, rsr);
400 while (true) {
401 /* Read incoming packet header */
402 DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
403 DP_IN(base, DP_P1_CURP, cur);
404 DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
405 DP_IN(base, DP_BNDRY, pkt);
406
407 pkt += 1;
408 if (pkt == dp->rx_buf_end)
409 pkt = dp->rx_buf_start;
410
411 if (pkt == cur) {
412 break;
413 }
414 DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
415 DP_OUT(base, DP_RBCH, 0);
416 DP_OUT(base, DP_RSAL, 0);
417 DP_OUT(base, DP_RSAH, pkt);
418 if (dp->rx_next == pkt) {
419 if (cur == dp->rx_buf_start)
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200420 DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
wdenk8ed96042005-01-09 23:16:25 +0000421 else
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200422 DP_OUT(base, DP_BNDRY, cur - 1); /* Update pointer */
wdenk8ed96042005-01-09 23:16:25 +0000423 return;
424 }
425 dp->rx_next = pkt;
426 DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
427 DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
428#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
429 CYGACC_CALL_IF_DELAY_US(10);
430#endif
431
goda.yusukee7101852008-03-05 17:08:20 +0900432 /* read header (get data size)*/
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200433 for (i = 0; i < sizeof(rcv_hdr);) {
wdenk8ed96042005-01-09 23:16:25 +0000434 DP_IN_DATA(dp->data, rcv_hdr[i++]);
435 }
436
437#if DEBUG & 5
438 printf("rx hdr %02x %02x %02x %02x\n",
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200439 rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
wdenk8ed96042005-01-09 23:16:25 +0000440#endif
441 len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
goda.yusukee7101852008-03-05 17:08:20 +0900442
443 /* data read */
wdenk8ed96042005-01-09 23:16:25 +0000444 uboot_push_packet_len(len);
goda.yusukee7101852008-03-05 17:08:20 +0900445
wdenk8ed96042005-01-09 23:16:25 +0000446 if (rcv_hdr[1] == dp->rx_buf_start)
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200447 DP_OUT(base, DP_BNDRY, dp->rx_buf_end - 1);
wdenk8ed96042005-01-09 23:16:25 +0000448 else
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200449 DP_OUT(base, DP_BNDRY, rcv_hdr[1] - 1); /* Update pointer */
wdenk8ed96042005-01-09 23:16:25 +0000450 }
451}
452
453/*
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200454 * This function is called as a result of the "eth_drv_recv()" call above.
455 * It's job is to actually fetch data for a packet from the hardware once
456 * memory buffers have been allocated for the packet. Note that the buffers
457 * may come in pieces, using a scatter-gather list. This allows for more
458 * efficient processing in the upper layers of the stack.
459 */
wdenk8ed96042005-01-09 23:16:25 +0000460static void
goda.yusukee7101852008-03-05 17:08:20 +0900461dp83902a_recv(u8 *data, int len)
wdenk8ed96042005-01-09 23:16:25 +0000462{
463 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900464 u8 *base = dp->base;
wdenk8ed96042005-01-09 23:16:25 +0000465 int i, mlen;
goda.yusukee7101852008-03-05 17:08:20 +0900466 u8 saved_char = 0;
wdenk8ed96042005-01-09 23:16:25 +0000467 bool saved;
468#if DEBUG & 4
469 int dx;
470#endif
471
472 DEBUG_FUNCTION();
473
474#if DEBUG & 5
475 printf("Rx packet %d length %d\n", dp->rx_next, len);
476#endif
477
478 /* Read incoming packet data */
479 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
480 DP_OUT(base, DP_RBCL, len & 0xFF);
481 DP_OUT(base, DP_RBCH, len >> 8);
482 DP_OUT(base, DP_RSAL, 4); /* Past header */
483 DP_OUT(base, DP_RSAH, dp->rx_next);
484 DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
485 DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
486#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
487 CYGACC_CALL_IF_DELAY_US(10);
488#endif
489
490 saved = false;
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200491 for (i = 0; i < 1; i++) {
wdenk8ed96042005-01-09 23:16:25 +0000492 if (data) {
493 mlen = len;
494#if DEBUG & 4
goda.yusukee7101852008-03-05 17:08:20 +0900495 printf(" sg buf %08lx len %08x \n", (u32) data, mlen);
wdenk8ed96042005-01-09 23:16:25 +0000496 dx = 0;
497#endif
498 while (0 < mlen) {
499 /* Saved byte from previous loop? */
500 if (saved) {
501 *data++ = saved_char;
502 mlen--;
503 saved = false;
504 continue;
505 }
506
507 {
goda.yusukee7101852008-03-05 17:08:20 +0900508 u8 tmp;
wdenk8ed96042005-01-09 23:16:25 +0000509 DP_IN_DATA(dp->data, tmp);
510#if DEBUG & 4
511 printf(" %02x", tmp);
512 if (0 == (++dx % 16)) printf("\n ");
513#endif
514 *data++ = tmp;;
515 mlen--;
516 }
517 }
518#if DEBUG & 4
519 printf("\n");
520#endif
521 }
522 }
523}
524
525static void
526dp83902a_TxEvent(void)
527{
528 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900529 u8 *base = dp->base;
530 u8 tsr;
531 u32 key;
wdenk8ed96042005-01-09 23:16:25 +0000532
533 DEBUG_FUNCTION();
534
535 DP_IN(base, DP_TSR, tsr);
536 if (dp->tx_int == 1) {
537 key = dp->tx1_key;
538 dp->tx1 = 0;
539 } else {
540 key = dp->tx2_key;
541 dp->tx2 = 0;
542 }
543 /* Start next packet if one is ready */
544 dp->tx_started = false;
545 if (dp->tx1) {
546 dp83902a_start_xmit(dp->tx1, dp->tx1_len);
547 dp->tx_int = 1;
548 } else if (dp->tx2) {
549 dp83902a_start_xmit(dp->tx2, dp->tx2_len);
550 dp->tx_int = 2;
551 } else {
552 dp->tx_int = 0;
553 }
554 /* Tell higher level we sent this packet */
555 uboot_push_tx_done(key, 0);
556}
557
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200558/*
559 * Read the tally counters to clear them. Called in response to a CNT
560 * interrupt.
561 */
wdenk8ed96042005-01-09 23:16:25 +0000562static void
563dp83902a_ClearCounters(void)
564{
565 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900566 u8 *base = dp->base;
567 u8 cnt1, cnt2, cnt3;
wdenk8ed96042005-01-09 23:16:25 +0000568
569 DP_IN(base, DP_FER, cnt1);
570 DP_IN(base, DP_CER, cnt2);
571 DP_IN(base, DP_MISSED, cnt3);
572 DP_OUT(base, DP_ISR, DP_ISR_CNT);
573}
574
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200575/*
576 * Deal with an overflow condition. This code follows the procedure set
577 * out in section 7.0 of the datasheet.
578 */
wdenk8ed96042005-01-09 23:16:25 +0000579static void
580dp83902a_Overflow(void)
581{
582 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
goda.yusukee7101852008-03-05 17:08:20 +0900583 u8 *base = dp->base;
584 u8 isr;
wdenk8ed96042005-01-09 23:16:25 +0000585
586 /* Issue a stop command and wait 1.6ms for it to complete. */
587 DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
588 CYGACC_CALL_IF_DELAY_US(1600);
589
590 /* Clear the remote byte counter registers. */
591 DP_OUT(base, DP_RBCL, 0);
592 DP_OUT(base, DP_RBCH, 0);
593
594 /* Enter loopback mode while we clear the buffer. */
595 DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
596 DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
597
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200598 /*
599 * Read in as many packets as we can and acknowledge any and receive
600 * interrupts. Since the buffer has overflowed, a receive event of
601 * some kind will have occured.
602 */
wdenk8ed96042005-01-09 23:16:25 +0000603 dp83902a_RxEvent();
604 DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
605
606 /* Clear the overflow condition and leave loopback mode. */
607 DP_OUT(base, DP_ISR, DP_ISR_OFLW);
608 DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
609
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200610 /*
611 * If a transmit command was issued, but no transmit event has occured,
612 * restart it here.
613 */
wdenk8ed96042005-01-09 23:16:25 +0000614 DP_IN(base, DP_ISR, isr);
615 if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
616 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
617 }
618}
619
620static void
621dp83902a_poll(void)
622{
623 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
goda.yusukee7101852008-03-05 17:08:20 +0900624 u8 *base = dp->base;
625 u8 isr;
wdenk8ed96042005-01-09 23:16:25 +0000626
627 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
628 DP_IN(base, DP_ISR, isr);
629 while (0 != isr) {
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200630 /*
631 * The CNT interrupt triggers when the MSB of one of the error
632 * counters is set. We don't much care about these counters, but
633 * we should read their values to reset them.
634 */
wdenk8ed96042005-01-09 23:16:25 +0000635 if (isr & DP_ISR_CNT) {
636 dp83902a_ClearCounters();
637 }
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200638 /*
639 * Check for overflow. It's a special case, since there's a
640 * particular procedure that must be followed to get back into
641 * a running state.a
642 */
wdenk8ed96042005-01-09 23:16:25 +0000643 if (isr & DP_ISR_OFLW) {
644 dp83902a_Overflow();
645 } else {
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200646 /*
647 * Other kinds of interrupts can be acknowledged simply by
648 * clearing the relevant bits of the ISR. Do that now, then
649 * handle the interrupts we care about.
650 */
651 DP_OUT(base, DP_ISR, isr); /* Clear set bits */
wdenk8ed96042005-01-09 23:16:25 +0000652 if (!dp->running) break; /* Is this necessary? */
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200653 /*
654 * Check for tx_started on TX event since these may happen
655 * spuriously it seems.
656 */
wdenk8ed96042005-01-09 23:16:25 +0000657 if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
658 dp83902a_TxEvent();
659 }
660 if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
661 dp83902a_RxEvent();
662 }
663 }
664 DP_IN(base, DP_ISR, isr);
665 }
666}
667
668/* find prom (taken from pc_net_cs.c from Linux) */
669
670#include "8390.h"
goda.yusukee7101852008-03-05 17:08:20 +0900671/*
wdenk8ed96042005-01-09 23:16:25 +0000672typedef struct hw_info_t {
673 u_int offset;
674 u_char a0, a1, a2;
675 u_int flags;
676} hw_info_t;
goda.yusukee7101852008-03-05 17:08:20 +0900677*/
wdenk8ed96042005-01-09 23:16:25 +0000678#define DELAY_OUTPUT 0x01
679#define HAS_MISC_REG 0x02
680#define USE_BIG_BUF 0x04
681#define HAS_IBM_MISC 0x08
682#define IS_DL10019 0x10
683#define IS_DL10022 0x20
684#define HAS_MII 0x40
685#define USE_SHMEM 0x80 /* autodetected */
686
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200687#define AM79C9XX_HOME_PHY 0x00006B90 /* HomePNA PHY */
688#define AM79C9XX_ETH_PHY 0x00006B70 /* 10baseT PHY */
wdenk8ed96042005-01-09 23:16:25 +0000689#define MII_PHYID_REV_MASK 0xfffffff0
690#define MII_PHYID_REG1 0x02
691#define MII_PHYID_REG2 0x03
692
693static hw_info_t hw_info[] = {
694 { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
695 { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
696 { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
697 { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200698 DELAY_OUTPUT | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000699 { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
700 { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
701 { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
702 { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
703 { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
704 { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
705 { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200706 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000707 { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
708 { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
709 { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200710 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000711 { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200712 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000713 { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200714 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000715 { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200716 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000717 { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200718 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000719 { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200720 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000721 { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200722 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000723 { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200724 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000725 { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200726 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000727 { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200728 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000729 { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
730 { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
731 { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200732 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000733 { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200734 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000735 { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
736 { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
737 { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
738 { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
739 { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200740 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000741 { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200742 HAS_MISC_REG | HAS_IBM_MISC },
wdenk8ed96042005-01-09 23:16:25 +0000743 { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
744 { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
745 { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
746 { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200747 DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
wdenk8ed96042005-01-09 23:16:25 +0000748 { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
749 { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
750 { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
751 { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
Vlad Lunguec227552007-10-25 16:08:14 +0300752 { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 },
753 { /* Qemu */ 0x0, 0x52, 0x54, 0x00, 0 }
wdenk8ed96042005-01-09 23:16:25 +0000754};
755
756#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))
757
758static hw_info_t default_info = { 0, 0, 0, 0, 0 };
759
goda.yusukee7101852008-03-05 17:08:20 +0900760u8 dev_addr[6];
wdenk8ed96042005-01-09 23:16:25 +0000761
762#define PCNET_CMD 0x00
763#define PCNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */
764#define PCNET_RESET 0x1f /* Issue a read to reset, a write to clear. */
765#define PCNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */
766
goda.yusukee7101852008-03-05 17:08:20 +0900767u32 nic_base;
wdenk8ed96042005-01-09 23:16:25 +0000768
769/* U-boot specific routines */
goda.yusukee7101852008-03-05 17:08:20 +0900770static u8 *pbuf = NULL;
wdenk8ed96042005-01-09 23:16:25 +0000771
772static int pkey = -1;
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200773static int initialized = 0;
wdenk8ed96042005-01-09 23:16:25 +0000774
775void uboot_push_packet_len(int len) {
Vlad Lunguec227552007-10-25 16:08:14 +0300776 PRINTK("pushed len = %d\n", len);
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200777 if (len >= 2000) {
wdenk8ed96042005-01-09 23:16:25 +0000778 printf("NE2000: packet too big\n");
779 return;
780 }
Vlad Lunguec227552007-10-25 16:08:14 +0300781 dp83902a_recv(&pbuf[0], len);
Wolfgang Denk05bf4912007-10-21 01:01:17 +0200782
goda.yusukee7101852008-03-05 17:08:20 +0900783 /*Just pass it to the upper layer*/
Vlad Lunguec227552007-10-25 16:08:14 +0300784 NetReceive(&pbuf[0], len);
wdenk8ed96042005-01-09 23:16:25 +0000785}
786
787void uboot_push_tx_done(int key, int val) {
788 PRINTK("pushed key = %d\n", key);
789 pkey = key;
790}
791
792int eth_init(bd_t *bd) {
793 static hw_info_t * r;
794 char ethaddr[20];
795
796 PRINTK("### eth_init\n");
797
798 if (!pbuf) {
Vlad Lunguec227552007-10-25 16:08:14 +0300799 pbuf = malloc(2000);
wdenk8ed96042005-01-09 23:16:25 +0000800 if (!pbuf) {
Vlad Lunguec227552007-10-25 16:08:14 +0300801 printf("Cannot allocate rx buffer\n");
wdenk8ed96042005-01-09 23:16:25 +0000802 return -1;
803 }
804 }
805
806#ifdef CONFIG_DRIVER_NE2000_CCR
807 {
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200808 vu_char *p = (vu_char *) CONFIG_DRIVER_NE2000_CCR;
wdenk8ed96042005-01-09 23:16:25 +0000809
810 PRINTK("CCR before is %x\n", *p);
811 *p = CONFIG_DRIVER_NE2000_VAL;
812 PRINTK("CCR after is %x\n", *p);
813 }
814#endif
815
816 nic_base = CONFIG_DRIVER_NE2000_BASE;
goda.yusukee7101852008-03-05 17:08:20 +0900817 nic.base = (u8 *) CONFIG_DRIVER_NE2000_BASE;
wdenk8ed96042005-01-09 23:16:25 +0000818
goda.yusukee7101852008-03-05 17:08:20 +0900819 r = get_prom(dev_addr);
wdenk8ed96042005-01-09 23:16:25 +0000820 if (!r)
821 return -1;
822
823 sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
824 dev_addr[0], dev_addr[1],
825 dev_addr[2], dev_addr[3],
826 dev_addr[4], dev_addr[5]) ;
827 PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
828 setenv ("ethaddr", ethaddr);
829
wdenk8ed96042005-01-09 23:16:25 +0000830 nic.data = nic.base + DP_DATA;
goda.yusukee7101852008-03-05 17:08:20 +0900831 nic.tx_buf1 = START_PG;
832 nic.tx_buf2 = START_PG2;
833 nic.rx_buf_start = RX_START;
834 nic.rx_buf_end = RX_END;
wdenk8ed96042005-01-09 23:16:25 +0000835
836 if (dp83902a_init() == false)
837 return -1;
goda.yusukee7101852008-03-05 17:08:20 +0900838
wdenk8ed96042005-01-09 23:16:25 +0000839 dp83902a_start(dev_addr);
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200840 initialized = 1;
goda.yusukee7101852008-03-05 17:08:20 +0900841
wdenk8ed96042005-01-09 23:16:25 +0000842 return 0;
843}
844
845void eth_halt() {
goda.yusukee7101852008-03-05 17:08:20 +0900846
wdenk8ed96042005-01-09 23:16:25 +0000847 PRINTK("### eth_halt\n");
Vlad Lunguff285ca2007-10-04 20:47:10 +0300848 if(initialized)
849 dp83902a_stop();
Jean-Christophe PLAGNIOL-VILLARD4acbc6c2008-04-24 07:57:16 +0200850 initialized = 0;
wdenk8ed96042005-01-09 23:16:25 +0000851}
852
853int eth_rx() {
Marcel Ziswiler10c73822007-12-30 03:30:56 +0100854 dp83902a_poll();
855 return 1;
wdenk8ed96042005-01-09 23:16:25 +0000856}
857
858int eth_send(volatile void *packet, int length) {
859 int tmo;
860
861 PRINTK("### eth_send\n");
862
863 pkey = -1;
864
goda.yusukee7101852008-03-05 17:08:20 +0900865 dp83902a_send((u8 *) packet, length, 666);
wdenk8ed96042005-01-09 23:16:25 +0000866 tmo = get_timer (0) + TOUT * CFG_HZ;
867 while(1) {
868 dp83902a_poll();
869 if (pkey != -1) {
870 PRINTK("Packet sucesfully sent\n");
871 return 0;
872 }
873 if (get_timer (0) >= tmo) {
874 printf("transmission error (timoeut)\n");
875 return 0;
876 }
877
878 }
879 return 0;
880}