1 //==========================================================================
5 // NetSilion NET+ARM Ethernet Driver (DMA driven)
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System
11 // Copyright (C) 2005 eCosCentric Ltd.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //==========================================================================
39 //#####DESCRIPTIONBEGIN####
41 // Author(s): Harald Brandl (harald.brandl@fh-joanneum.at)
42 // Contributors: Harald Brandl
44 // Purpose: NET+ARM Ethernet Driver (DMA driven)
47 //####DESCRIPTIONEND####
49 //==========================================================================
51 #include <cyg/infra/cyg_type.h>
52 #include <cyg/hal/hal_arch.h>
53 #include <cyg/infra/diag.h>
54 #include <cyg/hal/drv_api.h>
55 #include <cyg/io/eth/netdev.h>
56 #include <cyg/io/eth/eth_drv.h>
58 #include <pkgconf/devs_eth_arm_netarm.h>
59 #include <cyg/hal/hal_platform_ints.h>
60 #include <cyg/hal/plf_mmap.h>
63 #include "netarm_eth_drv.h"
67 #define BufferSizeA 128
68 #define BufferSizeB 512
69 #define BufferSizeC 1524
75 #define EEPROM_MAC 0 // location of MAC address inside eeprom
78 static cyg_mutex_t Key_Mutex;
79 static private_data_t driver_private;
81 static unsigned char RxBufferA[NumA][BufferSizeA] __attribute__ ((aligned (4)));
82 static unsigned char RxBufferB[NumB][BufferSizeB] __attribute__ ((aligned (4)));
83 static unsigned char RxBufferC[NumC][BufferSizeC] __attribute__ ((aligned (4)));
85 static unsigned char TxBuffer[1518] __attribute__ ((aligned (4)));
87 static BDP_t RxBDP_A[NumA];
88 static BDP_t RxBDP_B[NumB];
89 static BDP_t RxBDP_C[NumC];
93 // relocation pointer for data accessed by DMA to enable caching
94 static unsigned char *pRxBufferA = (unsigned char *)RxBufferA,
95 *pRxBufferB = (unsigned char *)RxBufferB,
96 *pRxBufferC = (unsigned char *)RxBufferC;
97 static unsigned char *pTxBuffer = TxBuffer;
99 static BDP_t *pRxBDP_A = RxBDP_A, *pRxBDP_B = RxBDP_B, *pRxBDP_C = RxBDP_C;
100 static BDP_t *pTxBDP = &TxBDP;
103 ETH_DRV_SC(netarm_sc,
104 (void *)&driver_private, // driver specific data
105 "eth0", // name for this interface
117 NETDEVTAB_ENTRY(netarm_netdev,
124 #define fastcopy memcpy
127 fastcopy(void *buf, void *data, unsigned long len)
133 "TST R1, #2;" // test if aligned
134 "LDRNEH R3, [R1], #2;"
135 "STRNEH R3, [R0], #2;"
138 "LDRNEB R3, [R1], #1;"
139 "STRNEB R3, [R0], #1;"
146 "LDMIA R1!, {R3 - R12, R14};"
147 "STMIA R0!, {R3 - R12, R14};"
152 "LDMIA R1!, {R3 - R12, R14};"
153 "STMIA R0!, {R3 - R12, R14};"
158 "LDMIA R1!, {R3 - R12, R14};"
159 "STMIA R0!, {R3 - R12, R14};"
164 "LDMIA R1!, {R3 - R12, R14};"
165 "STMIA R0!, {R3 - R12, R14};"
170 "LDMIA R1!, {R3 - R12, R14};"
171 "STMIA R0!, {R3 - R12, R14};"
176 "LDMIA R1!, {R3 - R12, R14};"
177 "STMIA R0!, {R3 - R12, R14};"
182 "LDMIA R1!, {R3 - R12, R14};"
183 "STMIA R0!, {R3 - R12, R14};"
188 "LDMIA R1!, {R3 - R12, R14};"
189 "STMIA R0!, {R3 - R12, R14};"
194 "LDMIA R1!, {R3 - R12, R14};"
195 "STMIA R0!, {R3 - R12, R14};"
200 "LDMIA R1!, {R3 - R12, R14};"
201 "STMIA R0!, {R3 - R12, R14};"
209 "AND R14, R2, #0xfffffffc;"
235 "LDMIA R1!, {R3, R4};"
236 "STMIA R0!, {R3, R4};"
240 "LDMIA R1!, {R3 - R5};"
241 "STMIA R0!, {R3 - R5};"
245 "LDMIA R1!, {R3 - R6};"
246 "STMIA R0!, {R3 - R6};"
250 "LDMIA R1!, {R3 - R7};"
251 "STMIA R0!, {R3 - R7};"
255 "LDMIA R1!, {R3 - R8};"
256 "STMIA R0!, {R3 - R8};"
260 "LDMIA R1!, {R3 - R9};"
261 "STMIA R0!, {R3 - R9};"
265 "LDMIA R1!, {R3 - R10};"
266 "STMIA R0!, {R3 - R10};"
270 "LDMIA R1!, {R3 - R11};"
271 "STMIA R0!, {R3 - R11};"
275 "LDMIA R1!, {R3 - R12};"
276 "STMIA R0!, {R3 - R12};"
280 "LDRNEH R3, [R1], #2;"
281 "STRNEH R3, [R0], #2;"
283 "LDRNEB R3, [R1], #1;"
284 "STRNEB R3, [R0], #1;"
289 : "r" (buf), "r" (data), "r" (len)
290 : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14"
296 KeyBufferFull(private_data_t *pd)
300 cyg_drv_mutex_lock(&Key_Mutex);
302 if((pd->key_head + 1) % MaxKeys == pd->key_tail)
307 cyg_drv_mutex_unlock(&Key_Mutex);
314 AddKey(unsigned long key, private_data_t *pd)
317 cyg_drv_mutex_lock(&Key_Mutex);
319 pd->KeyBuffer[pd->key_head] = key;
320 pd->key_head = (pd->key_head + 1) % MaxKeys;
322 cyg_drv_mutex_unlock(&Key_Mutex);
326 GetKey(private_data_t *pd)
330 cyg_drv_mutex_lock(&Key_Mutex);
332 if(pd->key_tail != pd->key_head)
334 key = pd->KeyBuffer[pd->key_tail];
335 pd->key_tail = (pd->key_tail + 1) % MaxKeys;
338 cyg_drv_mutex_unlock(&Key_Mutex);
345 dma_rx_isr(cyg_vector_t vector, cyg_addrword_t data)
348 // block this interrupt until the dsr completes
349 cyg_drv_interrupt_mask(vector);
351 // tell ecos to allow further interrupt processing
352 cyg_drv_interrupt_acknowledge(vector);
354 return CYG_ISR_CALL_DSR; // call the dsr
358 dma_rx_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
361 eth_drv_dsr( vector, count, data );
363 HAL_WRITE_UINT32(DMA1A_SR, 0x80000000); // acknowledge and mask interrupts
364 HAL_WRITE_UINT32(DMA1B_SR, 0x80000000);
365 HAL_WRITE_UINT32(DMA1C_SR, 0x80000000);
367 cyg_drv_interrupt_unmask(vector);
371 dma_tx_isr(cyg_vector_t vector, cyg_addrword_t data)
374 // block this interrupt until the dsr completes
375 cyg_drv_interrupt_mask(vector);
377 // tell ecos to allow further interrupt processing
378 cyg_drv_interrupt_acknowledge(vector);
380 return CYG_ISR_CALL_DSR; // invoke the dsr
384 dma_tx_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
387 eth_drv_dsr( vector, count, data );
389 HAL_OR_UINT32(DMA2_SR, 0x80000000); // acknowledge interrupt
391 cyg_drv_interrupt_unmask(vector);
399 /* map DMA shared data to non-cached ram */
400 #ifdef CYGSEM_HAL_ENABLE_DCACHE_ON_STARTUP
401 HAL_CACHED_TO_UNCACHED_ADDRESS(RxBufferA, pRxBufferA, unsigned char *);
402 HAL_CACHED_TO_UNCACHED_ADDRESS(RxBufferB, pRxBufferB, unsigned char *);
403 HAL_CACHED_TO_UNCACHED_ADDRESS(RxBufferC, pRxBufferC, unsigned char *);
405 HAL_CACHED_TO_UNCACHED_ADDRESS(TxBuffer, pTxBuffer, unsigned char *);
407 HAL_CACHED_TO_UNCACHED_ADDRESS(RxBDP_A, pRxBDP_A, BDP_t *);
408 HAL_CACHED_TO_UNCACHED_ADDRESS(RxBDP_B, pRxBDP_B, BDP_t *);
409 HAL_CACHED_TO_UNCACHED_ADDRESS(RxBDP_C, pRxBDP_C, BDP_t *);
411 HAL_CACHED_TO_UNCACHED_ADDRESS(TxBDP, pTxBDP, BDP_t * );
414 HAL_OR_UINT32(SYSCON, 0x40); // reset DMA module
416 for(i = 0; i < NumA; i++)
418 pRxBDP_A[i].lo = ((unsigned)(pRxBufferA + i*BufferSizeA)) & 0x3fffffff;
419 pRxBDP_A[i].hi = BufferSizeA;
422 pRxBDP_A[i - 1].lo |= 0x80000000; // set W bit
424 for(i = 0; i < NumB; i++)
426 pRxBDP_B[i].lo = ((unsigned)(pRxBufferB + i*BufferSizeB)) & 0x3fffffff;
427 pRxBDP_B[i].hi = BufferSizeB;
430 pRxBDP_B[i - 1].lo |= 0x80000000;
432 for(i = 0; i < NumC; i++)
434 pRxBDP_C[i].lo = ((unsigned)(pRxBufferC + i*BufferSizeC)) & 0x3fffffff;
435 pRxBDP_C[i].hi = BufferSizeC;
438 pRxBDP_C[i - 1].lo |= 0x80000000;
440 HAL_AND_UINT32(SYSCON, ~0x40);
442 HAL_WRITE_UINT32(DMA1A_BDP, (unsigned)pRxBDP_A);
443 HAL_WRITE_UINT32(DMA1A_CR, 0x82000000); //burst transfer
444 HAL_WRITE_UINT32(DMA1A_SR, 0xa00000);
446 HAL_WRITE_UINT32(DMA1B_BDP, (unsigned)pRxBDP_B);
447 HAL_WRITE_UINT32(DMA1B_CR, 0x82000000); //burst transfer
448 HAL_WRITE_UINT32(DMA1B_SR, 0xa00000);
450 HAL_WRITE_UINT32(DMA1C_BDP, (unsigned)pRxBDP_C);
451 HAL_WRITE_UINT32(DMA1C_CR, 0x82000000); //burst transfer
452 HAL_WRITE_UINT32(DMA1C_SR, 0xa00000);
455 pTxBDP->lo = ((unsigned)pTxBuffer) & 0x3fffffff;
456 pTxBDP->lo |= 0xa0000000; // set W and L bit
458 HAL_WRITE_UINT32(DMA2_BDP, (unsigned)pTxBDP);
459 HAL_WRITE_UINT32(DMA2_CR, 0x86000000); //burst transfer
460 HAL_WRITE_UINT32(DMA2_SR, 0x800000);
465 netarm_init(struct cyg_netdevtab_entry *tab)
467 struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
469 static cyg_interrupt dma_rx_int_object, dma_tx_int_object;
470 static cyg_handle_t dma_rx_int_handle, dma_tx_int_handle;
472 #ifdef CYGSEM_DEVS_ETH_ARM_NETARM_ETH0_SET_ESA
474 unsigned char esa[6] = CYGDAT_DEVS_ETH_ARM_NETARM_ETH0_ESA;
476 unsigned char esa[6];
478 cyg_netarm_initI2C();
479 cyg_netarm_eepromRead(0x50, EEPROM_MAC, esa, 6);
482 // setup dma receiver
485 cyg_netarm_mii_reset();
486 cyg_netarm_mii_negotiate(); // initialize PHY
487 duplex = cyg_netarm_mii_check_duplex();
489 // Ethernet Controller Initializatition
491 // auto CRC, late collision retry
492 HAL_WRITE_UINT32(MACCR, 0x1c | (duplex << 1));
493 // insert MAC source address into ethernet frame
494 HAL_WRITE_UINT32(STLCR, 0x3);
495 HAL_WRITE_UINT32(BtBIPGGapTimerR, 0x14); // standard values
496 HAL_WRITE_UINT32(NonBtBIPGGapTimerR, (0x9 << 7) | 0x11);// standard values
497 HAL_WRITE_UINT32(CollWinR, (0x37 << 8) | 0xf); // standard values
498 HAL_WRITE_UINT32(SAFR, 0x1); // broadcast mode
499 // dma mode, full duplex, enable pNA mode(needed for alignment)
500 HAL_WRITE_UINT32(EthGenCR, 0x40400400 | (duplex << 16));
502 cyg_drv_interrupt_create(
503 CYGNUM_HAL_INTERRUPT_DMA1, // Interrupt Vector
504 0, // Interrupt Priority
505 (cyg_addrword_t)&netarm_sc, // Reference to Driver Instance
511 cyg_drv_interrupt_create(
512 CYGNUM_HAL_INTERRUPT_DMA2, // Interrupt Vector
513 0, // Interrupt Priority
514 (cyg_addrword_t)&netarm_sc, // Reference to Driver Instance
520 cyg_drv_interrupt_attach(dma_rx_int_handle);
522 cyg_drv_interrupt_attach(dma_tx_int_handle);
524 cyg_mutex_init(&Key_Mutex);
526 sc->funs->eth_drv->init(sc, esa);
533 netarm_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
536 private_data_t *pd = (private_data_t *)(sc->driver_private);
537 unsigned char *data, *buf = pd->RxBuffer;
539 for (i = 0; i < sg_len; i++) {
540 data = (unsigned char *)(sg_list[i].buf);
541 len = sg_list[i].len;
549 fastcopy(data, buf, len);
557 netarm_deliver(struct eth_drv_sc *sc)
559 static int a = 0, b = 0, c = 0;
560 unsigned key, rega, regb, regc;
561 private_data_t *pd = (private_data_t *)(sc->driver_private);
564 while((key = GetKey(pd)))
566 sc->funs->eth_drv->tx_done(sc, key, 0);
569 while(pRxBDP_A[a].hi & 0x8000)
571 pd->RxBuffer = (unsigned char *)(pRxBDP_A[a].lo & 0x1FFFFFFF);
572 HAL_REORDER_BARRIER();
573 sc->funs->eth_drv->recv(sc, pRxBDP_A[a].hi & 0x7FFF);
574 HAL_REORDER_BARRIER();
575 pRxBDP_A[a].hi = BufferSizeA;
576 HAL_REORDER_BARRIER();
580 while(pRxBDP_B[b].hi & 0x8000)
582 pd->RxBuffer = (unsigned char *)(pRxBDP_B[b].lo & 0x1FFFFFFF);
583 HAL_REORDER_BARRIER();
584 sc->funs->eth_drv->recv(sc, pRxBDP_B[b].hi & 0x7FFF);
585 HAL_REORDER_BARRIER();
586 pRxBDP_B[b].hi = BufferSizeB;
587 HAL_REORDER_BARRIER();
591 while(pRxBDP_C[c].hi & 0x8000)
593 pd->RxBuffer = (unsigned char *)(pRxBDP_C[c].lo & 0x1FFFFFFF);
594 HAL_REORDER_BARRIER();
595 sc->funs->eth_drv->recv(sc, pRxBDP_C[c].hi & 0x7FFF);
596 HAL_REORDER_BARRIER();
597 pRxBDP_C[c].hi = BufferSizeC;
598 HAL_REORDER_BARRIER();
602 HAL_READ_UINT32(DMA1A_SR, rega);
603 HAL_READ_UINT32(DMA1B_SR, regb);
604 HAL_READ_UINT32(DMA1C_SR, regc);
606 if((rega & 0x20000000) || (regb & 0x20000000) || (regc & 0x20000000))
608 HAL_AND_UINT32(EthGenCR, ~0xc0000000); // reset Rx FIFO
609 HAL_OR_UINT32(EthGenCR, 0xc0000000);
612 HAL_WRITE_UINT32(DMA1A_SR, 0x20a00000);
613 HAL_WRITE_UINT32(DMA1B_SR, 0x20a00000);
614 HAL_WRITE_UINT32(DMA1C_SR, 0x20a00000);
619 netarm_can_send(struct eth_drv_sc *sc)
621 private_data_t *pd = (private_data_t *)(sc->driver_private);
623 if((pTxBDP->hi & 0x8000) || KeyBufferFull(pd))
630 netarm_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list,
631 int sg_len, int total_len, unsigned long key)
633 private_data_t *pd = (private_data_t *)(sc->driver_private);
635 unsigned char *data, *buf = pTxBuffer;
639 // Put data into buffer
640 for(i = 0; i < sg_len; i++) {
641 data = (unsigned char *)sg_list[i].buf;
642 len = sg_list[i].len;
646 if(((unsigned)buf & 0x3) != ((unsigned)data & 0x3))
648 memcpy(buf, data, len);
652 fastcopy(buf, data, len);
660 pTxBDP->hi = total_len | 0x8000;
661 HAL_REORDER_BARRIER();
662 HAL_OR_UINT32(DMA2_SR, 0xf0000000);
663 cyg_drv_dsr_unlock();
668 netarm_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
670 setMAC(enaddr); // set MAC address
671 HAL_REORDER_BARRIER();
672 HAL_OR_UINT32(EthGenCR, 0x80800000); // enable Rx und Tx FIFO
673 HAL_REORDER_BARRIER();
674 cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_DMA1);
675 cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_DMA2);
679 netarm_stop(struct eth_drv_sc *sc)
681 HAL_AND_UINT32(EthGenCR, 0x7f7fffff);
682 HAL_REORDER_BARRIER();
683 cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_DMA1);
684 cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_DMA2);
688 netarm_control(struct eth_drv_sc *sc, unsigned long key, void *data, int len)
694 netarm_poll(struct eth_drv_sc *sc)
699 netarm_int_vector(struct eth_drv_sc *sc)
701 return CYGNUM_HAL_INTERRUPT_DMA1;
705 setMAC(unsigned char *esa)
707 HAL_WRITE_UINT32(SAR1, (esa[1] << 8) | esa[0]); // set MAC address
708 HAL_WRITE_UINT32(SAR2, (esa[3] << 8) | esa[2]);
709 HAL_WRITE_UINT32(SAR3, (esa[5] << 8) | esa[4]);