2 * (C) Copyright 2000-2004
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * (C) Copyright 2007 Freescale Semiconductor, Inc.
6 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
8 * SPDX-License-Identifier: GPL-2.0+
21 /* Ethernet Transmit and Receive Buffers */
22 #define DBUF_LENGTH 1520
23 #define PKT_MAXBUF_SIZE 1518
24 #define PKT_MINBUF_SIZE 64
25 #define PKT_MAXBLR_SIZE 1536
26 #define LAST_PKTBUFSRX PKTBUFSRX - 1
27 #define BD_ENET_RX_W_E (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY)
28 #define BD_ENET_TX_RDY_LST (BD_ENET_TX_READY | BD_ENET_TX_LAST)
29 #define FIFO_ERRSTAT (FIFO_STAT_RXW | FIFO_STAT_UF | FIFO_STAT_OF)
31 /* RxBD bits definitions */
32 #define BD_ENET_RX_ERR (BD_ENET_RX_LG | BD_ENET_RX_NO | BD_ENET_RX_CR | \
33 BD_ENET_RX_OV | BD_ENET_RX_TR)
35 #include <asm/immap.h>
36 #include <asm/fsl_mcdmafec.h>
40 DECLARE_GLOBAL_DATA_PTR
;
42 struct fec_info_dma fec_info
[] = {
43 #ifdef CONFIG_SYS_FEC0_IOBASE
46 CONFIG_SYS_FEC0_IOBASE
, /* io base */
47 CONFIG_SYS_FEC0_PINMUX
, /* gpio pin muxing */
48 CONFIG_SYS_FEC0_MIIBASE
, /* mii base */
50 0, /* duplex and speed */
58 0, /* initialized flag */
59 (struct fec_info_dma
*)-1, /* next */
60 FEC0_RX_TASK
, /* rxTask */
61 FEC0_TX_TASK
, /* txTask */
62 FEC0_RX_PRIORITY
, /* rxPri */
63 FEC0_TX_PRIORITY
, /* txPri */
64 FEC0_RX_INIT
, /* rxInit */
65 FEC0_TX_INIT
, /* txInit */
70 #ifdef CONFIG_SYS_FEC1_IOBASE
73 CONFIG_SYS_FEC1_IOBASE
, /* io base */
74 CONFIG_SYS_FEC1_PINMUX
, /* gpio pin muxing */
75 CONFIG_SYS_FEC1_MIIBASE
, /* mii base */
77 0, /* duplex and speed */
79 0, /* phy name init */
80 #ifdef CONFIG_SYS_DMA_USE_INTSRAM
81 (cbd_t
*)DBUF_LENGTH
, /* RX BD */
89 0, /* initialized flag */
90 (struct fec_info_dma
*)-1, /* next */
91 FEC1_RX_TASK
, /* rxTask */
92 FEC1_TX_TASK
, /* txTask */
93 FEC1_RX_PRIORITY
, /* rxPri */
94 FEC1_TX_PRIORITY
, /* txPri */
95 FEC1_RX_INIT
, /* rxInit */
96 FEC1_TX_INIT
, /* txInit */
103 static int fec_send(struct eth_device
*dev
, void *packet
, int length
);
104 static int fec_recv(struct eth_device
*dev
);
105 static int fec_init(struct eth_device
*dev
, bd_t
* bd
);
106 static void fec_halt(struct eth_device
*dev
);
109 static void dbg_fec_regs(struct eth_device
*dev
)
111 struct fec_info_dma
*info
= dev
->priv
;
112 volatile fecdma_t
*fecp
= (fecdma_t
*) (info
->iobase
);
115 printf("ievent %x - %x\n", (int)&fecp
->eir
, fecp
->eir
);
116 printf("imask %x - %x\n", (int)&fecp
->eimr
, fecp
->eimr
);
117 printf("ecntrl %x - %x\n", (int)&fecp
->ecr
, fecp
->ecr
);
118 printf("mii_mframe %x - %x\n", (int)&fecp
->mmfr
, fecp
->mmfr
);
119 printf("mii_speed %x - %x\n", (int)&fecp
->mscr
, fecp
->mscr
);
120 printf("mii_ctrlstat %x - %x\n", (int)&fecp
->mibc
, fecp
->mibc
);
121 printf("r_cntrl %x - %x\n", (int)&fecp
->rcr
, fecp
->rcr
);
122 printf("r hash %x - %x\n", (int)&fecp
->rhr
, fecp
->rhr
);
123 printf("x_cntrl %x - %x\n", (int)&fecp
->tcr
, fecp
->tcr
);
124 printf("padr_l %x - %x\n", (int)&fecp
->palr
, fecp
->palr
);
125 printf("padr_u %x - %x\n", (int)&fecp
->paur
, fecp
->paur
);
126 printf("op_pause %x - %x\n", (int)&fecp
->opd
, fecp
->opd
);
127 printf("iadr_u %x - %x\n", (int)&fecp
->iaur
, fecp
->iaur
);
128 printf("iadr_l %x - %x\n", (int)&fecp
->ialr
, fecp
->ialr
);
129 printf("gadr_u %x - %x\n", (int)&fecp
->gaur
, fecp
->gaur
);
130 printf("gadr_l %x - %x\n", (int)&fecp
->galr
, fecp
->galr
);
131 printf("x_wmrk %x - %x\n", (int)&fecp
->tfwr
, fecp
->tfwr
);
132 printf("r_fdata %x - %x\n", (int)&fecp
->rfdr
, fecp
->rfdr
);
133 printf("r_fstat %x - %x\n", (int)&fecp
->rfsr
, fecp
->rfsr
);
134 printf("r_fctrl %x - %x\n", (int)&fecp
->rfcr
, fecp
->rfcr
);
135 printf("r_flrfp %x - %x\n", (int)&fecp
->rlrfp
, fecp
->rlrfp
);
136 printf("r_flwfp %x - %x\n", (int)&fecp
->rlwfp
, fecp
->rlwfp
);
137 printf("r_frfar %x - %x\n", (int)&fecp
->rfar
, fecp
->rfar
);
138 printf("r_frfrp %x - %x\n", (int)&fecp
->rfrp
, fecp
->rfrp
);
139 printf("r_frfwp %x - %x\n", (int)&fecp
->rfwp
, fecp
->rfwp
);
140 printf("t_fdata %x - %x\n", (int)&fecp
->tfdr
, fecp
->tfdr
);
141 printf("t_fstat %x - %x\n", (int)&fecp
->tfsr
, fecp
->tfsr
);
142 printf("t_fctrl %x - %x\n", (int)&fecp
->tfcr
, fecp
->tfcr
);
143 printf("t_flrfp %x - %x\n", (int)&fecp
->tlrfp
, fecp
->tlrfp
);
144 printf("t_flwfp %x - %x\n", (int)&fecp
->tlwfp
, fecp
->tlwfp
);
145 printf("t_ftfar %x - %x\n", (int)&fecp
->tfar
, fecp
->tfar
);
146 printf("t_ftfrp %x - %x\n", (int)&fecp
->tfrp
, fecp
->tfrp
);
147 printf("t_ftfwp %x - %x\n", (int)&fecp
->tfwp
, fecp
->tfwp
);
148 printf("frst %x - %x\n", (int)&fecp
->frst
, fecp
->frst
);
149 printf("ctcwr %x - %x\n", (int)&fecp
->ctcwr
, fecp
->ctcwr
);
153 static void set_fec_duplex_speed(volatile fecdma_t
* fecp
, bd_t
* bd
,
156 if ((dup_spd
>> 16) == FULL
) {
157 /* Set maximum frame length */
158 fecp
->rcr
= FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE
) | FEC_RCR_MII_MODE
|
159 FEC_RCR_PROM
| 0x100;
160 fecp
->tcr
= FEC_TCR_FDEN
;
162 /* Half duplex mode */
163 fecp
->rcr
= FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE
) |
164 FEC_RCR_MII_MODE
| FEC_RCR_DRT
;
165 fecp
->tcr
&= ~FEC_TCR_FDEN
;
168 if ((dup_spd
& 0xFFFF) == _100BASET
) {
172 bd
->bi_ethspeed
= 100;
177 bd
->bi_ethspeed
= 10;
181 static int fec_send(struct eth_device
*dev
, void *packet
, int length
)
183 struct fec_info_dma
*info
= dev
->priv
;
184 cbd_t
*pTbd
, *pUsedTbd
;
187 miiphy_read(dev
->name
, info
->phy_addr
, MII_BMSR
, &phyStatus
);
189 /* process all the consumed TBDs */
190 while (info
->cleanTbdNum
< CONFIG_SYS_TX_ETH_BUFFER
) {
191 pUsedTbd
= &info
->txbd
[info
->usedTbdIdx
];
192 if (pUsedTbd
->cbd_sc
& BD_ENET_TX_READY
) {
194 printf("Cannot clean TBD %d, in use\n",
200 /* clean this buffer descriptor */
201 if (info
->usedTbdIdx
== (CONFIG_SYS_TX_ETH_BUFFER
- 1))
202 pUsedTbd
->cbd_sc
= BD_ENET_TX_WRAP
;
204 pUsedTbd
->cbd_sc
= 0;
206 /* update some indeces for a correct handling of the TBD ring */
208 info
->usedTbdIdx
= (info
->usedTbdIdx
+ 1) % CONFIG_SYS_TX_ETH_BUFFER
;
211 /* Check for valid length of data. */
212 if ((length
> 1500) || (length
<= 0)) {
216 /* Check the number of vacant TxBDs. */
217 if (info
->cleanTbdNum
< 1) {
218 printf("No available TxBDs ...\n");
222 /* Get the first TxBD to send the mac header */
223 pTbd
= &info
->txbd
[info
->txIdx
];
224 pTbd
->cbd_datlen
= length
;
225 pTbd
->cbd_bufaddr
= (u32
) packet
;
226 pTbd
->cbd_sc
|= BD_ENET_TX_LAST
| BD_ENET_TX_TC
| BD_ENET_TX_READY
;
227 info
->txIdx
= (info
->txIdx
+ 1) % CONFIG_SYS_TX_ETH_BUFFER
;
229 /* Enable DMA transmit task */
230 MCD_continDma(info
->txTask
);
232 info
->cleanTbdNum
-= 1;
234 /* wait until frame is sent . */
235 while (pTbd
->cbd_sc
& BD_ENET_TX_READY
) {
239 return (int)(info
->txbd
[info
->txIdx
].cbd_sc
& BD_ENET_TX_STATS
);
242 static int fec_recv(struct eth_device
*dev
)
244 struct fec_info_dma
*info
= dev
->priv
;
245 volatile fecdma_t
*fecp
= (fecdma_t
*) (info
->iobase
);
247 cbd_t
*prbd
= &info
->rxbd
[info
->rxIdx
];
249 int frame_length
, len
= 0;
251 /* Check if any critical events have happened */
256 if (ievent
& (FEC_EIR_BABT
| FEC_EIR_TXERR
| FEC_EIR_RXERR
)) {
257 printf("fec_recv: error\n");
263 if (ievent
& FEC_EIR_HBERR
) {
264 /* Heartbeat error */
265 fecp
->tcr
|= FEC_TCR_GTS
;
268 if (ievent
& FEC_EIR_GRA
) {
269 /* Graceful stop complete */
270 if (fecp
->tcr
& FEC_TCR_GTS
) {
271 printf("fec_recv: tcr_gts\n");
273 fecp
->tcr
&= ~FEC_TCR_GTS
;
279 if (!(prbd
->cbd_sc
& BD_ENET_RX_EMPTY
)) {
280 if ((prbd
->cbd_sc
& BD_ENET_RX_LAST
) &&
281 !(prbd
->cbd_sc
& BD_ENET_RX_ERR
) &&
282 ((prbd
->cbd_datlen
- 4) > 14)) {
284 /* Get buffer address and size */
285 frame_length
= prbd
->cbd_datlen
- 4;
287 /* Fill the buffer and pass it to upper layers */
288 net_process_received_packet((uchar
*)prbd
->cbd_bufaddr
,
293 /* Reset buffer descriptor as empty */
294 if ((info
->rxIdx
) == (PKTBUFSRX
- 1))
295 prbd
->cbd_sc
= (BD_ENET_RX_WRAP
| BD_ENET_RX_EMPTY
);
297 prbd
->cbd_sc
= BD_ENET_RX_EMPTY
;
299 prbd
->cbd_datlen
= PKTSIZE_ALIGN
;
301 /* Now, we have an empty RxBD, restart the DMA receive task */
302 MCD_continDma(info
->rxTask
);
304 /* Increment BD count */
305 info
->rxIdx
= (info
->rxIdx
+ 1) % PKTBUFSRX
;
311 static void fec_set_hwaddr(volatile fecdma_t
* fecp
, u8
* mac
)
313 u8 currByte
; /* byte for which to compute the CRC */
314 int byte
; /* loop - counter */
315 int bit
; /* loop - counter */
316 u32 crc
= 0xffffffff; /* initial value */
318 for (byte
= 0; byte
< 6; byte
++) {
319 currByte
= mac
[byte
];
320 for (bit
= 0; bit
< 8; bit
++) {
321 if ((currByte
& 0x01) ^ (crc
& 0x01)) {
323 crc
= crc
^ 0xedb88320;
333 /* Set individual hash table register */
335 fecp
->ialr
= (1 << (crc
- 32));
339 fecp
->iaur
= (1 << crc
);
342 /* Set physical address */
343 fecp
->palr
= (mac
[0] << 24) + (mac
[1] << 16) + (mac
[2] << 8) + mac
[3];
344 fecp
->paur
= (mac
[4] << 24) + (mac
[5] << 16) + 0x8808;
346 /* Clear multicast address hash table */
351 static int fec_init(struct eth_device
*dev
, bd_t
* bd
)
353 struct fec_info_dma
*info
= dev
->priv
;
354 volatile fecdma_t
*fecp
= (fecdma_t
*) (info
->iobase
);
359 printf("fec_init: iobase 0x%08x ...\n", info
->iobase
);
362 fecpin_setclear(dev
, 1);
366 #if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \
367 defined (CONFIG_SYS_DISCOVER_PHY)
371 set_fec_duplex_speed(fecp
, bd
, info
->dup_spd
);
373 #ifndef CONFIG_SYS_DISCOVER_PHY
374 set_fec_duplex_speed(fecp
, bd
, (FECDUPLEX
<< 16) | FECSPEED
);
375 #endif /* ifndef CONFIG_SYS_DISCOVER_PHY */
376 #endif /* CONFIG_CMD_MII || CONFIG_MII */
378 /* We use strictly polling mode only */
381 /* Clear any pending interrupt */
382 fecp
->eir
= 0xffffffff;
384 /* Set station address */
385 if ((u32
) fecp
== CONFIG_SYS_FEC0_IOBASE
)
386 eth_env_get_enetaddr("ethaddr", enetaddr
);
388 eth_env_get_enetaddr("eth1addr", enetaddr
);
389 fec_set_hwaddr(fecp
, enetaddr
);
391 /* Set Opcode/Pause Duration Register */
392 fecp
->opd
= 0x00010020;
394 /* Setup Buffers and Buffer Descriptors */
398 /* Setup Receiver Buffer Descriptors (13.14.24.18)
399 * Settings: Empty, Wrap */
400 for (i
= 0; i
< PKTBUFSRX
; i
++) {
401 info
->rxbd
[i
].cbd_sc
= BD_ENET_RX_EMPTY
;
402 info
->rxbd
[i
].cbd_datlen
= PKTSIZE_ALIGN
;
403 info
->rxbd
[i
].cbd_bufaddr
= (uint
) net_rx_packets
[i
];
405 info
->rxbd
[PKTBUFSRX
- 1].cbd_sc
|= BD_ENET_RX_WRAP
;
407 /* Setup Ethernet Transmitter Buffer Descriptors (13.14.24.19)
408 * Settings: Last, Tx CRC */
409 for (i
= 0; i
< CONFIG_SYS_TX_ETH_BUFFER
; i
++) {
410 info
->txbd
[i
].cbd_sc
= 0;
411 info
->txbd
[i
].cbd_datlen
= 0;
412 info
->txbd
[i
].cbd_bufaddr
= (uint
) (&info
->txbuf
[0]);
414 info
->txbd
[CONFIG_SYS_TX_ETH_BUFFER
- 1].cbd_sc
|= BD_ENET_TX_WRAP
;
416 info
->usedTbdIdx
= 0;
417 info
->cleanTbdNum
= CONFIG_SYS_TX_ETH_BUFFER
;
419 /* Set Rx FIFO alarm and granularity value */
420 fecp
->rfcr
= 0x0c000000;
421 fecp
->rfar
= 0x0000030c;
423 /* Set Tx FIFO granularity value */
424 fecp
->tfcr
= FIFO_CTRL_FRAME
| FIFO_CTRL_GR(6) | 0x00040000;
425 fecp
->tfar
= 0x00000080;
428 fecp
->ctcwr
= 0x03000000;
430 /* Enable DMA receive task */
431 MCD_startDma(info
->rxTask
, /* Dma channel */
432 (s8
*) info
->rxbd
, /*Source Address */
433 0, /* Source increment */
434 (s8
*) (&fecp
->rfdr
), /* dest */
435 4, /* dest increment */
438 info
->rxInit
, /* initiator */
439 info
->rxPri
, /* priority */
440 (MCD_FECRX_DMA
| MCD_TT_FLAGS_DEF
), /* Flags */
441 (MCD_NO_CSUM
| MCD_NO_BYTE_SWAP
) /* Function description */
444 /* Enable DMA tx task with no ready buffer descriptors */
445 MCD_startDma(info
->txTask
, /* Dma channel */
446 (s8
*) info
->txbd
, /*Source Address */
447 0, /* Source increment */
448 (s8
*) (&fecp
->tfdr
), /* dest */
452 info
->txInit
, /* initiator */
453 info
->txPri
, /* priority */
454 (MCD_FECTX_DMA
| MCD_TT_FLAGS_DEF
), /* Flags */
455 (MCD_NO_CSUM
| MCD_NO_BYTE_SWAP
) /* Function description */
458 /* Now enable the transmit and receive processing */
459 fecp
->ecr
|= FEC_ECR_ETHER_EN
;
464 static void fec_halt(struct eth_device
*dev
)
466 struct fec_info_dma
*info
= dev
->priv
;
467 volatile fecdma_t
*fecp
= (fecdma_t
*) (info
->iobase
);
468 int counter
= 0xffff;
470 /* issue graceful stop command to the FEC transmitter if necessary */
471 fecp
->tcr
|= FEC_TCR_GTS
;
473 /* wait for graceful stop to register */
474 while ((counter
--) && (!(fecp
->eir
& FEC_EIR_GRA
))) ;
476 /* Disable DMA tasks */
477 MCD_killDma(info
->txTask
);
478 MCD_killDma(info
->rxTask
);
480 /* Disable the Ethernet Controller */
481 fecp
->ecr
&= ~FEC_ECR_ETHER_EN
;
483 /* Clear FIFO status registers */
484 fecp
->rfsr
&= FIFO_ERRSTAT
;
485 fecp
->tfsr
&= FIFO_ERRSTAT
;
487 fecp
->frst
= 0x01000000;
489 /* Issue a reset command to the FEC chip */
490 fecp
->ecr
|= FEC_ECR_RESET
;
492 /* wait at least 20 clock cycles */
496 printf("Ethernet task stopped\n");
500 int mcdmafec_initialize(bd_t
* bis
)
502 struct eth_device
*dev
;
504 #ifdef CONFIG_SYS_DMA_USE_INTSRAM
505 u32 tmp
= CONFIG_SYS_INTSRAM
+ 0x2000;
508 for (i
= 0; i
< ARRAY_SIZE(fec_info
); i
++) {
511 (struct eth_device
*)memalign(CONFIG_SYS_CACHELINE_SIZE
,
516 memset(dev
, 0, sizeof(*dev
));
518 sprintf(dev
->name
, "FEC%d", fec_info
[i
].index
);
520 dev
->priv
= &fec_info
[i
];
521 dev
->init
= fec_init
;
522 dev
->halt
= fec_halt
;
523 dev
->send
= fec_send
;
524 dev
->recv
= fec_recv
;
526 /* setup Receive and Transmit buffer descriptor */
527 #ifdef CONFIG_SYS_DMA_USE_INTSRAM
528 fec_info
[i
].rxbd
= (cbd_t
*)((u32
)fec_info
[i
].rxbd
+ tmp
);
529 tmp
= (u32
)fec_info
[i
].rxbd
;
531 (cbd_t
*)((u32
)fec_info
[i
].txbd
+ tmp
+
532 (PKTBUFSRX
* sizeof(cbd_t
)));
533 tmp
= (u32
)fec_info
[i
].txbd
;
535 (char *)((u32
)fec_info
[i
].txbuf
+ tmp
+
536 (CONFIG_SYS_TX_ETH_BUFFER
* sizeof(cbd_t
)));
537 tmp
= (u32
)fec_info
[i
].txbuf
;
540 (cbd_t
*) memalign(CONFIG_SYS_CACHELINE_SIZE
,
541 (PKTBUFSRX
* sizeof(cbd_t
)));
543 (cbd_t
*) memalign(CONFIG_SYS_CACHELINE_SIZE
,
544 (CONFIG_SYS_TX_ETH_BUFFER
* sizeof(cbd_t
)));
546 (char *)memalign(CONFIG_SYS_CACHELINE_SIZE
, DBUF_LENGTH
);
550 printf("rxbd %x txbd %x\n",
551 (int)fec_info
[i
].rxbd
, (int)fec_info
[i
].txbd
);
554 fec_info
[i
].phy_name
= (char *)memalign(CONFIG_SYS_CACHELINE_SIZE
, 32);
558 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
560 struct mii_dev
*mdiodev
= mdio_alloc();
563 strncpy(mdiodev
->name
, dev
->name
, MDIO_NAME_LEN
);
564 mdiodev
->read
= mcffec_miiphy_read
;
565 mdiodev
->write
= mcffec_miiphy_write
;
567 retval
= mdio_register(mdiodev
);
573 fec_info
[i
- 1].next
= &fec_info
[i
];
575 fec_info
[i
- 1].next
= &fec_info
[0];
578 bis
->bi_ethspeed
= 10;