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