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.
35 //==========================================================================
36 //#####DESCRIPTIONBEGIN####
38 // Author(s): Harald Brandl (harald.brandl@fh-joanneum.at)
39 // Contributors: Harald Brandl
41 // Purpose: NET+ARM Ethernet Driver (DMA driven)
44 //####DESCRIPTIONEND####
46 //==========================================================================
48 #include <cyg/infra/cyg_type.h>
49 #include <cyg/hal/hal_arch.h>
50 #include <cyg/infra/diag.h>
51 #include <cyg/hal/drv_api.h>
52 #include <cyg/io/eth/netdev.h>
53 #include <cyg/io/eth/eth_drv.h>
55 #include <pkgconf/devs_eth_arm_netarm.h>
56 #include <cyg/hal/hal_platform_ints.h>
59 #include "netarm_eth_drv.h"
62 #include <cyg/hal/hal_io.h>
64 // FIXME: The HAL should provide this
65 #define CYGNUM_HAL_INTERRUPT_DMA2 31
66 #define CYGNUM_HAL_INTERRUPT_DMA1 32
68 // FIXME: The HAL should provide this and it should handle more than
70 #define HAL_VIRT_TO_PHYS_ADDRESS( vaddr ) (unsigned char *)vaddr - 0x8000000
72 #define BufferSizeA 128
73 #define BufferSizeB 512
74 #define BufferSizeC 1524
80 #define EEPROM_MAC 0 // location of MAC address inside eeprom
82 static cyg_mutex_t Key_Mutex;
83 static private_data_t driver_private;
85 static volatile unsigned char RxBufferA[NumA][BufferSizeA];
86 static volatile unsigned char RxBufferB[NumB][BufferSizeB];
87 static volatile unsigned char RxBufferC[NumC][BufferSizeC];
89 static volatile unsigned char TxBuffer[1500];
90 static volatile unsigned char TxHeader[14];
92 static volatile BDP_t RxBDP_A[NumA];
93 static volatile BDP_t RxBDP_B[NumB];
94 static volatile BDP_t RxBDP_C[NumC];
96 static volatile BDP_t TxBDP[2];
98 // relocation pointer for data accessed by DMA to enable caching
99 static volatile unsigned char *pRxBufferA, *pRxBufferB, *pRxBufferC;
100 static volatile unsigned char *pTxHeader, *pTxBuffer;
101 static volatile BDP_t *pRxBDP_A, *pRxBDP_B, *pRxBDP_C;
102 static volatile BDP_t *pTxBDP;
104 ETH_DRV_SC(netarm_sc,
105 (void *)&driver_private, // driver specific data
106 "eth0", // Name for this interface
117 NETDEVTAB_ENTRY(netarm_netdev,
123 fastcopy(void *buf, void *data, unsigned long len)
129 "TST R1, #2;" // test if aligned
130 "LDRNEH R3, [R1], #2;"
131 "STRNEH R3, [R0], #2;"
134 "LDRNEB R3, [R1], #1;"
135 "STRNEB R3, [R0], #1;"
142 "LDMIA R1!, {R3 - R12, R14};"
143 "STMIA R0!, {R3 - R12, R14};"
148 "LDMIA R1!, {R3 - R12, R14};"
149 "STMIA R0!, {R3 - R12, R14};"
154 "LDMIA R1!, {R3 - R12, R14};"
155 "STMIA R0!, {R3 - R12, R14};"
160 "LDMIA R1!, {R3 - R12, R14};"
161 "STMIA R0!, {R3 - R12, R14};"
166 "LDMIA R1!, {R3 - R12, R14};"
167 "STMIA R0!, {R3 - R12, R14};"
172 "LDMIA R1!, {R3 - R12, R14};"
173 "STMIA R0!, {R3 - R12, R14};"
178 "LDMIA R1!, {R3 - R12, R14};"
179 "STMIA R0!, {R3 - R12, R14};"
184 "LDMIA R1!, {R3 - R12, R14};"
185 "STMIA R0!, {R3 - R12, R14};"
190 "LDMIA R1!, {R3 - R12, R14};"
191 "STMIA R0!, {R3 - R12, R14};"
196 "LDMIA R1!, {R3 - R12, R14};"
197 "STMIA R0!, {R3 - R12, R14};"
205 "AND R14, R2, #0xfffffffc;"
231 "LDMIA R1!, {R3, R4};"
232 "STMIA R0!, {R3, R4};"
236 "LDMIA R1!, {R3 - R5};"
237 "STMIA R0!, {R3 - R5};"
241 "LDMIA R1!, {R3 - R6};"
242 "STMIA R0!, {R3 - R6};"
246 "LDMIA R1!, {R3 - R7};"
247 "STMIA R0!, {R3 - R7};"
251 "LDMIA R1!, {R3 - R8};"
252 "STMIA R0!, {R3 - R8};"
256 "LDMIA R1!, {R3 - R9};"
257 "STMIA R0!, {R3 - R9};"
261 "LDMIA R1!, {R3 - R10};"
262 "STMIA R0!, {R3 - R10};"
266 "LDMIA R1!, {R3 - R11};"
267 "STMIA R0!, {R3 - R11};"
271 "LDMIA R1!, {R3 - R12};"
272 "STMIA R0!, {R3 - R12};"
276 "LDRNEH R3, [R1], #2;"
277 "STRNEH R3, [R0], #2;"
279 "LDRNEB R3, [R1], #1;"
280 "STRNEB R3, [R0], #1;"
285 : "r" (buf), "r" (data), "r" (len)
286 : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14"
291 KeyBufferFull(private_data_t *pd)
295 cyg_drv_mutex_lock(&Key_Mutex);
297 if((pd->key_head + 1) % MaxKeys == pd->key_tail)
302 cyg_drv_mutex_unlock(&Key_Mutex);
308 AddKey(unsigned long key, private_data_t *pd)
311 cyg_drv_mutex_lock(&Key_Mutex);
313 pd->KeyBuffer[pd->key_head] = key;
314 pd->key_head = (pd->key_head + 1) % MaxKeys;
316 cyg_drv_mutex_unlock(&Key_Mutex);
320 GetKey(private_data_t *pd)
324 cyg_drv_mutex_lock(&Key_Mutex);
326 if(pd->key_tail != pd->key_head)
328 key = pd->KeyBuffer[pd->key_tail];
329 pd->key_tail = (pd->key_tail + 1) % MaxKeys;
332 cyg_drv_mutex_unlock(&Key_Mutex);
338 dma_rx_isr(cyg_vector_t vector, cyg_addrword_t data)
341 // block this interrupt until the dsr completes
342 cyg_drv_interrupt_mask(vector);
344 // tell ecos to allow further interrupt processing
345 cyg_drv_interrupt_acknowledge(vector);
347 return CYG_ISR_CALL_DSR; // call the dsr
351 dma_rx_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
354 eth_drv_dsr( vector, count, data );
356 DMA1A_SR = 0x80000000; // acknowledge and mask interrupts
357 DMA1B_SR = 0x80000000;
358 DMA1C_SR = 0x80000000;
360 cyg_drv_interrupt_unmask(vector);
364 dma_tx_isr(cyg_vector_t vector, cyg_addrword_t data)
367 // block this interrupt until the dsr completes
368 cyg_drv_interrupt_mask(vector);
370 // tell ecos to allow further interrupt processing
371 cyg_drv_interrupt_acknowledge(vector);
373 return CYG_ISR_CALL_DSR; // invoke the dsr
377 dma_tx_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
380 eth_drv_dsr( vector, count, data );
382 DMA2_SR |= 0x80000000; // acknowledge interrupt
384 cyg_drv_interrupt_unmask(vector);
392 pRxBufferA = (unsigned char *)HAL_VIRT_TO_PHYS_ADDRESS(RxBufferA);
393 pRxBufferB = (unsigned char *)HAL_VIRT_TO_PHYS_ADDRESS(RxBufferB);
394 pRxBufferC = (unsigned char *)HAL_VIRT_TO_PHYS_ADDRESS(RxBufferC);
396 pTxBuffer = (unsigned char *)HAL_VIRT_TO_PHYS_ADDRESS(TxBuffer);
397 pTxHeader = (unsigned char *)HAL_VIRT_TO_PHYS_ADDRESS(TxHeader);
399 pRxBDP_A = (BDP_t *)HAL_VIRT_TO_PHYS_ADDRESS(RxBDP_A);
400 pRxBDP_B = (BDP_t *)HAL_VIRT_TO_PHYS_ADDRESS(RxBDP_B);
401 pRxBDP_C = (BDP_t *)HAL_VIRT_TO_PHYS_ADDRESS(RxBDP_C);
403 pTxBDP = (BDP_t *)((unsigned char *)TxBDP);
405 *SYSCON |= 0x40; // reset DMA module
407 for(i = 0; i < NumA; i++)
409 pRxBDP_A[i].lo = ((unsigned)(pRxBufferA+i*BufferSizeA)) & 0x3fffffff;
410 pRxBDP_A[i].hi = BufferSizeA;
413 pRxBDP_A[i - 1].lo |= 0x80000000; // set W bit
415 for(i = 0; i < NumB; i++)
417 pRxBDP_B[i].lo = ((unsigned)(pRxBufferB+i*BufferSizeB)) & 0x3fffffff;
418 pRxBDP_B[i].hi = BufferSizeB;
421 pRxBDP_B[i - 1].lo |= 0x80000000;
423 for(i = 0; i < NumC; i++)
425 pRxBDP_C[i].lo = ((unsigned)(pRxBufferC+i*BufferSizeC)) & 0x3fffffff;
426 pRxBDP_C[i].hi = BufferSizeC;
429 pRxBDP_C[i - 1].lo |= 0x80000000;
433 DMA1A_BDP = (unsigned)pRxBDP_A;
434 DMA1A_CR = 0x82000000; //burst transfer
437 DMA1B_BDP = (unsigned)pRxBDP_B;
438 DMA1B_CR = 0x82000000; //burst transfer
441 DMA1C_BDP = (unsigned)pRxBDP_C;
442 DMA1C_CR = 0x82000000; //burst transfer
446 pTxBDP[0].lo = ((unsigned)pTxHeader) & 0x3fffffff;
447 pTxBDP[1].lo = ((unsigned)pTxBuffer) & 0x3fffffff;
448 pTxBDP[1].lo |= 0xa0000000; // set W and L bit
450 DMA2_BDP = (unsigned)pTxBDP;
451 DMA2_CR = 0x86000000; //burst transfer
457 netarm_init(struct cyg_netdevtab_entry *tab)
459 struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
461 static cyg_interrupt dma_rx_int_object, dma_tx_int_object;
462 static cyg_handle_t dma_rx_int_handle, dma_tx_int_handle;
464 #ifdef CYGSEM_DEVS_ETH_ARM_NETARM_ETH0_SET_ESA
466 unsigned char esa[6] = CYGDAT_DEVS_ETH_ARM_NETARM_ETH0_ESA;
468 unsigned char esa[6];
471 eepromRead(0x50, EEPROM_MAC, esa, 6);
474 // setup dma receiver
478 mii_negotiate(); // initialize PHY
479 duplex = mii_check_duplex();
481 // Ethernet Controller Initializatition
483 MACCR = (0x1c | (duplex << 1)); // auto CRC, late collision retry
484 STLCR = 0x3; // insert MAC source address
485 // into ethernet frame
486 BtBIPGGapTimerR = 0x14; // standard values
487 NonBtBIPGGapTimerR = ((0x9 << 7) | 0x11); // standard values
488 CollWinR = ((0x37 << 8) | 0xf); // standard values
489 SAFR = 0x1; // broadcast mode
490 EthGenCR = (0x40400400 | (duplex << 16)); // dma mode, full duplex,
491 // enable pNA mode(needed
494 cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_DMA1, // Interrupt Vector
495 0, // Interrupt Priority
496 (cyg_addrword_t)&netarm_sc, // Reference
504 cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_DMA2, // Interrupt Vector
505 0, // Interrupt Priority
506 (cyg_addrword_t)&netarm_sc, // Reference
514 cyg_drv_interrupt_attach(dma_rx_int_handle);
515 cyg_drv_interrupt_attach(dma_tx_int_handle);
517 cyg_mutex_init(&Key_Mutex);
519 sc->funs->eth_drv->init(sc, esa);
525 netarm_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
528 private_data_t *pd = (private_data_t *)(sc->driver_private);
529 unsigned char *data, *buf = pd->RxBuffer;
531 for (i = 0; i < sg_len; i++) {
532 data = (unsigned char *)(sg_list[i].buf);
533 len = sg_list[i].len;
541 fastcopy(data, buf, len);
548 netarm_deliver(struct eth_drv_sc *sc)
550 static int a = 0, b = 0, c = 0;
552 private_data_t *pd = (private_data_t *)(sc->driver_private);
554 while((key = GetKey(pd)))
556 sc->funs->eth_drv->tx_done(sc, key, 0);
559 while(pRxBDP_A[a].hi & 0x8000)
561 pd->RxBuffer = (unsigned char *)(pRxBDP_A[a].lo & 0x1FFFFFFF);
562 HAL_REORDER_BARRIER();
563 sc->funs->eth_drv->recv(sc, pRxBDP_A[a].hi & 0x7FFF);
564 HAL_REORDER_BARRIER();
565 pRxBDP_A[a].hi = BufferSizeA;
566 HAL_REORDER_BARRIER();
570 while(pRxBDP_B[b].hi & 0x8000)
572 pd->RxBuffer = (unsigned char *)(pRxBDP_B[b].lo & 0x1FFFFFFF);
573 HAL_REORDER_BARRIER();
574 sc->funs->eth_drv->recv(sc, pRxBDP_B[b].hi & 0x7FFF);
575 HAL_REORDER_BARRIER();
576 pRxBDP_B[b].hi = BufferSizeB;
577 HAL_REORDER_BARRIER();
581 while(pRxBDP_C[c].hi & 0x8000)
583 pd->RxBuffer = (unsigned char *)(pRxBDP_C[c].lo & 0x1FFFFFFF);
584 HAL_REORDER_BARRIER();
585 sc->funs->eth_drv->recv(sc, pRxBDP_C[c].hi & 0x7FFF);
586 HAL_REORDER_BARRIER();
587 pRxBDP_C[c].hi = BufferSizeC;
588 HAL_REORDER_BARRIER();
592 if((DMA1A_SR & 0x20000000) || (DMA1B_SR & 0x20000000) || (DMA1C_SR & 0x20000000))
594 EthGenCR &= ~0xc0000000; // reset Rx FIFO
595 EthGenCR |= 0xc0000000;
598 DMA1A_SR = 0x20a00000;
599 DMA1B_SR = 0x20a00000;
600 DMA1C_SR = 0x20a00000;
604 netarm_can_send(struct eth_drv_sc *sc)
606 private_data_t *pd = (private_data_t *)(sc->driver_private);
608 if((pTxBDP[0].hi & 0x8000) || (pTxBDP[1].hi & 0x8000) || KeyBufferFull(pd))
615 netarm_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list,
616 int sg_len, int total_len, unsigned long key)
618 private_data_t *pd = (private_data_t *)(sc->driver_private);
621 volatile char *buf = pTxBuffer;
625 // Put data into buffer
626 for (i = 0; i < sg_len; i++) {
627 data = (unsigned char *)sg_list[i].buf;
628 len = sg_list[i].len;
632 if((unsigned long)data & 0x3)
634 memcpy((unsigned char*)pTxHeader, data, 0xe);
638 fastcopy((unsigned char *)pTxHeader, data, 0xe);
647 fastcopy((unsigned char *)buf, data, len);
653 pTxBDP[0].hi = 0x800e;
654 HAL_REORDER_BARRIER();
655 pTxBDP[1].hi = (total_len - 0xe) | 0x8000;
656 HAL_REORDER_BARRIER();
657 DMA2_SR |= 0xf0000000;
658 cyg_drv_dsr_unlock();
662 netarm_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
664 SetMAC(enaddr); // set MAC address
665 HAL_REORDER_BARRIER();
666 EthGenCR |= 0x80800000; // enable Rx und Tx FIFO
667 HAL_REORDER_BARRIER();
668 cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_DMA1);
669 cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_DMA2);
673 netarm_stop(struct eth_drv_sc *sc)
675 EthGenCR &= 0x7f7fffff;
676 HAL_REORDER_BARRIER();
677 cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_DMA1);
678 cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_DMA2);
682 netarm_control(struct eth_drv_sc *sc, unsigned long key, void *data, int len)
686 case ETH_DRV_SET_MAC_ADDRESS:
689 case ETH_DRV_SET_MC_LIST:
690 case ETH_DRV_SET_MC_ALL:
699 netarm_poll(struct eth_drv_sc *sc)
704 netarm_int_vector(struct eth_drv_sc *sc)
706 return CYGNUM_HAL_INTERRUPT_DMA1;
710 SetMAC(unsigned char *esa)
712 SAR1 = (esa[1] << 8) | esa[0]; // set MAC address
713 SAR2 = (esa[3] << 8) | esa[2];
714 SAR3 = (esa[5] << 8) | esa[4];