]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/eth/ns/dp83816/v2_0/src/if_dp83816.c
Initial revision
[karo-tx-redboot.git] / packages / devs / eth / ns / dp83816 / v2_0 / src / if_dp83816.c
1 //==========================================================================
2 //
3 //      dev/if_dp83816.c
4 //
5 //      Ethernet device driver for NS DP83816 ethernet controller
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003, 2004 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: 
46 // Date:         2003-09-29
47 // Purpose:      
48 // Description:
49 //
50 //####DESCRIPTIONEND####
51 //
52 //==========================================================================
53
54 #include <pkgconf/system.h>
55 #include <pkgconf/io_eth_drivers.h>
56
57 #include <cyg/infra/cyg_type.h>
58 #include <cyg/hal/hal_arch.h>
59 #include <cyg/hal/hal_endian.h>
60 #include <cyg/infra/diag.h>
61 #include <cyg/hal/drv_api.h>
62 #include <cyg/hal/hal_if.h>
63 #include <cyg/io/eth/eth_drv.h>
64 #include <cyg/io/eth/netdev.h>
65
66 #include "dp83816.h"
67 #include CYGDAT_DEVS_ETH_NS_DP83816_INL
68
69 #ifdef CYGHWR_NS_DP83816_USE_EEPROM
70 static cyg_uint16 dp83816_eeprom_read(struct dp83816_priv_data *dp, int location);
71 #endif
72
73 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
74 // This ISR is called when the ethernet interrupt occurs
75 static cyg_uint32
76 dp83816_isr(cyg_vector_t vector, cyg_addrword_t data)
77 {
78     struct eth_drv_sc *sc = (struct eth_drv_sc *)data;
79     dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
80
81     DEBUG_FUNCTION();
82
83     cyg_drv_interrupt_mask(dp->interrupt);
84     cyg_drv_interrupt_acknowledge(dp->interrupt);
85     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
86 }
87 #endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
88
89 // The deliver function (ex-DSR)  handles the ethernet [logical] processing
90 static void
91 dp83816_deliver(struct eth_drv_sc *sc)
92 {
93 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
94     dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
95 #endif
96
97     DEBUG_FUNCTION();
98
99     // Service the interrupt:
100     dp83816_poll(sc);
101 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
102     // Allow interrupts to happen again
103     cyg_drv_interrupt_unmask(dp->interrupt);
104 #endif
105 }
106
107 static bool
108 dp83816_reset(dp83816_priv_data_t *dp)
109 {
110     unsigned char *bp;
111     dp83816_bd_t *bdp;
112     cyg_uint32 stat;
113     int i, timeout;
114
115     DP_OUT(dp->base, DP_CR, _CR_RST);  // Reset device
116     timeout = 10000;
117     do {
118         DP_IN(dp->base, DP_CR, stat);
119     } while (((stat & _CR_RST) != 0) && (--timeout > 0));
120     if (timeout == 0) {
121         diag_printf("DP83816 - reset timed out! - stat: %x\n", stat);
122         return false;
123     }
124     // Rx ring
125     bdp = dp->rxnext = CYGARC_UNCACHED_ADDRESS(dp->rxd);
126     bp = dp->rxbuf;
127     for (i = 0; i < dp->rxnum; i++, bdp++) {
128         bdp->next = (dp83816_bd_t *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(bdp+1));
129         bdp->stat = CYG_CPU_TO_LE32(BD_INTR | _DP83816_BUFSIZE);  // Max buffer
130         bdp->buf = (unsigned char *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(bp));
131         bp += _DP83816_BUFSIZE;
132     }
133     bdp--;  bdp->next = (dp83816_bd_t *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(dp->rxd));
134     DP_OUT(dp->base, DP_RXCFG, _RXCFG_MXDMA_128 | ((64/32)<<_RXCFG_DRTH_SHIFT));
135     DP_OUT(dp->base, DP_RXDP, CYGARC_PHYSICAL_ADDRESS(dp->rxd));
136     // Tx ring
137     bdp = dp->txfill = dp->txint = CYGARC_UNCACHED_ADDRESS(dp->txd);
138     bp = dp->txbuf;
139     for (i = 0; i < dp->txnum; i++, bdp++) {
140         bdp->next = (dp83816_bd_t *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(bdp+1));
141         bdp->stat = 0;  // Driver owns buffer for now
142         bdp->buf = (unsigned char *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(bp));
143         bp += _DP83816_BUFSIZE;
144     }
145     bdp--;  bdp->next = (dp83816_bd_t *)CYG_CPU_TO_LE32(CYGARC_PHYSICAL_ADDRESS(dp->txd));
146     DP_OUT(dp->base, DP_TXCFG, _TXCFG_ATP |
147                                _TXCFG_MXDMA_128 |
148                                ((256/32)<<_TXCFG_FLTH_SHIFT) |
149                                ((512/32)<<_TXCFG_DRTH_SHIFT));
150     DP_OUT(dp->base, DP_TXDP, CYGARC_PHYSICAL_ADDRESS(dp->txd));
151     dp->txbusy = 0;
152     // Fill in ESA
153     for (i = 0;  i < 6;  i+=2) {
154         DP_OUT(dp->base, DP_RFCR, i);
155         DP_OUT(dp->base, DP_RFDR, dp->enaddr[i] | (dp->enaddr[i+1]<<8));
156     }
157     // Setup up acceptance criteria
158     DP_OUT(dp->base, DP_RFCR, _RFCR_RFEN | _RFCR_AAB | _RFCR_APM);
159     // Set up interrupts
160     DP_IN(dp->base, DP_ISR, stat);  // Clear any current interrupts
161     DP_OUT(dp->base, DP_IMR, 0x00000000);  // Disable them all!
162     DP_OUT(dp->base, DP_IER, 0);
163     return true;
164 }
165
166 static bool 
167 dp83816_init(struct cyg_netdevtab_entry *tab)
168 {
169     struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
170     dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
171     cyg_uint8 *base;
172     bool esa_ok;
173     unsigned char enaddr[6];
174
175     DEBUG_FUNCTION();
176
177     CYGHWR_NS_DP83816_PLF_INIT(dp);
178     base = dp->base;
179     if (!base) return false;  // No device found
180
181     // Get physical device address
182 #ifdef CYGHWR_NS_DP83816_USE_EEPROM
183     {
184         cyg_uint16 t;
185
186         t = (dp83816_eeprom_read(dp, 0x0006) >> 15)
187             | (dp83816_eeprom_read(dp, 0x0007) << 1);
188         enaddr[0] = t & 0xFF;
189         enaddr[1] = t >> 8;
190         t = (dp83816_eeprom_read(dp, 0x0007) >> 15)
191             | (dp83816_eeprom_read(dp, 0x0008) << 1);
192         enaddr[2] = t & 0xFF;
193         enaddr[3] = t >> 8;
194         t = (dp83816_eeprom_read(dp, 0x0008) >> 15)
195             | (dp83816_eeprom_read(dp, 0x0009) << 1);
196         enaddr[4] = t & 0xFF;
197         enaddr[5] = t >> 8;
198         
199         esa_ok =  true;
200     }
201 #else
202 #ifdef CYGPKG_REDBOOT
203 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
204     esa_ok = flash_get_config(dp->esa_key, enaddr, CONFIG_ESA);
205 #else
206     esa_ok = false;
207 #endif
208 #else
209     esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,         
210                                          dp->esa_key, enaddr, CONFIG_ESA);
211 #endif
212 #endif
213     if (esa_ok) {
214         memcpy(dp->enaddr, enaddr, sizeof(enaddr));
215     } else {
216         // Can't figure out ESA
217         diag_printf("DP83816 - Warning! ESA unknown\n");
218     }
219
220     if (!dp83816_reset(dp)) return false;
221
222 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
223     cyg_drv_interrupt_create(
224         dp->interrupt,
225         0,                       // Priority - unused
226         (cyg_addrword_t)sc,      // Data item passed to ISR & DSR
227         dp83816_isr,             // ISR
228         eth_drv_dsr,             // DSR
229         &dp->interrupt_handle,   // handle to intr obj
230         &dp->interrupt_object ); // space for int obj
231
232     cyg_drv_interrupt_attach(dp->interrupt_handle);
233     cyg_drv_interrupt_unmask(dp->interrupt);
234 #endif
235
236     // Initialize upper level driver
237     (sc->funs->eth_drv->init)(sc, dp->enaddr);
238
239     return true;
240 }
241
242 static void
243 dp83816_stop(struct eth_drv_sc *sc)
244 {
245     dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
246
247     DP_OUT(dp->base, DP_IMR, 0x00000000);  // Disable interrupts
248     DP_OUT(dp->base, DP_IER, 0);
249     DP_OUT(dp->base, DP_CR, _CR_RXD | _CR_TXD);
250 }
251
252 //
253 // This function is called to "start up" the interface.  It may be called
254 // multiple times, even when the hardware is already running.  It will be
255 // called whenever something "hardware oriented" changes and should leave
256 // the hardware ready to send/receive packets.
257 //
258 static void
259 dp83816_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
260 {
261     dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
262
263     DP_OUT(dp->base, DP_IMR, 0xFFFFFFFF);  // Enable interrupts
264     DP_OUT(dp->base, DP_IER, 1);
265     DP_OUT(dp->base, DP_CR, _CR_RXE | _CR_TXE);
266 }
267
268 //
269 // This routine is called to perform special "control" opertions
270 //
271 static int
272 dp83816_control(struct eth_drv_sc *sc, unsigned long key,
273                void *data, int data_len)
274 {
275     switch (key) {
276     case ETH_DRV_SET_MAC_ADDRESS:
277         return 0;
278         break;
279     default:
280         return 1;
281         break;
282     }
283 }
284
285 //
286 // This routine is called to see if it is possible to send another packet.
287 // It will return non-zero if a transmit is possible, zero otherwise.
288 //
289 static int
290 dp83816_can_send(struct eth_drv_sc *sc)
291 {
292     dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
293
294     DEBUG_FUNCTION();
295     return (dp->txnum - dp->txbusy);
296 }
297
298 //
299 // This routine is called to send data to the hardware.  It is known a-priori
300 // that there is free buffer space (dp->tx_next).
301 //
302 static void 
303 dp83816_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, 
304             int total_len, unsigned long key)
305 {
306     struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
307     int i, len;
308     unsigned char *data;
309     dp83816_bd_t *bdp = dp->txfill;
310
311     DEBUG_FUNCTION();
312
313     len = total_len;
314     if (len < IEEE_8023_MIN_FRAME) len = IEEE_8023_MIN_FRAME;
315     data = (unsigned char *)CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->buf));
316     for (i = 0;  i < sg_len;  i++) {
317         memcpy(data, (unsigned char *)sg_list[i].buf, sg_list[i].len);
318         data += sg_list[i].len;
319     }
320     bdp->key = key;
321     bdp->stat = CYG_CPU_TO_LE32(len | BD_OWN | BD_INTR);
322     dp->txbusy++;
323     bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->next)));
324     dp->txfill = bdp;
325     // Kick the device, in case it went idle
326     DP_OUT(dp->base, DP_CR, _CR_TXE);
327 }
328
329 static void
330 dp83816_TxEvent(struct eth_drv_sc *sc)
331 {
332     struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
333     dp83816_bd_t *bdp = dp->txint;
334
335     DEBUG_FUNCTION();
336     while ((CYG_LE32_TO_CPU(bdp->stat) & (BD_OWN|BD_INTR)) == BD_INTR) {
337         // Tell higher level we sent this packet
338         (sc->funs->eth_drv->tx_done)(sc, bdp->key, 0);
339         bdp->stat = 0;  // retake buffer
340         bdp->key = 0;
341         dp->txbusy--;
342         bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->next)));
343     }
344     dp->txint = bdp;
345 }
346
347 //
348 // This function is called when a packet has been received.  It's job is
349 // to prepare to unload the packet from the hardware.  Once the length of
350 // the packet is known, the upper layer of the driver can be told.  When
351 // the upper layer is ready to unload the packet, the internal function
352 // 'dp83816_recv' will be called to actually fetch it from the hardware.
353 //
354 static void
355 dp83816_RxEvent(struct eth_drv_sc *sc)
356 {
357     struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
358     dp83816_bd_t *bdp = CYGARC_UNCACHED_ADDRESS(dp->rxd);
359     dp83816_bd_t *bdfirst = CYGARC_UNCACHED_ADDRESS(dp->rxd);
360     int len, err;
361
362     DEBUG_FUNCTION();
363
364     while (true) {
365         if ((CYG_LE32_TO_CPU(bdp->stat) & BD_OWN) != 0) {
366             err = CYG_LE32_TO_CPU(bdp->stat) & (BD_RXA|BD_RXO|BD_LONG|BD_RUNT|BD_ISE|BD_CRCE|BD_FAE|BD_COL);
367             if (err != 0) {
368                 diag_printf("RxError: %x\n", err);
369             }
370             len = CYG_LE32_TO_CPU(bdp->stat) & BD_LENGTH_MASK;
371             dp->rxnext = bdp;
372             (sc->funs->eth_drv->recv)(sc, len);
373             bdp->stat = CYG_CPU_TO_LE32(BD_INTR | _DP83816_BUFSIZE);  // Give back buffer
374         }
375         bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->next)));
376         if (bdp == bdfirst) {
377             break;
378         }
379     }
380 }
381
382 //
383 // This function is called as a result of the "eth_drv_recv()" call above.
384 // It's job is to actually fetch data for a packet from the hardware once
385 // memory buffers have been allocated for the packet.  Note that the buffers
386 // may come in pieces, using a scatter-gather list.  This allows for more
387 // efficient processing in the upper layers of the stack.
388 //
389 static void
390 dp83816_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
391 {
392     struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
393     dp83816_bd_t *bdp = dp->rxnext;
394     unsigned char *data;
395     int i;
396
397     data = (unsigned char *)CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->buf));
398     for (i = 0;  i < sg_len;  i++) {
399         memcpy((void *)sg_list[i].buf, data, sg_list[i].len);
400         data += sg_list[i].len;
401     }
402 }
403
404 static void
405 dp83816_warm_reset(struct eth_drv_sc *sc)
406 {
407     struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
408     dp83816_bd_t *bdp;
409     int i;
410
411     // Free up any active Tx buffers
412     bdp = CYGARC_UNCACHED_ADDRESS(dp->txd);
413     for (i = 0; i < dp->txnum; i++, bdp++) {
414         if (bdp->key) {
415             (sc->funs->eth_drv->tx_done)(sc, bdp->key, 0);
416         }
417     }
418     // Reset the device
419     dp83816_reset(dp);
420     DP_OUT(dp->base, DP_CR, _CR_RXE | _CR_TXE);
421 }
422
423 static void
424 dp83816_poll(struct eth_drv_sc *sc)
425 {
426     struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
427     unsigned long stat, cr_stat;
428
429     DP_IN(dp->base, DP_ISR, stat);
430     do {
431         if ((stat & (_ISR_TXDESC|_ISR_TXOK)) != 0) {
432             dp83816_TxEvent(sc);
433         }
434         if ((stat & (_ISR_RXDESC|_ISR_RXOK|_ISR_RXERR)) != 0) {
435             dp83816_RxEvent(sc);
436         }
437         DP_IN(dp->base, DP_CR, cr_stat);
438         if ((stat & (_ISR_HIBERR|_ISR_TXURN|_ISR_RXORN)) != 0) {            
439 #if 0
440             diag_printf("DP83816 - major error: %x, cmd_stat: %x\n", stat, cr_stat);
441 #endif
442             // Try to reset the device
443             dp83816_warm_reset(sc);
444         }
445         if (((cr_stat & _CR_RXE) == 0) ||
446             ((dp->txbusy > 1) && ((cr_stat & _CR_TXE) == 0))) {
447 #if 0
448             // What happened?
449             diag_printf("DP83816 went to lunch? - stat: %x/%x, txbusy: %x\n", cr_stat, stat, dp->txbusy);
450 #endif
451             // Try to reset the device
452             dp83816_warm_reset(sc);
453         }
454         DP_IN(dp->base, DP_ISR, stat);
455     } while (stat != 0);
456 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
457     CYGHWR_NS_DP83816_PLF_INT_CLEAR(dp);
458 #endif
459 }
460
461 static int
462 dp83816_int_vector(struct eth_drv_sc *sc)
463 {
464     struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
465     return dp->interrupt;
466 }
467
468 /* EEPROM Functions */
469 #ifdef CYGHWR_NS_DP83816_USE_EEPROM
470
471 #define EEPROM_READ(dp, x)  DP_IN((dp)->base, DP_MEAR, (x))
472 #define EEPROM_WRITE(dp, x) DP_OUT((dp)->base, DP_MEAR, (x))
473 #define EEPROM_DELAY(dp)    CYG_MACRO_START cyg_uint16 t; EEPROM_READ((dp), t); CYG_MACRO_END
474
475 #define DP83816_EEPROM_ADDR_LEN  6
476 #define DP83816_EE_READ_CMD     (6 << DP83816_EEPROM_ADDR_LEN)
477
478
479 /* EEPROM data is bit-swapped. */
480 static cyg_uint16 dp83816_eeprom_fixup_data(cyg_uint16 input)
481 {
482     cyg_uint16 output = 0;
483     int i;
484
485     for (i = 0; i < 16; i++) {
486         output = (output << 1) | (input & 0x0001);
487         input >>= 1;
488     }
489     return output;
490 }
491
492 static cyg_uint16 dp83816_eeprom_command(struct dp83816_priv_data *dp, int cmd, int cmd_len)
493 {
494     int d = 0;
495
496     EEPROM_WRITE(dp, _MEAR_EESEL);
497
498     do {
499         cyg_uint32 c = (cmd & (1 << cmd_len)) ? _MEAR_EEDI : 0;
500         cyg_uint8 t;
501
502         EEPROM_WRITE(dp, c | _MEAR_EESEL);
503         EEPROM_DELAY(dp);
504         EEPROM_WRITE(dp, c | _MEAR_EESEL | _MEAR_EECLK);
505         EEPROM_DELAY(dp);
506
507         EEPROM_READ(dp, t);
508         d <<= 1;
509         d |= (t & _MEAR_EEDO) ? 1 : 0;
510     } while (cmd_len--);
511
512     EEPROM_WRITE(dp, _MEAR_EESEL);
513     EEPROM_WRITE(dp, 0);
514
515     return d & 0xffff;
516 }
517
518 static cyg_uint16 dp83816_eeprom_read(struct dp83816_priv_data *dp, int loc)
519 {
520     cyg_uint16 d;
521
522     d = dp83816_eeprom_command(dp, (loc | DP83816_EE_READ_CMD) << 16,
523                                3 + DP83816_EEPROM_ADDR_LEN + 16);
524
525     return dp83816_eeprom_fixup_data(d);
526 }
527
528 #endif /* CYGHWR_NS_DP83816_USE_EEPROM */