GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / arch / mips / board / bcm96345 / src / dev_bcm6345_eth.c
blob1429c6ca9360b9e8384b476b513c04af1359dbbc
1 /*
2 <:copyright-broadcom
4 Copyright (c) 2002 Broadcom Corporation
5 All Rights Reserved
6 No portions of this material may be reproduced in any form without the
7 written permission of:
8 Broadcom Corporation
9 16215 Alton Parkway
10 Irvine, California 92619
11 All information contained in this document is Broadcom Corporation
12 company private, proprietary, and trade secret.
16 #include "lib_types.h"
17 #include "lib_malloc.h"
18 #include "lib_string.h"
19 #include "lib_printf.h"
21 #include "cfe_iocb.h"
22 #include "cfe_ioctl.h"
23 #include "cfe_device.h"
24 #include "cfe_devfuncs.h"
25 #include "sbmips.h"
27 #include "dev_bcm6345_eth.h"
28 extern int sysGetBoardId(void);
30 static void bcm6345_ether_probe( cfe_driver_t * drv, unsigned long probe_a,
31 unsigned long probe_b, void * probe_ptr );
32 static int bcm6345_ether_open(cfe_devctx_t *ctx);
33 static int bcm6345_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
34 static int bcm6345_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
35 static int bcm6345_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
36 static int bcm6345_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
37 static int bcm6345_ether_close(cfe_devctx_t *ctx);
38 static void bcm6345_write_mac_address(bcm6345_softc *softc, unsigned char *macAddr);
40 const static cfe_devdisp_t bcm6345_ether_dispatch = {
41 bcm6345_ether_open,
42 bcm6345_ether_read,
43 bcm6345_ether_inpstat,
44 bcm6345_ether_write,
45 bcm6345_ether_ioctl,
46 bcm6345_ether_close,
47 NULL,
48 NULL
51 const cfe_driver_t bcm6345_enet = {
52 "BCM6345 Ethernet",
53 "eth",
54 CFE_DEV_NETWORK,
55 &bcm6345_ether_dispatch,
56 bcm6345_ether_probe
59 extern cfe_driver_t flashdrv;
61 static void bcm6345_ether_probe( cfe_driver_t * drv, unsigned long probe_a,
62 unsigned long probe_b, void * probe_ptr )
64 bcm6345_softc * softc;
65 char descr[100];
67 softc = (bcm6345_softc *) KMALLOC( sizeof(bcm6345_softc), 0 );
68 if( softc == NULL ) {
69 xprintf( "BCM6345 : Failed to allocate softc memory.\n" );
70 } else {
71 memset( softc, 0, sizeof(bcm6345_softc) );
73 if (internal_open( softc ) == -1)
74 xprintf("Failed initializing enet hardware\n");
75 else
77 cfe_attach( drv, softc, NULL, descr );
78 cfe_attach(&flashdrv, softc, NULL, NULL);
85 static int bcm6345_ether_open(cfe_devctx_t *ctx)
87 return 0;
93 * mii_write: Write a value to the MII
95 static void mii_write(uint32 uPhyAddr, uint32 uRegAddr, uint32 data)
97 uint32 d;
98 d = 0x50020000 | (uPhyAddr << 23) | (uRegAddr << 18) | data;
99 EMAC->mdioData = d;
100 delay_t(MII_WRITE_DELAY);
101 while ( ! (EMAC->intStatus & 0x1) );
102 EMAC->intStatus = 0x1;
106 * mii_read: Read a value from the MII
108 static uint32 mii_read(uint32 uPhyAddr, uint32 uRegAddr)
110 EMAC->mdioData = 0x60020000 | (uPhyAddr << 23) | (uRegAddr << 18);
111 delay_t(MII_WRITE_DELAY);
112 while ( ! (EMAC->intStatus & 0x00000001) );
113 EMAC->intStatus = 0x1;
114 return EMAC->mdioData;
118 * mii_GetConfig: Return the current MII configuration
120 static MII_CONFIG mii_GetConfig(bcm6345_softc *softc)
122 uint32 uData;
123 MII_CONFIG eConfig = 0;
125 /* Read the Link Partner Ability */
126 uData = mii_read(softc->phyAddr, 0x05) & 0x0000FFFF;
127 if (uData & 0x0100) { /* 100 MB Full-Duplex */
128 eConfig = (MII_100MBIT | MII_FULLDUPLEX);
129 } else if (uData & 0x0080) { /* 100 MB Half-Duplex */
130 eConfig = MII_100MBIT;
131 } else if (uData & 0x0040) { /* 10 MB Full-Duplex */
132 eConfig = MII_FULLDUPLEX;
135 return eConfig;
139 * mii_AutoConfigure: Auto-Configure this MII interface
141 static MII_CONFIG mii_AutoConfigure(bcm6345_softc *softc)
143 int i;
144 uint32 uData;
145 MII_CONFIG eConfig;
147 /* enable and restart autonegotiation */
148 uData = mii_read(softc->phyAddr, 0) & 0x0000FFFF;
149 uData |= (EPHY_RESTART_AUTONEGOTIATION | EPHY_AUTONEGOTIATE);
150 mii_write(softc->phyAddr, 0x00, uData);
152 /* wait for it to finish */
153 for (i = 0; i < 1000; i++) {
154 delay_t(MII_READ_DELAY);
155 uData = mii_read(softc->phyAddr, 0x01);
156 if (uData & EPHY_AUTONEGOTIATION_COMPLETE) {
157 break;
161 eConfig = mii_GetConfig(softc);
162 if (uData & EPHY_AUTONEGOTIATION_COMPLETE) {
163 eConfig |= MII_AUTONEG;
166 mii_write(softc->phyAddr, 0x1A, 0x0F00);
168 return eConfig;
172 * soft_reset: Reset the MII
174 static void soft_reset(uint32 uPhyAddr)
176 uint32 uData;
178 mii_write(uPhyAddr, 0, 0x8000);
180 delay_t(MII_WRITE_DELAY);
181 do {
182 uData = mii_read(uPhyAddr, 0);
183 } while (uData & 0x00008000);
186 * init_emac: Initializes the Ethernet control registers
188 static void init_emac(bcm6345_softc *softc)
190 MII_CONFIG eMiiConfig;
192 /* disable ethernet MAC while updating its registers */
193 EMAC->config = EMAC_DISABLE ;
194 while(EMAC->config & EMAC_DISABLE);
196 /* issue soft reset, wait for it to complete */
197 EMAC->config = EMAC_SOFT_RESET;
198 while (EMAC->config & EMAC_SOFT_RESET);
200 switch(sysGetBoardId())
202 case BOARD_ID_BCM96345GW:
203 case BOARD_ID_BCM96345I:
204 softc->phyAddr = MII_EXTERNAL;
205 break;
207 case BOARD_ID_BCM96345R00:
208 case BOARD_ID_BCM96345R10:
209 case BOARD_ID_BCM96345SV:
210 case BOARD_ID_BCM96345USB:
211 default:
212 softc->phyAddr = MII_INTERNAL;
213 break;
216 /* init mii clock, do soft reset of phy, default is 10Base-T */
217 if (softc->phyAddr == MII_EXTERNAL) {
218 EMAC->config = EMAC_EXT_PHY;
219 EMAC->mdioFreq = EMAC_MII_PRE_EN | 0x005;
220 EMAC->txControl = EMAC_FD; /* FULL DUPLEX */
221 } else {
222 /* init mii clock, do soft reset of phy, default is 10Base-T */
223 EMAC->mdioFreq = EMAC_MII_PRE_EN | 0x01F;
224 soft_reset(softc->phyAddr);
226 eMiiConfig = mii_AutoConfigure(softc);
228 if (! (eMiiConfig & MII_AUTONEG)) {
229 xprintf("Auto-negotiation timed-out\n");
232 if (eMiiConfig & (MII_100MBIT | MII_FULLDUPLEX)) {
233 xprintf("100 MB Full-Duplex (auto-neg)\n");
234 } else if (eMiiConfig & MII_100MBIT) {
235 xprintf("100 MB Half-Duplex (auto-neg)\n");
236 } else if (eMiiConfig & MII_FULLDUPLEX) {
237 xprintf("0 MB Full-Duplex (auto-neg)\n");
238 } else {
239 xprintf("0 MB Half-Duplex (assumed)\n");
242 /* Check for FULL/HALF duplex */
243 if (eMiiConfig & MII_FULLDUPLEX) {
244 EMAC->txControl = EMAC_FD; /* FULL DUPLEX */
248 /* Initialize emac registers */
249 EMAC->rxControl = EMAC_FC_EN | EMAC_PROM; // allow Promiscuous
251 #ifdef MAC_LOOPBACK
252 EMAC->rxControl |= EMAC_LOOPBACK;
253 #endif
254 EMAC->rxMaxLength = ENET_MAX_MTU_SIZE;
255 EMAC->txMaxLength = ENET_MAX_MTU_SIZE;
257 /* tx threshold = abs(63-(0.63*EMAC_DMA_MAX_BURST_LENGTH)) */
258 EMAC->txThreshold = 16;
259 EMAC->mibControl = 0x01; /* clear MIBs on read */
260 EMAC->intMask = 0; /* mask all EMAC interrupts*/
262 EMAC->config |= EMAC_ENABLE;
265 * init_dma: Initialize DMA control register
267 static void init_dma(bcm6345_softc *softc)
269 // transmit
270 softc->txDma->cfg = 0; /* initialize first (will enable later) */
271 softc->txDma->maxBurst = DMA_MAX_BURST_LENGTH;
272 softc->txDma->startAddr = K1_TO_PHYS((uint32_t)(softc->txBds));
273 softc->txDma->length = NR_TX_BDS;
274 softc->txDma->fcThreshold = 0;
275 softc->txDma->numAlloc = 0;
276 softc->txDma->intMask = 0; /* mask all ints */
277 /* clr any pending interrupts on channel */
278 softc->txDma->intStat = DMA_DONE|DMA_NO_DESC|DMA_BUFF_DONE;
279 softc->txDma->intMask = DMA_DONE;
281 // receive
282 softc->rxDma->cfg = 0; // initialize first (will enable later)
283 softc->rxDma->maxBurst = DMA_MAX_BURST_LENGTH;
284 softc->rxDma->startAddr = K1_TO_PHYS((uint32_t)softc->rxBds);
285 softc->rxDma->length = NR_RX_BDS;
286 softc->rxDma->fcThreshold = 0;
287 softc->rxDma->numAlloc = 0;
288 softc->rxDma->intMask = 0; /* mask all ints */
289 /* clr any pending interrupts on channel */
290 softc->rxDma->intStat = DMA_DONE|DMA_NO_DESC|DMA_BUFF_DONE;
291 softc->rxDma->intMask = DMA_DONE;
293 /* configure DMA channels and enable Rx */
294 softc->txDma->cfg = DMA_CHAINING|DMA_WRAP_EN|DMA_FLOWC_EN;
295 softc->rxDma->cfg = DMA_CHAINING|DMA_WRAP_EN|DMA_FLOWC_EN;
299 static int internal_open(bcm6345_softc * softc)
302 int i;
303 void *p;
305 /* make sure emac clock is on */
306 INTC->blkEnables |= EMAC_CLK_EN;
308 /* init rx/tx dma channels */
309 softc->dmaChannels = (DmaChannel *)(DMA_BASE);
310 softc->rxDma = &softc->dmaChannels[EMAC_RX_CHAN];
311 softc->txDma = &softc->dmaChannels[EMAC_TX_CHAN];
313 p = KMALLOC( NR_TX_BDS * sizeof(DmaDesc), 0 );
314 if( p == NULL ) {
315 xprintf( "BCM6345 : Failed to allocate txBds memory.\n" );
316 KFREE( (void *)(softc->rxBds) );
317 softc->rxBds = NULL;
318 return -1;
321 softc->txBds = (DmaDesc *)K0_TO_K1((uint32) p);
322 p = KMALLOC( NR_RX_BDS * sizeof(DmaDesc), 0 );
323 if( p== NULL ) {
324 xprintf( "BCM6345 : Failed to allocate rxBds memory.\n" );
325 return -1;
327 softc->rxBds = (DmaDesc *)K0_TO_K1((uint32) p);
330 softc->rxBuffers = (uint32_t)KMALLOC( NR_RX_BDS * ENET_MAX_MTU_SIZE, 0 );
331 if( softc->rxBuffers == NULL ) {
332 xprintf( "BCM6345 : Failed to allocate RxBuffer memory.\n" );
333 KFREE( (void *)(softc->txBds) );
334 softc->txBds = NULL;
335 KFREE( (void *)(softc->rxBds) );
336 softc->rxBds = NULL;
337 return -1;
340 softc->txBuffers = (uint32_t)KMALLOC( NR_TX_BDS * ENET_MAX_MTU_SIZE, 0 );
341 if( softc->txBuffers == NULL ) {
342 xprintf( "BCM6345 : Failed to allocate txBuffer memory.\n" );
343 KFREE( (void *)(softc->rxBuffers) );
344 softc->rxBuffers = NULL;
345 KFREE( (void *)(softc->txBds) );
346 softc->txBds = NULL;
347 KFREE( (void *)(softc->rxBds) );
348 softc->rxBds = NULL;
349 return -1;
352 /* Init the Receive Buffer Descriptor Ring. */
353 softc->rxFirstBdPtr = softc->rxBdReadPtr = softc->rxBds;
354 softc->rxLastBdPtr = softc->rxBds + NR_RX_BDS - 1;
356 for(i = 0; i < NR_RX_BDS; i++) {
357 (softc->rxBds + i)->status = DMA_OWN;
358 (softc->rxBds + i)->length = ENET_MAX_MTU_SIZE;
359 (softc->rxBds + i)->address = softc->rxBuffers + i * ENET_MAX_MTU_SIZE;
360 (softc->rxBds + i)->address = K1_TO_PHYS( (softc->rxBds + i)->address );
361 softc->rxDma->numAlloc = 1;
363 softc->rxLastBdPtr->status |= DMA_WRAP;
365 /* Init Transmit Buffer Descriptor Ring. */
366 softc->txFirstBdPtr = softc->txNextBdPtr = softc->txBds;
367 softc->txLastBdPtr = softc->txBds + NR_TX_BDS - 1;
369 for(i = 0; i < NR_TX_BDS; i++) {
370 (softc->txBds + i)->status = 0;
371 (softc->txBds + i)->length = 0; //ENET_MAX_MTU_SIZE;
372 (softc->txBds + i)->address = softc->txBuffers + i * ENET_MAX_MTU_SIZE;
373 (softc->txBds + i)->address = K1_TO_PHYS( (softc->txBds + i)->address );
375 softc->txLastBdPtr->status = DMA_WRAP;
377 /* init dma registers */
378 init_dma(softc);
380 /* init enet control registers */
381 init_emac(softc);
382 memcpy(softc->hwaddr, "\x18\x10\x18\x01\x00\x01", ETH_ALEN);
384 bcm6345_write_mac_address( softc, softc->hwaddr);
386 softc->rxDma->cfg |= DMA_ENABLE;
388 return 0;
393 static int bcm6345_ether_read( cfe_devctx_t * ctx, iocb_buffer_t * buffer )
395 uint32_t rxEvents;
396 unsigned char * dstptr;
397 unsigned char * srcptr;
398 volatile DmaDesc * CurrentBdPtr;
399 bcm6345_softc * softc = (bcm6345_softc *) ctx->dev_softc;
400 uint16 dmaFlag;
402 if( ctx == NULL ) {
403 xprintf( "No context\n" );
404 return -1;
407 if( buffer == NULL ) {
408 xprintf( "No dst buffer\n" );
409 return -1;
412 if( buffer->buf_length > ENET_MAX_MTU_SIZE ) {
413 xprintf( "dst buffer too small.\n" );
414 xprintf( "actual size is %d\n", buffer->buf_length );
415 return -1;
418 if( softc == NULL ) {
419 xprintf( "softc has not been initialized.\n" );
420 return -1;
423 dmaFlag = (uint16) softc->rxBdReadPtr->status;
424 if (!(dmaFlag & DMA_EOP))
426 xprintf("dmaFlag (return -1)[%04x]\n", dmaFlag);
427 return -1;
430 dstptr = buffer->buf_ptr;
431 CurrentBdPtr = softc->rxBdReadPtr;
433 srcptr = (unsigned char *)( PHYS_TO_K1(CurrentBdPtr->address) );
435 buffer->buf_retlen = CurrentBdPtr->length;
436 memcpy( dstptr, srcptr, buffer->buf_retlen );
438 CurrentBdPtr->length = ENET_MAX_MTU_SIZE;
439 CurrentBdPtr->status = DMA_OWN;
440 if( CurrentBdPtr == softc->rxLastBdPtr )
441 CurrentBdPtr->status |= DMA_WRAP;
443 IncRxBdPtr( CurrentBdPtr, softc );
444 softc->rxBdReadPtr = CurrentBdPtr;
445 softc->rxDma->numAlloc = 1;
447 rxEvents = softc->rxDma->intStat;
449 if (rxEvents & DMA_BUFF_DONE)
451 softc->rxDma->intStat = DMA_BUFF_DONE; // clr interrupt
453 //Complete packet placed in memory.
454 if (rxEvents & DMA_DONE)
456 softc->rxDma->intStat = DMA_DONE; // clr interrupt
458 else {
459 return -1;
462 if (rxEvents & DMA_NO_DESC)
464 softc->rxDma->intStat |= DMA_NO_DESC; // clr interrupt
467 // enable rx dma
468 softc->rxDma->cfg = DMA_ENABLE |DMA_CHAINING|DMA_WRAP_EN;
469 return 0;
473 static int bcm6345_ether_inpstat( cfe_devctx_t * ctx, iocb_inpstat_t * inpstat )
475 bcm6345_softc * softc;
476 volatile DmaDesc * CurrentBdPtr;
478 /* ============================= ASSERTIONS ============================= */
480 if( ctx == NULL ) {
481 xprintf( "No context\n" );
482 return -1;
485 if( inpstat == NULL ) {
486 xprintf( "No inpstat buffer\n" );
487 return -1;
490 softc = (bcm6345_softc *)ctx->dev_softc;
491 if( softc == NULL ) {
492 xprintf( "softc has not been initialized.\n" );
493 return -1;
496 /* ====================================================================== */
499 CurrentBdPtr = softc->rxBdReadPtr;
501 // inp_status == 1 -> data available
502 inpstat->inp_status = (CurrentBdPtr->status & DMA_OWN) ? 0 : 1;
504 return 0;
508 static int bcm6345_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
510 uint32_t status;
511 unsigned char * dstptr;
512 bcm6345_softc * softc;
513 volatile DmaDesc * CurrentBdPtr;
514 volatile uint32 txEvents = 0;
516 /* ============================= ASSERTIONS ============================= */
518 if( ctx == NULL ) {
519 xprintf( "No context\n" );
520 return -1;
523 if( buffer == NULL ) {
524 xprintf( "No dst buffer\n" );
525 return -1;
528 if( buffer->buf_length > ENET_MAX_MTU_SIZE ) {
529 xprintf( "src buffer too large.\n" );
530 xprintf( "size is %d\n", buffer->buf_length );
531 return -1;
534 softc = (bcm6345_softc *) ctx->dev_softc;
535 if( softc == NULL ) {
536 xprintf( "softc has not been initialized.\n" );
537 return -1;
540 /* ====================================================================== */
542 CurrentBdPtr = softc->txNextBdPtr;
544 /* Find out if the next BD is available. */
545 if( CurrentBdPtr->status & DMA_OWN ) {
546 xprintf( "No tx BD available ?!\n" );
547 return -1;
550 dstptr = (unsigned char *)PHYS_TO_K1( CurrentBdPtr->address );
551 memcpy( dstptr, buffer->buf_ptr, buffer->buf_length );
553 /* Set status of DMA BD to be transmitted. */
554 status = DMA_SOP | DMA_EOP | DMA_APPEND_CRC | DMA_OWN;
555 if( CurrentBdPtr == softc->txLastBdPtr ) {
556 status |= DMA_WRAP;
558 CurrentBdPtr->length = buffer->buf_length;
559 CurrentBdPtr->status = status;
561 // Enable DMA for this channel
562 softc->txDma->cfg |= DMA_ENABLE;
564 // poll the dma status until done
567 txEvents = CurrentBdPtr->status;
568 } while (txEvents & DMA_OWN);
571 //Advance BD pointer to next in the chain.
572 InctxBdPtr( CurrentBdPtr, softc );
573 softc->txNextBdPtr = CurrentBdPtr;
575 return 0;
579 * perfectmatch_write: write an address to the EMAC perfect match registers
581 static void perfectmatch_write(int reg, unsigned char *pAddr, bool bValid)
583 volatile uint32 *pmDataLo;
584 volatile uint32 *pmDataHi;
586 switch (reg) {
587 case 0:
588 pmDataLo = &EMAC->pm0DataLo;
589 pmDataHi = &EMAC->pm0DataHi;
590 break;
591 case 1:
592 pmDataLo = &EMAC->pm1DataLo;
593 pmDataHi = &EMAC->pm1DataHi;
594 break;
595 case 2:
596 pmDataLo = &EMAC->pm2DataLo;
597 pmDataHi = &EMAC->pm0DataHi;
598 break;
599 case 3:
600 pmDataLo = &EMAC->pm3DataLo;
601 pmDataHi = &EMAC->pm3DataHi;
602 break;
603 default:
604 return;
606 /* Fill DataHi/Lo */
607 if (bValid == 1)
608 *pmDataLo = MAKE4((pAddr + 2));
609 *pmDataHi = MAKE2(pAddr) | (bValid << 16);
614 * bcm6345_write_mac_address: store MAC address into EMAC perfect match registers
616 static void bcm6345_write_mac_address(bcm6345_softc *softc, unsigned char *macAddr)
618 volatile uint32 data32bit;
620 data32bit = EMAC->config;
621 if (data32bit & EMAC_ENABLE) {
622 /* disable ethernet MAC while updating its registers */
623 EMAC->config &= ~EMAC_ENABLE ;
624 EMAC->config |= EMAC_DISABLE ;
625 while(EMAC->config & EMAC_DISABLE);
628 perfectmatch_write(0, macAddr, 1);
630 if (data32bit & EMAC_ENABLE) {
631 EMAC->config = data32bit;
636 static int bcm6345_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
638 int retval = 0;
640 return retval;
644 static int bcm6345_ether_close(cfe_devctx_t *ctx)
646 bcm6345_softc * softc = (bcm6345_softc *) ctx->dev_softc;
647 unsigned long sts;
649 sts = softc->rxDma->intStat;
650 softc->rxDma->intStat = sts;
651 softc->rxDma->intMask = 0;
652 softc->rxDma->cfg = 0;
654 sts = softc->txDma->intStat;
655 softc->txDma->intStat = sts;
656 softc->txDma->intMask = 0;
657 softc->txDma->cfg = 0;
659 /* return buffer allocation register internal count to 0 */
660 softc->rxDma->numAlloc = (NR_RX_BDS * -1);;
662 EMAC->config = EMAC_DISABLE;
663 KFREE( (void *)(softc->txBuffers) );
664 KFREE( (void *)(softc->rxBuffers) );
665 KFREE( (void *)(softc->txBds) );
666 KFREE( (void *)(softc->rxBds) );
667 return 0;
670 static void delay_t(int ticks)
672 int32_t t;
673 int tenTicks = ticks * 15; //~~~
675 t = _getticks() + tenTicks;
676 while (_getticks() < t) ; /* NULL LOOP */