1 //==========================================================================
5 // Ethernet device driver for NS DP83816 ethernet controller
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
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.
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
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.
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.
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.
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####
50 //####DESCRIPTIONEND####
52 //==========================================================================
54 #include <pkgconf/system.h>
55 #include <pkgconf/io_eth_drivers.h>
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>
67 #include CYGDAT_DEVS_ETH_NS_DP83816_INL
69 #ifdef CYGHWR_NS_DP83816_USE_EEPROM
70 static cyg_uint16 dp83816_eeprom_read(struct dp83816_priv_data *dp, int location);
73 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
74 // This ISR is called when the ethernet interrupt occurs
76 dp83816_isr(cyg_vector_t vector, cyg_addrword_t data)
78 struct eth_drv_sc *sc = (struct eth_drv_sc *)data;
79 dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
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
87 #endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
89 // The deliver function (ex-DSR) handles the ethernet [logical] processing
91 dp83816_deliver(struct eth_drv_sc *sc)
93 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
94 dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
99 // Service the interrupt:
101 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
102 // Allow interrupts to happen again
103 cyg_drv_interrupt_unmask(dp->interrupt);
108 dp83816_reset(dp83816_priv_data_t *dp)
115 DP_OUT(dp->base, DP_CR, _CR_RST); // Reset device
118 DP_IN(dp->base, DP_CR, stat);
119 } while (((stat & _CR_RST) != 0) && (--timeout > 0));
121 diag_printf("DP83816 - reset timed out! - stat: %x\n", stat);
125 bdp = dp->rxnext = CYGARC_UNCACHED_ADDRESS(dp->rxd);
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;
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));
137 bdp = dp->txfill = dp->txint = CYGARC_UNCACHED_ADDRESS(dp->txd);
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;
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 |
148 ((256/32)<<_TXCFG_FLTH_SHIFT) |
149 ((512/32)<<_TXCFG_DRTH_SHIFT));
150 DP_OUT(dp->base, DP_TXDP, CYGARC_PHYSICAL_ADDRESS(dp->txd));
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));
157 // Setup up acceptance criteria
158 DP_OUT(dp->base, DP_RFCR, _RFCR_RFEN | _RFCR_AAB | _RFCR_APM);
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);
167 dp83816_init(struct cyg_netdevtab_entry *tab)
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;
173 unsigned char enaddr[6];
177 CYGHWR_NS_DP83816_PLF_INIT(dp);
179 if (!base) return false; // No device found
181 // Get physical device address
182 #ifdef CYGHWR_NS_DP83816_USE_EEPROM
186 t = (dp83816_eeprom_read(dp, 0x0006) >> 15)
187 | (dp83816_eeprom_read(dp, 0x0007) << 1);
188 enaddr[0] = t & 0xFF;
190 t = (dp83816_eeprom_read(dp, 0x0007) >> 15)
191 | (dp83816_eeprom_read(dp, 0x0008) << 1);
192 enaddr[2] = t & 0xFF;
194 t = (dp83816_eeprom_read(dp, 0x0008) >> 15)
195 | (dp83816_eeprom_read(dp, 0x0009) << 1);
196 enaddr[4] = t & 0xFF;
202 #ifdef CYGPKG_REDBOOT
203 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
204 esa_ok = flash_get_config(dp->esa_key, enaddr, CONFIG_ESA);
209 esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
210 dp->esa_key, enaddr, CONFIG_ESA);
214 memcpy(dp->enaddr, enaddr, sizeof(enaddr));
216 // Can't figure out ESA
217 diag_printf("DP83816 - Warning! ESA unknown\n");
220 if (!dp83816_reset(dp)) return false;
222 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
223 cyg_drv_interrupt_create(
225 0, // Priority - unused
226 (cyg_addrword_t)sc, // Data item passed to ISR & DSR
229 &dp->interrupt_handle, // handle to intr obj
230 &dp->interrupt_object ); // space for int obj
232 cyg_drv_interrupt_attach(dp->interrupt_handle);
233 cyg_drv_interrupt_unmask(dp->interrupt);
236 // Initialize upper level driver
237 (sc->funs->eth_drv->init)(sc, dp->enaddr);
243 dp83816_stop(struct eth_drv_sc *sc)
245 dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
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);
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.
259 dp83816_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
261 dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
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);
269 // This routine is called to perform special "control" opertions
272 dp83816_control(struct eth_drv_sc *sc, unsigned long key,
273 void *data, int data_len)
276 case ETH_DRV_SET_MAC_ADDRESS:
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.
290 dp83816_can_send(struct eth_drv_sc *sc)
292 dp83816_priv_data_t *dp = (dp83816_priv_data_t *)sc->driver_private;
295 return (dp->txnum - dp->txbusy);
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).
303 dp83816_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
304 int total_len, unsigned long key)
306 struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
309 dp83816_bd_t *bdp = dp->txfill;
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;
321 bdp->stat = CYG_CPU_TO_LE32(len | BD_OWN | BD_INTR);
323 bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->next)));
325 // Kick the device, in case it went idle
326 DP_OUT(dp->base, DP_CR, _CR_TXE);
330 dp83816_TxEvent(struct eth_drv_sc *sc)
332 struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
333 dp83816_bd_t *bdp = dp->txint;
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
342 bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->next)));
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.
355 dp83816_RxEvent(struct eth_drv_sc *sc)
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);
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);
368 diag_printf("RxError: %x\n", err);
370 len = CYG_LE32_TO_CPU(bdp->stat) & BD_LENGTH_MASK;
372 (sc->funs->eth_drv->recv)(sc, len);
373 bdp->stat = CYG_CPU_TO_LE32(BD_INTR | _DP83816_BUFSIZE); // Give back buffer
375 bdp = (dp83816_bd_t *)CYGARC_UNCACHED_ADDRESS(CYGARC_VIRTUAL_ADDRESS(CYG_LE32_TO_CPU((unsigned long)bdp->next)));
376 if (bdp == bdfirst) {
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.
390 dp83816_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
392 struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
393 dp83816_bd_t *bdp = dp->rxnext;
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;
405 dp83816_warm_reset(struct eth_drv_sc *sc)
407 struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
411 // Free up any active Tx buffers
412 bdp = CYGARC_UNCACHED_ADDRESS(dp->txd);
413 for (i = 0; i < dp->txnum; i++, bdp++) {
415 (sc->funs->eth_drv->tx_done)(sc, bdp->key, 0);
420 DP_OUT(dp->base, DP_CR, _CR_RXE | _CR_TXE);
424 dp83816_poll(struct eth_drv_sc *sc)
426 struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
427 unsigned long stat, cr_stat;
429 DP_IN(dp->base, DP_ISR, stat);
431 if ((stat & (_ISR_TXDESC|_ISR_TXOK)) != 0) {
434 if ((stat & (_ISR_RXDESC|_ISR_RXOK|_ISR_RXERR)) != 0) {
437 DP_IN(dp->base, DP_CR, cr_stat);
438 if ((stat & (_ISR_HIBERR|_ISR_TXURN|_ISR_RXORN)) != 0) {
440 diag_printf("DP83816 - major error: %x, cmd_stat: %x\n", stat, cr_stat);
442 // Try to reset the device
443 dp83816_warm_reset(sc);
445 if (((cr_stat & _CR_RXE) == 0) ||
446 ((dp->txbusy > 1) && ((cr_stat & _CR_TXE) == 0))) {
449 diag_printf("DP83816 went to lunch? - stat: %x/%x, txbusy: %x\n", cr_stat, stat, dp->txbusy);
451 // Try to reset the device
452 dp83816_warm_reset(sc);
454 DP_IN(dp->base, DP_ISR, stat);
456 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
457 CYGHWR_NS_DP83816_PLF_INT_CLEAR(dp);
462 dp83816_int_vector(struct eth_drv_sc *sc)
464 struct dp83816_priv_data *dp = (struct dp83816_priv_data *)sc->driver_private;
465 return dp->interrupt;
468 /* EEPROM Functions */
469 #ifdef CYGHWR_NS_DP83816_USE_EEPROM
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
475 #define DP83816_EEPROM_ADDR_LEN 6
476 #define DP83816_EE_READ_CMD (6 << DP83816_EEPROM_ADDR_LEN)
479 /* EEPROM data is bit-swapped. */
480 static cyg_uint16 dp83816_eeprom_fixup_data(cyg_uint16 input)
482 cyg_uint16 output = 0;
485 for (i = 0; i < 16; i++) {
486 output = (output << 1) | (input & 0x0001);
492 static cyg_uint16 dp83816_eeprom_command(struct dp83816_priv_data *dp, int cmd, int cmd_len)
496 EEPROM_WRITE(dp, _MEAR_EESEL);
499 cyg_uint32 c = (cmd & (1 << cmd_len)) ? _MEAR_EEDI : 0;
502 EEPROM_WRITE(dp, c | _MEAR_EESEL);
504 EEPROM_WRITE(dp, c | _MEAR_EESEL | _MEAR_EECLK);
509 d |= (t & _MEAR_EEDO) ? 1 : 0;
512 EEPROM_WRITE(dp, _MEAR_EESEL);
518 static cyg_uint16 dp83816_eeprom_read(struct dp83816_priv_data *dp, int loc)
522 d = dp83816_eeprom_command(dp, (loc | DP83816_EE_READ_CMD) << 16,
523 3 + DP83816_EEPROM_ADDR_LEN + 16);
525 return dp83816_eeprom_fixup_data(d);
528 #endif /* CYGHWR_NS_DP83816_USE_EEPROM */