blob: c978d62ef30ff7c42332b291762165e5afcc6aca [file] [log] [blame]
wdenk8ed96042005-01-09 23:16:25 +00001/*
2Ported to U-Boot by Christian Pellegrin <chri@ascensit.com>
3
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
8
9==========================================================================
10
11dev/if_dp83902a.c
12
13Ethernet device driver for NS DP83902a ethernet controller
14
15==========================================================================
16####ECOSGPLCOPYRIGHTBEGIN####
17-------------------------------------------
18This file is part of eCos, the Embedded Configurable Operating System.
19Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
20
21eCos is free software; you can redistribute it and/or modify it under
22the terms of the GNU General Public License as published by the Free
23Software Foundation; either version 2 or (at your option) any later version.
24
25eCos is distributed in the hope that it will be useful, but WITHOUT ANY
26WARRANTY; without even the implied warranty of MERCHANTABILITY or
27FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28for more details.
29
30You should have received a copy of the GNU General Public License along
31with eCos; if not, write to the Free Software Foundation, Inc.,
3259 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
33
34As a special exception, if other files instantiate templates or use macros
35or inline functions from this file, or you compile this file and link it
36with other works to produce a work based on this file, this file does not
37by itself cause the resulting work to be covered by the GNU General Public
38License. However the source code for this file must still be made available
39in accordance with section (3) of the GNU General Public License.
40
41This exception does not invalidate any other reasons why a work based on
42this file might be covered by the GNU General Public License.
43
44Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
45at http://sources.redhat.com/ecos/ecos-license/
46-------------------------------------------
47####ECOSGPLCOPYRIGHTEND####
48####BSDCOPYRIGHTBEGIN####
49
50-------------------------------------------
51
52Portions of this software may have been derived from OpenBSD or other sources,
53and are covered by the appropriate copyright disclaimers included herein.
54
55-------------------------------------------
56
57####BSDCOPYRIGHTEND####
58==========================================================================
59#####DESCRIPTIONBEGIN####
60
61Author(s): gthomas
62Contributors: gthomas, jskov, rsandifo
63Date: 2001-06-13
64Purpose:
65Description:
66
67FIXME: Will fail if pinged with large packets (1520 bytes)
68Add promisc config
69Add SNMP
70
71####DESCRIPTIONEND####
72
73
74==========================================================================
75
76*/
77
78#include <common.h>
79#include <command.h>
80#include <net.h>
81#include <malloc.h>
82
83#ifdef CONFIG_DRIVER_NE2000
84
85/* wor around udelay resetting OCR */
86static void my_udelay(long us) {
87 long tmo;
88
89 tmo = get_timer (0) + us * CFG_HZ / 1000000; /* will this be much greater than 0 ? */
90 while (get_timer (0) < tmo);
91}
92
93#define mdelay(n) my_udelay((n)*1000)
94
95/* forward definition of function used for the uboot interface */
96void uboot_push_packet_len(int len);
97void uboot_push_tx_done(int key, int val);
98
99/* timeout for tx/rx in s */
100#define TOUT 5
101
102#define ETHER_ADDR_LEN 6
103
104/*
105 ------------------------------------------------------------------------
106 Debugging details
107
108 Set to perms of:
109 0 disables all debug output
110 1 for process debug output
111 2 for added data IO output: get_reg, put_reg
112 4 for packet allocation/free output
113 8 for only startup status, so we can tell we're installed OK
114*/
115/*#define DEBUG 0xf*/
116#define DEBUG 0
117
118#if DEBUG & 1
119#define DEBUG_FUNCTION() do { printf("%s\n", __FUNCTION__); } while (0)
120#define DEBUG_LINE() do { printf("%d\n", __LINE__); } while (0)
121#else
122#define DEBUG_FUNCTION() do {} while(0)
123#define DEBUG_LINE() do {} while(0)
124#endif
125
126#include "ne2000.h"
127
128#if DEBUG & 1
129#define PRINTK(args...) printf(args)
130#else
131#define PRINTK(args...)
132#endif
133
134static dp83902a_priv_data_t nic; /* just one instance of the card supported */
135
136static bool
137dp83902a_init(void)
138{
139 dp83902a_priv_data_t *dp = &nic;
140 cyg_uint8* base;
141 int i;
142
143 DEBUG_FUNCTION();
144
145 base = dp->base;
146 if (!base) return false; /* No device found */
147
148 DEBUG_LINE();
149
150 /* Prepare ESA */
151 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1); /* Select page 1 */
152 /* Use the address from the serial EEPROM */
153 for (i = 0; i < 6; i++)
154 DP_IN(base, DP_P1_PAR0+i, dp->esa[i]);
155 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0); /* Select page 0 */
156
157 printf("NE2000 - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
158 "eeprom",
159 dp->esa[0],
160 dp->esa[1],
161 dp->esa[2],
162 dp->esa[3],
163 dp->esa[4],
164 dp->esa[5] );
165
166 return true;
167}
168
169static void
170dp83902a_stop(void)
171{
172 dp83902a_priv_data_t *dp = &nic;
173 cyg_uint8 *base = dp->base;
174
175 DEBUG_FUNCTION();
176
177 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
178 DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
179 DP_OUT(base, DP_IMR, 0x00); /* Disable all interrupts */
180
181 dp->running = false;
182}
183
184/*
185 This function is called to "start up" the interface. It may be called
186 multiple times, even when the hardware is already running. It will be
187 called whenever something "hardware oriented" changes and should leave
188 the hardware ready to send/receive packets.
189*/
190static void
191dp83902a_start(unsigned char * enaddr)
192{
193 dp83902a_priv_data_t *dp = &nic;
194 cyg_uint8 *base = dp->base;
195 int i;
196
197 DEBUG_FUNCTION();
198
199 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP); /* Brutal */
200 DP_OUT(base, DP_DCR, DP_DCR_INIT);
201 DP_OUT(base, DP_RBCH, 0); /* Remote byte count */
202 DP_OUT(base, DP_RBCL, 0);
203 DP_OUT(base, DP_RCR, DP_RCR_MON); /* Accept no packets */
204 DP_OUT(base, DP_TCR, DP_TCR_LOCAL); /* Transmitter [virtually] off */
205 DP_OUT(base, DP_TPSR, dp->tx_buf1); /* Transmitter start page */
206 dp->tx1 = dp->tx2 = 0;
207 dp->tx_next = dp->tx_buf1;
208 dp->tx_started = false;
209 DP_OUT(base, DP_PSTART, dp->rx_buf_start); /* Receive ring start page */
210 DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1); /* Receive ring boundary */
211 DP_OUT(base, DP_PSTOP, dp->rx_buf_end); /* Receive ring end page */
212 dp->rx_next = dp->rx_buf_start-1;
213 DP_OUT(base, DP_ISR, 0xFF); /* Clear any pending interrupts */
214 DP_OUT(base, DP_IMR, DP_IMR_All); /* Enable all interrupts */
215 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1 | DP_CR_STOP); /* Select page 1 */
216 DP_OUT(base, DP_P1_CURP, dp->rx_buf_start); /* Current page - next free page for Rx */
217 for (i = 0; i < ETHER_ADDR_LEN; i++) {
218 DP_OUT(base, DP_P1_PAR0+i, enaddr[i]);
219 }
220 /* Enable and start device */
221 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
222 DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
223 DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
224 dp->running = true;
225}
226
227/*
228 This routine is called to start the transmitter. It is split out from the
229 data handling routine so it may be called either when data becomes first
230 available or when an Tx interrupt occurs
231*/
232
233static void
234dp83902a_start_xmit(int start_page, int len)
235{
236 dp83902a_priv_data_t *dp = (dp83902a_priv_data_t *) &nic;
237 cyg_uint8 *base = dp->base;
238
239 DEBUG_FUNCTION();
240
241#if DEBUG & 1
242 printf("Tx pkt %d len %d\n", start_page, len);
243 if (dp->tx_started)
244 printf("TX already started?!?\n");
245#endif
246
247 DP_OUT(base, DP_ISR, (DP_ISR_TxP | DP_ISR_TxE));
248 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
249 DP_OUT(base, DP_TBCL, len & 0xFF);
250 DP_OUT(base, DP_TBCH, len >> 8);
251 DP_OUT(base, DP_TPSR, start_page);
252 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
253
254 dp->tx_started = true;
255}
256
257/*
258 This routine is called to send data to the hardware. It is known a-priori
259 that there is free buffer space (dp->tx_next).
260*/
261static void
262dp83902a_send(unsigned char *data, int total_len, unsigned long key)
263{
264 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
265 cyg_uint8 *base = dp->base;
266 int len, start_page, pkt_len, i, isr;
267#if DEBUG & 4
268 int dx;
269#endif
270
271 DEBUG_FUNCTION();
272
273 len = pkt_len = total_len;
274 if (pkt_len < IEEE_8023_MIN_FRAME) pkt_len = IEEE_8023_MIN_FRAME;
275
276 start_page = dp->tx_next;
277 if (dp->tx_next == dp->tx_buf1) {
278 dp->tx1 = start_page;
279 dp->tx1_len = pkt_len;
280 dp->tx1_key = key;
281 dp->tx_next = dp->tx_buf2;
282 } else {
283 dp->tx2 = start_page;
284 dp->tx2_len = pkt_len;
285 dp->tx2_key = key;
286 dp->tx_next = dp->tx_buf1;
287 }
288
289#if DEBUG & 5
290 printf("TX prep page %d len %d\n", start_page, pkt_len);
291#endif
292
293 DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
294 {
295 /* Dummy read. The manual sez something slightly different, */
296 /* but the code is extended a bit to do what Hitachi's monitor */
297 /* does (i.e., also read data). */
298
299 cyg_uint16 tmp;
300 int len = 1;
301
302 DP_OUT(base, DP_RSAL, 0x100-len);
303 DP_OUT(base, DP_RSAH, (start_page-1) & 0xff);
304 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
311 /* Stall for a bit before continuing to work around random data */
312 /* corruption problems on some platforms. */
313 CYGACC_CALL_IF_DELAY_US(1);
314#endif
315
316 /* Send data to device buffer(s) */
317 DP_OUT(base, DP_RSAL, 0);
318 DP_OUT(base, DP_RSAH, start_page);
319 DP_OUT(base, DP_RBCL, pkt_len & 0xFF);
320 DP_OUT(base, DP_RBCH, pkt_len >> 8);
321 DP_OUT(base, DP_CR, DP_CR_WDMA | DP_CR_START);
322
323 /* Put data into buffer */
324#if DEBUG & 4
325 printf(" sg buf %08lx len %08x\n ", (unsigned long) data, len);
326 dx = 0;
327#endif
328 while (len > 0) {
329#if DEBUG & 4
330 printf(" %02x", *data);
331 if (0 == (++dx % 16)) printf("\n ");
332#endif
333 DP_OUT_DATA(dp->data, *data++);
334 len--;
335 }
336#if DEBUG & 4
337 printf("\n");
338#endif
339 if (total_len < pkt_len) {
340#if DEBUG & 4
341 printf(" + %d bytes of padding\n", pkt_len - total_len);
342#endif
343 /* Padding to 802.3 length was required */
344 for (i = total_len; i < pkt_len;) {
345 i++;
346 DP_OUT_DATA(dp->data, 0);
347 }
348 }
349
350#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
351 /* After last data write, delay for a bit before accessing the */
352 /* device again, or we may get random data corruption in the last */
353 /* datum (on some platforms). */
354 CYGACC_CALL_IF_DELAY_US(1);
355#endif
356
357 /* Wait for DMA to complete */
358 do {
359 DP_IN(base, DP_ISR, isr);
360 } while ((isr & DP_ISR_RDC) == 0);
361 /* Then disable DMA */
362 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
363
364 /* Start transmit if not already going */
365 if (!dp->tx_started) {
366 if (start_page == dp->tx1) {
367 dp->tx_int = 1; /* Expecting interrupt from BUF1 */
368 } else {
369 dp->tx_int = 2; /* Expecting interrupt from BUF2 */
370 }
371 dp83902a_start_xmit(start_page, pkt_len);
372 }
373}
374
375/*
376 This function is called when a packet has been received. It's job is
377 to prepare to unload the packet from the hardware. Once the length of
378 the packet is known, the upper layer of the driver can be told. When
379 the upper layer is ready to unload the packet, the internal function
380 'dp83902a_recv' will be called to actually fetch it from the hardware.
381*/
382static void
383dp83902a_RxEvent(void)
384{
385 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
386 cyg_uint8 *base = dp->base;
387 unsigned char rsr;
388 unsigned char rcv_hdr[4];
389 int i, len, pkt, cur;
390
391 DEBUG_FUNCTION();
392
393 DP_IN(base, DP_RSR, rsr);
394 while (true) {
395 /* Read incoming packet header */
396 DP_OUT(base, DP_CR, DP_CR_PAGE1 | DP_CR_NODMA | DP_CR_START);
397 DP_IN(base, DP_P1_CURP, cur);
398 DP_OUT(base, DP_P1_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
399 DP_IN(base, DP_BNDRY, pkt);
400
401 pkt += 1;
402 if (pkt == dp->rx_buf_end)
403 pkt = dp->rx_buf_start;
404
405 if (pkt == cur) {
406 break;
407 }
408 DP_OUT(base, DP_RBCL, sizeof(rcv_hdr));
409 DP_OUT(base, DP_RBCH, 0);
410 DP_OUT(base, DP_RSAL, 0);
411 DP_OUT(base, DP_RSAH, pkt);
412 if (dp->rx_next == pkt) {
413 if (cur == dp->rx_buf_start)
414 DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1);
415 else
416 DP_OUT(base, DP_BNDRY, cur-1); /* Update pointer */
417 return;
418 }
419 dp->rx_next = pkt;
420 DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
421 DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
422#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
423 CYGACC_CALL_IF_DELAY_US(10);
424#endif
425
426 for (i = 0; i < sizeof(rcv_hdr);) {
427 DP_IN_DATA(dp->data, rcv_hdr[i++]);
428 }
429
430#if DEBUG & 5
431 printf("rx hdr %02x %02x %02x %02x\n",
432 rcv_hdr[0], rcv_hdr[1], rcv_hdr[2], rcv_hdr[3]);
433#endif
434 len = ((rcv_hdr[3] << 8) | rcv_hdr[2]) - sizeof(rcv_hdr);
435 uboot_push_packet_len(len);
436 if (rcv_hdr[1] == dp->rx_buf_start)
437 DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1);
438 else
439 DP_OUT(base, DP_BNDRY, rcv_hdr[1]-1); /* Update pointer */
440 }
441}
442
443/*
444 This function is called as a result of the "eth_drv_recv()" call above.
445 It's job is to actually fetch data for a packet from the hardware once
446 memory buffers have been allocated for the packet. Note that the buffers
447 may come in pieces, using a scatter-gather list. This allows for more
448 efficient processing in the upper layers of the stack.
449*/
450static void
451dp83902a_recv(unsigned char *data, int len)
452{
453 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
454 cyg_uint8 *base = dp->base;
455 int i, mlen;
456 cyg_uint8 saved_char = 0;
457 bool saved;
458#if DEBUG & 4
459 int dx;
460#endif
461
462 DEBUG_FUNCTION();
463
464#if DEBUG & 5
465 printf("Rx packet %d length %d\n", dp->rx_next, len);
466#endif
467
468 /* Read incoming packet data */
469 DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
470 DP_OUT(base, DP_RBCL, len & 0xFF);
471 DP_OUT(base, DP_RBCH, len >> 8);
472 DP_OUT(base, DP_RSAL, 4); /* Past header */
473 DP_OUT(base, DP_RSAH, dp->rx_next);
474 DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
475 DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
476#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
477 CYGACC_CALL_IF_DELAY_US(10);
478#endif
479
480 saved = false;
481 for (i = 0; i < 1; i++) {
482 if (data) {
483 mlen = len;
484#if DEBUG & 4
485 printf(" sg buf %08lx len %08x \n", (unsigned long) data, mlen);
486 dx = 0;
487#endif
488 while (0 < mlen) {
489 /* Saved byte from previous loop? */
490 if (saved) {
491 *data++ = saved_char;
492 mlen--;
493 saved = false;
494 continue;
495 }
496
497 {
498 cyg_uint8 tmp;
499 DP_IN_DATA(dp->data, tmp);
500#if DEBUG & 4
501 printf(" %02x", tmp);
502 if (0 == (++dx % 16)) printf("\n ");
503#endif
504 *data++ = tmp;;
505 mlen--;
506 }
507 }
508#if DEBUG & 4
509 printf("\n");
510#endif
511 }
512 }
513}
514
515static void
516dp83902a_TxEvent(void)
517{
518 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
519 cyg_uint8 *base = dp->base;
520 unsigned char tsr;
521 unsigned long key;
522
523 DEBUG_FUNCTION();
524
525 DP_IN(base, DP_TSR, tsr);
526 if (dp->tx_int == 1) {
527 key = dp->tx1_key;
528 dp->tx1 = 0;
529 } else {
530 key = dp->tx2_key;
531 dp->tx2 = 0;
532 }
533 /* Start next packet if one is ready */
534 dp->tx_started = false;
535 if (dp->tx1) {
536 dp83902a_start_xmit(dp->tx1, dp->tx1_len);
537 dp->tx_int = 1;
538 } else if (dp->tx2) {
539 dp83902a_start_xmit(dp->tx2, dp->tx2_len);
540 dp->tx_int = 2;
541 } else {
542 dp->tx_int = 0;
543 }
544 /* Tell higher level we sent this packet */
545 uboot_push_tx_done(key, 0);
546}
547
548/* Read the tally counters to clear them. Called in response to a CNT */
549/* interrupt. */
550static void
551dp83902a_ClearCounters(void)
552{
553 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
554 cyg_uint8 *base = dp->base;
555 cyg_uint8 cnt1, cnt2, cnt3;
556
557 DP_IN(base, DP_FER, cnt1);
558 DP_IN(base, DP_CER, cnt2);
559 DP_IN(base, DP_MISSED, cnt3);
560 DP_OUT(base, DP_ISR, DP_ISR_CNT);
561}
562
563/* Deal with an overflow condition. This code follows the procedure set */
564/* out in section 7.0 of the datasheet. */
565static void
566dp83902a_Overflow(void)
567{
568 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *)&nic;
569 cyg_uint8 *base = dp->base;
570 cyg_uint8 isr;
571
572 /* Issue a stop command and wait 1.6ms for it to complete. */
573 DP_OUT(base, DP_CR, DP_CR_STOP | DP_CR_NODMA);
574 CYGACC_CALL_IF_DELAY_US(1600);
575
576 /* Clear the remote byte counter registers. */
577 DP_OUT(base, DP_RBCL, 0);
578 DP_OUT(base, DP_RBCH, 0);
579
580 /* Enter loopback mode while we clear the buffer. */
581 DP_OUT(base, DP_TCR, DP_TCR_LOCAL);
582 DP_OUT(base, DP_CR, DP_CR_START | DP_CR_NODMA);
583
584 /* Read in as many packets as we can and acknowledge any and receive */
585 /* interrupts. Since the buffer has overflowed, a receive event of */
586 /* some kind will have occured. */
587 dp83902a_RxEvent();
588 DP_OUT(base, DP_ISR, DP_ISR_RxP|DP_ISR_RxE);
589
590 /* Clear the overflow condition and leave loopback mode. */
591 DP_OUT(base, DP_ISR, DP_ISR_OFLW);
592 DP_OUT(base, DP_TCR, DP_TCR_NORMAL);
593
594 /* If a transmit command was issued, but no transmit event has occured, */
595 /* restart it here. */
596 DP_IN(base, DP_ISR, isr);
597 if (dp->tx_started && !(isr & (DP_ISR_TxP|DP_ISR_TxE))) {
598 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_TXPKT | DP_CR_START);
599 }
600}
601
602static void
603dp83902a_poll(void)
604{
605 struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
606 cyg_uint8 *base = dp->base;
607 unsigned char isr;
608
609 DP_OUT(base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0 | DP_CR_START);
610 DP_IN(base, DP_ISR, isr);
611 while (0 != isr) {
612 /* The CNT interrupt triggers when the MSB of one of the error */
613 /* counters is set. We don't much care about these counters, but */
614 /* we should read their values to reset them. */
615 if (isr & DP_ISR_CNT) {
616 dp83902a_ClearCounters();
617 }
618 /* Check for overflow. It's a special case, since there's a */
619 /* particular procedure that must be followed to get back into */
620 /* a running state.a */
621 if (isr & DP_ISR_OFLW) {
622 dp83902a_Overflow();
623 } else {
624 /* Other kinds of interrupts can be acknowledged simply by */
625 /* clearing the relevant bits of the ISR. Do that now, then */
626 /* handle the interrupts we care about. */
627 DP_OUT(base, DP_ISR, isr); /* Clear set bits */
628 if (!dp->running) break; /* Is this necessary? */
629 /* Check for tx_started on TX event since these may happen */
630 /* spuriously it seems. */
631 if (isr & (DP_ISR_TxP|DP_ISR_TxE) && dp->tx_started) {
632 dp83902a_TxEvent();
633 }
634 if (isr & (DP_ISR_RxP|DP_ISR_RxE)) {
635 dp83902a_RxEvent();
636 }
637 }
638 DP_IN(base, DP_ISR, isr);
639 }
640}
641
642/* find prom (taken from pc_net_cs.c from Linux) */
643
644#include "8390.h"
645
646typedef struct hw_info_t {
647 u_int offset;
648 u_char a0, a1, a2;
649 u_int flags;
650} hw_info_t;
651
652#define DELAY_OUTPUT 0x01
653#define HAS_MISC_REG 0x02
654#define USE_BIG_BUF 0x04
655#define HAS_IBM_MISC 0x08
656#define IS_DL10019 0x10
657#define IS_DL10022 0x20
658#define HAS_MII 0x40
659#define USE_SHMEM 0x80 /* autodetected */
660
661#define AM79C9XX_HOME_PHY 0x00006B90 /* HomePNA PHY */
662#define AM79C9XX_ETH_PHY 0x00006B70 /* 10baseT PHY */
663#define MII_PHYID_REV_MASK 0xfffffff0
664#define MII_PHYID_REG1 0x02
665#define MII_PHYID_REG2 0x03
666
667static hw_info_t hw_info[] = {
668 { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT },
669 { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
670 { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
671 { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
672 DELAY_OUTPUT | HAS_IBM_MISC },
673 { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
674 { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
675 { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
676 { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
677 { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
678 { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
679 { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
680 HAS_MISC_REG | HAS_IBM_MISC },
681 { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
682 { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
683 { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
684 HAS_MISC_REG | HAS_IBM_MISC },
685 { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
686 HAS_MISC_REG | HAS_IBM_MISC },
687 { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
688 HAS_MISC_REG | HAS_IBM_MISC },
689 { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
690 HAS_MISC_REG | HAS_IBM_MISC },
691 { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
692 HAS_MISC_REG | HAS_IBM_MISC },
693 { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
694 HAS_MISC_REG | HAS_IBM_MISC },
695 { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
696 HAS_MISC_REG | HAS_IBM_MISC },
697 { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
698 HAS_MISC_REG | HAS_IBM_MISC },
699 { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
700 HAS_MISC_REG | HAS_IBM_MISC },
701 { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
702 HAS_MISC_REG | HAS_IBM_MISC },
703 { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
704 { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
705 { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
706 HAS_MISC_REG | HAS_IBM_MISC },
707 { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
708 HAS_MISC_REG | HAS_IBM_MISC },
709 { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
710 { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
711 { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
712 { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
713 { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
714 HAS_MISC_REG | HAS_IBM_MISC },
715 { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45,
716 HAS_MISC_REG | HAS_IBM_MISC },
717 { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
718 { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
719 { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
720 { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
721 DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
722 { /* Socket LP-E CF+ */ 0x01c0, 0x00, 0xc0, 0x1b, 0 },
723 { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
724 { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
725 { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
Vlad Lunguec227552007-10-25 16:08:14 +0300726 { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 },
727 { /* Qemu */ 0x0, 0x52, 0x54, 0x00, 0 }
wdenk8ed96042005-01-09 23:16:25 +0000728};
729
730#define NR_INFO (sizeof(hw_info)/sizeof(hw_info_t))
731
732static hw_info_t default_info = { 0, 0, 0, 0, 0 };
733
734unsigned char dev_addr[6];
735
736#define PCNET_CMD 0x00
737#define PCNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */
738#define PCNET_RESET 0x1f /* Issue a read to reset, a write to clear. */
739#define PCNET_MISC 0x18 /* For IBM CCAE and Socket EA cards */
740
741unsigned long nic_base;
742
743static void pcnet_reset_8390(void)
744{
745 int i, r;
746
747 PRINTK("nic base is %lx\n", nic_base);
748
wdenk8ed96042005-01-09 23:16:25 +0000749 n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
750 PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));
751 n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD);
752 PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));
753 n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
754 PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));
wdenk8ed96042005-01-09 23:16:25 +0000755 n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
756
Vlad Lunguff285ca2007-10-04 20:47:10 +0300757 n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET);
wdenk8ed96042005-01-09 23:16:25 +0000758
759 for (i = 0; i < 100; i++) {
760 if ((r = (n2k_inb(EN0_ISR) & ENISR_RESET)) != 0)
761 break;
762 PRINTK("got %x in reset\n", r);
763 my_udelay(100);
764 }
765 n2k_outb(ENISR_RESET, EN0_ISR); /* Ack intr. */
766
767 if (i == 100)
768 printf("pcnet_reset_8390() did not complete.\n");
769} /* pcnet_reset_8390 */
770
771static hw_info_t * get_prom(void ) {
772 unsigned char prom[32];
773 int i, j;
774 struct {
775 u_char value, offset;
776 } program_seq[] = {
777 {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
778 {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */
779 {0x00, EN0_RCNTLO}, /* Clear the count regs. */
780 {0x00, EN0_RCNTHI},
781 {0x00, EN0_IMR}, /* Mask completion irq. */
782 {0xFF, EN0_ISR},
783 {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */
784 {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */
785 {32, EN0_RCNTLO},
786 {0x00, EN0_RCNTHI},
787 {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */
788 {0x00, EN0_RSARHI},
789 {E8390_RREAD+E8390_START, E8390_CMD},
790 };
791
792 PRINTK("trying to get MAC via prom reading\n");
793
794 pcnet_reset_8390();
795
796 mdelay(10);
797
798 for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
799 n2k_outb(program_seq[i].value, program_seq[i].offset);
800
801 PRINTK("PROM:");
802 for (i = 0; i < 32; i++) {
803 prom[i] = n2k_inb(PCNET_DATAPORT);
804 PRINTK(" %02x", prom[i]);
805 }
806 PRINTK("\n");
807 for (i = 0; i < NR_INFO; i++) {
808 if ((prom[0] == hw_info[i].a0) &&
809 (prom[2] == hw_info[i].a1) &&
810 (prom[4] == hw_info[i].a2)) {
811 PRINTK("matched board %d\n", i);
812 break;
813 }
814 }
815 if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
816 for (j = 0; j < 6; j++)
817 dev_addr[j] = prom[j<<1];
818 PRINTK("on exit i is %d/%ld\n", i, NR_INFO);
819 PRINTK("MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n",
820 dev_addr[0],dev_addr[1],dev_addr[2],dev_addr[3],dev_addr[4],dev_addr[5]);
821 return (i < NR_INFO) ? hw_info+i : &default_info;
822 }
823 return NULL;
824}
825
826/* U-boot specific routines */
827
wdenk8ed96042005-01-09 23:16:25 +0000828
829static unsigned char *pbuf = NULL;
wdenk8ed96042005-01-09 23:16:25 +0000830
831static int pkey = -1;
Vlad Lunguff285ca2007-10-04 20:47:10 +0300832static int initialized=0;
wdenk8ed96042005-01-09 23:16:25 +0000833
834void uboot_push_packet_len(int len) {
Vlad Lunguec227552007-10-25 16:08:14 +0300835 PRINTK("pushed len = %d\n", len);
wdenk8ed96042005-01-09 23:16:25 +0000836 if (len>=2000) {
837 printf("NE2000: packet too big\n");
838 return;
839 }
Vlad Lunguec227552007-10-25 16:08:14 +0300840 dp83902a_recv(&pbuf[0], len);
Wolfgang Denk05bf4912007-10-21 01:01:17 +0200841
842 /*Just pass it to the upper layer*/
Vlad Lunguec227552007-10-25 16:08:14 +0300843 NetReceive(&pbuf[0], len);
wdenk8ed96042005-01-09 23:16:25 +0000844}
845
846void uboot_push_tx_done(int key, int val) {
847 PRINTK("pushed key = %d\n", key);
848 pkey = key;
849}
850
851int eth_init(bd_t *bd) {
852 static hw_info_t * r;
853 char ethaddr[20];
854
855 PRINTK("### eth_init\n");
856
857 if (!pbuf) {
Vlad Lunguec227552007-10-25 16:08:14 +0300858 pbuf = malloc(2000);
wdenk8ed96042005-01-09 23:16:25 +0000859 if (!pbuf) {
Vlad Lunguec227552007-10-25 16:08:14 +0300860 printf("Cannot allocate rx buffer\n");
wdenk8ed96042005-01-09 23:16:25 +0000861 return -1;
862 }
863 }
864
865#ifdef CONFIG_DRIVER_NE2000_CCR
866 {
867 volatile unsigned char *p = (volatile unsigned char *) CONFIG_DRIVER_NE2000_CCR;
868
869 PRINTK("CCR before is %x\n", *p);
870 *p = CONFIG_DRIVER_NE2000_VAL;
871 PRINTK("CCR after is %x\n", *p);
872 }
873#endif
874
875 nic_base = CONFIG_DRIVER_NE2000_BASE;
876 nic.base = (cyg_uint8 *) CONFIG_DRIVER_NE2000_BASE;
877
878 r = get_prom();
879 if (!r)
880 return -1;
881
882 sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
883 dev_addr[0], dev_addr[1],
884 dev_addr[2], dev_addr[3],
885 dev_addr[4], dev_addr[5]) ;
886 PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
887 setenv ("ethaddr", ethaddr);
888
889
890#define DP_DATA 0x10
891 nic.data = nic.base + DP_DATA;
892 nic.tx_buf1 = 0x40;
893 nic.tx_buf2 = 0x48;
894 nic.rx_buf_start = 0x50;
895 nic.rx_buf_end = 0x80;
896
897 if (dp83902a_init() == false)
898 return -1;
899 dp83902a_start(dev_addr);
Vlad Lunguff285ca2007-10-04 20:47:10 +0300900 initialized=1;
wdenk8ed96042005-01-09 23:16:25 +0000901 return 0;
902}
903
904void eth_halt() {
905
906 PRINTK("### eth_halt\n");
Vlad Lunguff285ca2007-10-04 20:47:10 +0300907 if(initialized)
908 dp83902a_stop();
909 initialized=0;
wdenk8ed96042005-01-09 23:16:25 +0000910}
911
912int eth_rx() {
Vlad Lunguff285ca2007-10-04 20:47:10 +0300913dp83902a_poll();
914return 1;
wdenk8ed96042005-01-09 23:16:25 +0000915}
916
917int eth_send(volatile void *packet, int length) {
918 int tmo;
919
920 PRINTK("### eth_send\n");
921
922 pkey = -1;
923
924 dp83902a_send((unsigned char *) packet, length, 666);
925 tmo = get_timer (0) + TOUT * CFG_HZ;
926 while(1) {
927 dp83902a_poll();
928 if (pkey != -1) {
929 PRINTK("Packet sucesfully sent\n");
930 return 0;
931 }
932 if (get_timer (0) >= tmo) {
933 printf("transmission error (timoeut)\n");
934 return 0;
935 }
936
937 }
938 return 0;
939}
wdenk8ed96042005-01-09 23:16:25 +0000940#endif