4 Copyright (c) 2002 Broadcom Corporation
6 No portions of this material may be reproduced in any form without the
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"
22 #include "cfe_ioctl.h"
23 #include "cfe_device.h"
24 #include "cfe_devfuncs.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
= {
43 bcm6345_ether_inpstat
,
51 const cfe_driver_t bcm6345_enet
= {
55 &bcm6345_ether_dispatch
,
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
;
67 softc
= (bcm6345_softc
*) KMALLOC( sizeof(bcm6345_softc
), 0 );
69 xprintf( "BCM6345 : Failed to allocate softc memory.\n" );
71 memset( softc
, 0, sizeof(bcm6345_softc
) );
73 if (internal_open( softc
) == -1)
74 xprintf("Failed initializing enet hardware\n");
77 cfe_attach( drv
, softc
, NULL
, descr
);
78 cfe_attach(&flashdrv
, softc
, NULL
, NULL
);
85 static int bcm6345_ether_open(cfe_devctx_t
*ctx
)
93 * mii_write: Write a value to the MII
95 static void mii_write(uint32 uPhyAddr
, uint32 uRegAddr
, uint32 data
)
98 d
= 0x50020000 | (uPhyAddr
<< 23) | (uRegAddr
<< 18) | data
;
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
)
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
;
139 * mii_AutoConfigure: Auto-Configure this MII interface
141 static MII_CONFIG
mii_AutoConfigure(bcm6345_softc
*softc
)
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
) {
161 eConfig
= mii_GetConfig(softc
);
162 if (uData
& EPHY_AUTONEGOTIATION_COMPLETE
) {
163 eConfig
|= MII_AUTONEG
;
166 mii_write(softc
->phyAddr
, 0x1A, 0x0F00);
172 * soft_reset: Reset the MII
174 static void soft_reset(uint32 uPhyAddr
)
178 mii_write(uPhyAddr
, 0, 0x8000);
180 delay_t(MII_WRITE_DELAY
);
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
;
207 case BOARD_ID_BCM96345R00
:
208 case BOARD_ID_BCM96345R10
:
209 case BOARD_ID_BCM96345SV
:
210 case BOARD_ID_BCM96345USB
:
212 softc
->phyAddr
= MII_INTERNAL
;
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 */
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");
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
252 EMAC
->rxControl
|= EMAC_LOOPBACK
;
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
)
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
;
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
)
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 );
315 xprintf( "BCM6345 : Failed to allocate txBds memory.\n" );
316 KFREE( (void *)(softc
->rxBds
) );
321 softc
->txBds
= (DmaDesc
*)K0_TO_K1((uint32
) p
);
322 p
= KMALLOC( NR_RX_BDS
* sizeof(DmaDesc
), 0 );
324 xprintf( "BCM6345 : Failed to allocate rxBds memory.\n" );
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
) );
335 KFREE( (void *)(softc
->rxBds
) );
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
) );
347 KFREE( (void *)(softc
->rxBds
) );
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 */
380 /* init enet control registers */
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
;
393 static int bcm6345_ether_read( cfe_devctx_t
* ctx
, iocb_buffer_t
* buffer
)
396 unsigned char * dstptr
;
397 unsigned char * srcptr
;
398 volatile DmaDesc
* CurrentBdPtr
;
399 bcm6345_softc
* softc
= (bcm6345_softc
*) ctx
->dev_softc
;
403 xprintf( "No context\n" );
407 if( buffer
== NULL
) {
408 xprintf( "No dst buffer\n" );
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
);
418 if( softc
== NULL
) {
419 xprintf( "softc has not been initialized.\n" );
423 dmaFlag
= (uint16
) softc
->rxBdReadPtr
->status
;
424 if (!(dmaFlag
& DMA_EOP
))
426 xprintf("dmaFlag (return -1)[%04x]\n", dmaFlag
);
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
462 if (rxEvents
& DMA_NO_DESC
)
464 softc
->rxDma
->intStat
|= DMA_NO_DESC
; // clr interrupt
468 softc
->rxDma
->cfg
= DMA_ENABLE
|DMA_CHAINING
|DMA_WRAP_EN
;
473 static int bcm6345_ether_inpstat( cfe_devctx_t
* ctx
, iocb_inpstat_t
* inpstat
)
475 bcm6345_softc
* softc
;
476 volatile DmaDesc
* CurrentBdPtr
;
478 /* ============================= ASSERTIONS ============================= */
481 xprintf( "No context\n" );
485 if( inpstat
== NULL
) {
486 xprintf( "No inpstat buffer\n" );
490 softc
= (bcm6345_softc
*)ctx
->dev_softc
;
491 if( softc
== NULL
) {
492 xprintf( "softc has not been initialized.\n" );
496 /* ====================================================================== */
499 CurrentBdPtr
= softc
->rxBdReadPtr
;
501 // inp_status == 1 -> data available
502 inpstat
->inp_status
= (CurrentBdPtr
->status
& DMA_OWN
) ? 0 : 1;
508 static int bcm6345_ether_write(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
511 unsigned char * dstptr
;
512 bcm6345_softc
* softc
;
513 volatile DmaDesc
* CurrentBdPtr
;
514 volatile uint32 txEvents
= 0;
516 /* ============================= ASSERTIONS ============================= */
519 xprintf( "No context\n" );
523 if( buffer
== NULL
) {
524 xprintf( "No dst buffer\n" );
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
);
534 softc
= (bcm6345_softc
*) ctx
->dev_softc
;
535 if( softc
== NULL
) {
536 xprintf( "softc has not been initialized.\n" );
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" );
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
) {
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
;
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
;
588 pmDataLo
= &EMAC
->pm0DataLo
;
589 pmDataHi
= &EMAC
->pm0DataHi
;
592 pmDataLo
= &EMAC
->pm1DataLo
;
593 pmDataHi
= &EMAC
->pm1DataHi
;
596 pmDataLo
= &EMAC
->pm2DataLo
;
597 pmDataHi
= &EMAC
->pm0DataHi
;
600 pmDataLo
= &EMAC
->pm3DataLo
;
601 pmDataHi
= &EMAC
->pm3DataHi
;
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
)
644 static int bcm6345_ether_close(cfe_devctx_t
*ctx
)
646 bcm6345_softc
* softc
= (bcm6345_softc
*) ctx
->dev_softc
;
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
) );
670 static void delay_t(int ticks
)
673 int tenTicks
= ticks
* 15; //~~~
675 t
= _getticks() + tenTicks
;
676 while (_getticks() < t
) ; /* NULL LOOP */