]> git.ipfire.org Git - people/ms/u-boot.git/blame - cpu/mpc5xxx/fec.c
Big white-space cleanup.
[people/ms/u-boot.git] / cpu / mpc5xxx / fec.c
CommitLineData
945af8d7 1/*
5e5f9ed2 2 * (C) Copyright 2003-2005
945af8d7
WD
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * This file is based on mpc4200fec.c,
6 * (C) Copyright Motorola, Inc., 2000
7 */
8
9#include <common.h>
10#include <mpc5xxx.h>
11#include <malloc.h>
12#include <net.h>
13#include <miiphy.h>
14#include "sdma.h"
15#include "fec.h"
16
d87080b7
WD
17DECLARE_GLOBAL_DATA_PTR;
18
77846748 19/* #define DEBUG 0x28 */
945af8d7 20
4431283c 21#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
cbd8a35c 22 defined(CONFIG_MPC5xxx_FEC)
945af8d7 23
4431283c 24#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
63ff004c
MB
25#error "CONFIG_MII has to be defined!"
26#endif
27
945af8d7 28#if (DEBUG & 0x60)
63ff004c
MB
29static void tfifo_print(char *devname, mpc5xxx_fec_priv *fec);
30static void rfifo_print(char *devname, mpc5xxx_fec_priv *fec);
945af8d7
WD
31#endif /* DEBUG */
32
33#if (DEBUG & 0x40)
34static uint32 local_crc32(char *string, unsigned int crc_value, int len);
35#endif
36
77846748
WD
37typedef struct {
38 uint8 data[1500]; /* actual data */
39 int length; /* actual length */
40 int used; /* buffer in use or not */
41 uint8 head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */
42} NBUF;
43
63ff004c
MB
44int fec5xxx_miiphy_read(char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal);
45int fec5xxx_miiphy_write(char *devname, uint8 phyAddr, uint8 regAddr, uint16 data);
46
d4ca31c4
WD
47/********************************************************************/
48#if (DEBUG & 0x2)
63ff004c 49static void mpc5xxx_fec_phydump (char *devname)
d4ca31c4
WD
50{
51 uint16 phyStatus, i;
52 uint8 phyAddr = CONFIG_PHY_ADDR;
53 uint8 reg_mask[] = {
54#if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */
55 /* regs to print: 0...7, 16...19, 21, 23, 24 */
56 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
57 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0,
58#else
59 /* regs to print: 0...8, 16...20 */
60 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
61 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62#endif
63 };
64
65 for (i = 0; i < 32; i++) {
66 if (reg_mask[i]) {
63ff004c 67 miiphy_read(devname, phyAddr, i, &phyStatus);
d4ca31c4
WD
68 printf("Mii reg %d: 0x%04x\n", i, phyStatus);
69 }
70 }
71}
72#endif
73
945af8d7
WD
74/********************************************************************/
75static int mpc5xxx_fec_rbd_init(mpc5xxx_fec_priv *fec)
76{
77 int ix;
78 char *data;
77846748 79 static int once = 0;
945af8d7 80
945af8d7 81 for (ix = 0; ix < FEC_RBD_NUM; ix++) {
77846748
WD
82 if (!once) {
83 data = (char *)malloc(FEC_MAX_PKT_SIZE);
84 if (data == NULL) {
85 printf ("RBD INIT FAILED\n");
86 return -1;
87 }
88 fec->rbdBase[ix].dataPointer = (uint32)data;
945af8d7
WD
89 }
90 fec->rbdBase[ix].status = FEC_RBD_EMPTY;
91 fec->rbdBase[ix].dataLength = 0;
945af8d7 92 }
77846748 93 once ++;
945af8d7
WD
94
95 /*
96 * have the last RBD to close the ring
97 */
98 fec->rbdBase[ix - 1].status |= FEC_RBD_WRAP;
99 fec->rbdIndex = 0;
100
101 return 0;
102}
103
104/********************************************************************/
105static void mpc5xxx_fec_tbd_init(mpc5xxx_fec_priv *fec)
106{
107 int ix;
108
109 for (ix = 0; ix < FEC_TBD_NUM; ix++) {
110 fec->tbdBase[ix].status = 0;
111 }
112
113 /*
114 * Have the last TBD to close the ring
115 */
116 fec->tbdBase[ix - 1].status |= FEC_TBD_WRAP;
117
118 /*
119 * Initialize some indices
120 */
121 fec->tbdIndex = 0;
122 fec->usedTbdIndex = 0;
123 fec->cleanTbdNum = FEC_TBD_NUM;
124}
125
126/********************************************************************/
151ab83a 127static void mpc5xxx_fec_rbd_clean(mpc5xxx_fec_priv *fec, volatile FEC_RBD * pRbd)
945af8d7
WD
128{
129 /*
130 * Reset buffer descriptor as empty
131 */
132 if ((fec->rbdIndex) == (FEC_RBD_NUM - 1))
133 pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY);
134 else
135 pRbd->status = FEC_RBD_EMPTY;
136
137 pRbd->dataLength = 0;
138
139 /*
140 * Now, we have an empty RxBD, restart the SmartDMA receive task
141 */
142 SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
143
144 /*
145 * Increment BD count
146 */
147 fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM;
148}
149
150/********************************************************************/
151static void mpc5xxx_fec_tbd_scrub(mpc5xxx_fec_priv *fec)
152{
151ab83a 153 volatile FEC_TBD *pUsedTbd;
945af8d7
WD
154
155#if (DEBUG & 0x1)
156 printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
157 fec->cleanTbdNum, fec->usedTbdIndex);
158#endif
159
160 /*
161 * process all the consumed TBDs
162 */
163 while (fec->cleanTbdNum < FEC_TBD_NUM) {
164 pUsedTbd = &fec->tbdBase[fec->usedTbdIndex];
165 if (pUsedTbd->status & FEC_TBD_READY) {
166#if (DEBUG & 0x20)
167 printf("Cannot clean TBD %d, in use\n", fec->cleanTbdNum);
168#endif
169 return;
170 }
171
172 /*
173 * clean this buffer descriptor
174 */
175 if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
176 pUsedTbd->status = FEC_TBD_WRAP;
177 else
178 pUsedTbd->status = 0;
179
180 /*
181 * update some indeces for a correct handling of the TBD ring
182 */
183 fec->cleanTbdNum++;
184 fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
185 }
186}
187
188/********************************************************************/
189static void mpc5xxx_fec_set_hwaddr(mpc5xxx_fec_priv *fec, char *mac)
190{
191 uint8 currByte; /* byte for which to compute the CRC */
192 int byte; /* loop - counter */
193 int bit; /* loop - counter */
194 uint32 crc = 0xffffffff; /* initial value */
195
196 /*
197 * The algorithm used is the following:
198 * we loop on each of the six bytes of the provided address,
199 * and we compute the CRC by left-shifting the previous
200 * value by one position, so that each bit in the current
201 * byte of the address may contribute the calculation. If
202 * the latter and the MSB in the CRC are different, then
203 * the CRC value so computed is also ex-ored with the
204 * "polynomium generator". The current byte of the address
205 * is also shifted right by one bit at each iteration.
206 * This is because the CRC generatore in hardware is implemented
207 * as a shift-register with as many ex-ores as the radixes
208 * in the polynomium. This suggests that we represent the
209 * polynomiumm itself as a 32-bit constant.
210 */
211 for (byte = 0; byte < 6; byte++) {
212 currByte = mac[byte];
213 for (bit = 0; bit < 8; bit++) {
214 if ((currByte & 0x01) ^ (crc & 0x01)) {
215 crc >>= 1;
216 crc = crc ^ 0xedb88320;
217 } else {
218 crc >>= 1;
219 }
220 currByte >>= 1;
221 }
222 }
223
224 crc = crc >> 26;
225
226 /*
227 * Set individual hash table register
228 */
229 if (crc >= 32) {
230 fec->eth->iaddr1 = (1 << (crc - 32));
231 fec->eth->iaddr2 = 0;
232 } else {
233 fec->eth->iaddr1 = 0;
234 fec->eth->iaddr2 = (1 << crc);
235 }
236
237 /*
238 * Set physical address
239 */
240 fec->eth->paddr1 = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
241 fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
242}
243
244/********************************************************************/
245static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis)
246{
247 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
248 struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA;
945af8d7
WD
249
250#if (DEBUG & 0x1)
251 printf ("mpc5xxx_fec_init... Begin\n");
252#endif
253
254 /*
255 * Initialize RxBD/TxBD rings
256 */
257 mpc5xxx_fec_rbd_init(fec);
258 mpc5xxx_fec_tbd_init(fec);
259
945af8d7
WD
260 /*
261 * Clear FEC-Lite interrupt event register(IEVENT)
262 */
263 fec->eth->ievent = 0xffffffff;
264
265 /*
266 * Set interrupt mask register
267 */
268 fec->eth->imask = 0x00000000;
269
270 /*
271 * Set FEC-Lite receive control register(R_CNTRL):
272 */
273 if (fec->xcv_type == SEVENWIRE) {
274 /*
275 * Frame length=1518; 7-wire mode
276 */
277 fec->eth->r_cntrl = 0x05ee0020; /*0x05ee0000;FIXME */
278 } else {
279 /*
280 * Frame length=1518; MII mode;
281 */
282 fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */
283 }
284
7e780369
WD
285 fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */
286 if (fec->xcv_type != SEVENWIRE) {
945af8d7 287 /*
7152b1d0 288 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
945af8d7
WD
289 * and do not drop the Preamble.
290 */
6341d9d7 291 fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */
945af8d7
WD
292 }
293
294 /*
295 * Set Opcode/Pause Duration Register
296 */
6341d9d7 297 fec->eth->op_pause = 0x00010020; /*FIXME 0xffff0020; */
945af8d7
WD
298
299 /*
300 * Set Rx FIFO alarm and granularity value
301 */
c44ffb9e
WD
302 fec->eth->rfifo_cntrl = 0x0c000000
303 | (fec->eth->rfifo_cntrl & ~0x0f000000);
945af8d7
WD
304 fec->eth->rfifo_alarm = 0x0000030c;
305#if (DEBUG & 0x22)
306 if (fec->eth->rfifo_status & 0x00700000 ) {
307 printf("mpc5xxx_fec_init() RFIFO error\n");
308 }
309#endif
310
311 /*
312 * Set Tx FIFO granularity value
313 */
c44ffb9e
WD
314 fec->eth->tfifo_cntrl = 0x0c000000
315 | (fec->eth->tfifo_cntrl & ~0x0f000000);
945af8d7
WD
316#if (DEBUG & 0x2)
317 printf("tfifo_status: 0x%08x\n", fec->eth->tfifo_status);
318 printf("tfifo_alarm: 0x%08x\n", fec->eth->tfifo_alarm);
319#endif
320
321 /*
322 * Set transmit fifo watermark register(X_WMRK), default = 64
323 */
324 fec->eth->tfifo_alarm = 0x00000080;
325 fec->eth->x_wmrk = 0x2;
326
327 /*
328 * Set individual address filter for unicast address
329 * and set physical address registers.
330 */
77ddac94 331 mpc5xxx_fec_set_hwaddr(fec, (char *)dev->enetaddr);
945af8d7
WD
332
333 /*
334 * Set multicast address filter
335 */
336 fec->eth->gaddr1 = 0x00000000;
337 fec->eth->gaddr2 = 0x00000000;
338
339 /*
340 * Turn ON cheater FSM: ????
341 */
342 fec->eth->xmit_fsm = 0x03000000;
343
344#if defined(CONFIG_MPC5200)
345 /*
346 * Turn off COMM bus prefetch in the MGT5200 BestComm. It doesn't
347 * work w/ the current receive task.
348 */
349 sdma->PtdCntrl |= 0x00000001;
350#endif
351
352 /*
353 * Set priority of different initiators
354 */
355 sdma->IPR0 = 7; /* always */
356 sdma->IPR3 = 6; /* Eth RX */
357 sdma->IPR4 = 5; /* Eth Tx */
358
359 /*
360 * Clear SmartDMA task interrupt pending bits
361 */
362 SDMA_CLEAR_IEVENT(FEC_RECV_TASK_NO);
363
945af8d7
WD
364 /*
365 * Initialize SmartDMA parameters stored in SRAM
366 */
151ab83a
WD
367 *(volatile int *)FEC_TBD_BASE = (int)fec->tbdBase;
368 *(volatile int *)FEC_RBD_BASE = (int)fec->rbdBase;
369 *(volatile int *)FEC_TBD_NEXT = (int)fec->tbdBase;
370 *(volatile int *)FEC_RBD_NEXT = (int)fec->rbdBase;
945af8d7 371
6c1362cf
WD
372 /*
373 * Enable FEC-Lite controller
374 */
375 fec->eth->ecntrl |= 0x00000006;
376
377#if (DEBUG & 0x2)
378 if (fec->xcv_type != SEVENWIRE)
6dedf3d4 379 mpc5xxx_fec_phydump (dev->name);
6c1362cf
WD
380#endif
381
382 /*
383 * Enable SmartDMA receive task
384 */
385 SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
386
387#if (DEBUG & 0x1)
388 printf("mpc5xxx_fec_init... Done \n");
389#endif
390
391 return 1;
392}
393
394/********************************************************************/
395static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis)
396{
6c1362cf
WD
397 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
398 const uint8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */
399
400#if (DEBUG & 0x1)
401 printf ("mpc5xxx_fec_init_phy... Begin\n");
402#endif
403
404 /*
405 * Initialize GPIO pins
406 */
407 if (fec->xcv_type == SEVENWIRE) {
408 /* 10MBit with 7-wire operation */
6c7a1408
WD
409#if defined(CONFIG_TOTAL5200)
410 /* 7-wire and USB2 on Ethernet */
411 *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00030000;
412#else /* !CONFIG_TOTAL5200 */
413 /* 7-wire only */
6c1362cf 414 *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00020000;
6c7a1408 415#endif /* CONFIG_TOTAL5200 */
6c1362cf
WD
416 } else {
417 /* 100MBit with MD operation */
418 *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00050000;
419 }
420
421 /*
422 * Clear FEC-Lite interrupt event register(IEVENT)
423 */
424 fec->eth->ievent = 0xffffffff;
425
426 /*
427 * Set interrupt mask register
428 */
429 fec->eth->imask = 0x00000000;
430
008861a2
BS
431/*
432 * In original Promess-provided code PHY initialization is disabled with the
433 * following comment: "Phy initialization is DISABLED for now. There was a
434 * problem with running 100 Mbps on PRO board". Thus we temporarily disable
435 * PHY initialization for the Motion-PRO board, until a proper fix is found.
436 */
437
6c1362cf
WD
438 if (fec->xcv_type != SEVENWIRE) {
439 /*
440 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
441 * and do not drop the Preamble.
442 */
443 fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */
444 }
445
945af8d7
WD
446 if (fec->xcv_type != SEVENWIRE) {
447 /*
448 * Initialize PHY(LXT971A):
449 *
450 * Generally, on power up, the LXT971A reads its configuration
451 * pins to check for forced operation, If not cofigured for
452 * forced operation, it uses auto-negotiation/parallel detection
453 * to automatically determine line operating conditions.
454 * If the PHY device on the other side of the link supports
455 * auto-negotiation, the LXT971A auto-negotiates with it
456 * using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
457 * support auto-negotiation, the LXT971A automatically detects
458 * the presence of either link pulses(10Mbps PHY) or Idle
459 * symbols(100Mbps) and sets its operating conditions accordingly.
460 *
461 * When auto-negotiation is controlled by software, the following
462 * steps are recommended.
463 *
464 * Note:
465 * The physical address is dependent on hardware configuration.
466 *
467 */
468 int timeout = 1;
469 uint16 phyStatus;
470
471 /*
472 * Reset PHY, then delay 300ns
473 */
63ff004c 474 miiphy_write(dev->name, phyAddr, 0x0, 0x8000);
945af8d7
WD
475 udelay(1000);
476
37403005
HS
477#if defined(CONFIG_UC101)
478 /* Set the LED configuration Register for the UC101 Board */
479 miiphy_write(dev->name, phyAddr, 0x14, 0x4122);
480#endif
945af8d7
WD
481 if (fec->xcv_type == MII10) {
482 /*
483 * Force 10Base-T, FDX operation
484 */
a57106fc 485#if (DEBUG & 0x2)
945af8d7 486 printf("Forcing 10 Mbps ethernet link... ");
a57106fc 487#endif
63ff004c 488 miiphy_read(dev->name, phyAddr, 0x1, &phyStatus);
945af8d7 489 /*
63ff004c 490 miiphy_write(dev->name, fec, phyAddr, 0x0, 0x0100);
945af8d7 491 */
63ff004c 492 miiphy_write(dev->name, phyAddr, 0x0, 0x0180);
945af8d7
WD
493
494 timeout = 20;
495 do { /* wait for link status to go down */
496 udelay(10000);
497 if ((timeout--) == 0) {
498#if (DEBUG & 0x2)
499 printf("hmmm, should not have waited...");
500#endif
501 break;
502 }
63ff004c 503 miiphy_read(dev->name, phyAddr, 0x1, &phyStatus);
945af8d7
WD
504#if (DEBUG & 0x2)
505 printf("=");
506#endif
507 } while ((phyStatus & 0x0004)); /* !link up */
508
509 timeout = 1000;
510 do { /* wait for link status to come back up */
511 udelay(10000);
512 if ((timeout--) == 0) {
513 printf("failed. Link is down.\n");
514 break;
515 }
63ff004c 516 miiphy_read(dev->name, phyAddr, 0x1, &phyStatus);
945af8d7
WD
517#if (DEBUG & 0x2)
518 printf("+");
519#endif
520 } while (!(phyStatus & 0x0004)); /* !link up */
521
ab209d51 522#if (DEBUG & 0x2)
945af8d7 523 printf ("done.\n");
ab209d51 524#endif
945af8d7
WD
525 } else { /* MII100 */
526 /*
527 * Set the auto-negotiation advertisement register bits
528 */
63ff004c 529 miiphy_write(dev->name, phyAddr, 0x4, 0x01e1);
945af8d7
WD
530
531 /*
532 * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
533 */
63ff004c 534 miiphy_write(dev->name, phyAddr, 0x0, 0x1200);
945af8d7
WD
535
536 /*
537 * Wait for AN completion
538 */
539 timeout = 5000;
540 do {
541 udelay(1000);
542
543 if ((timeout--) == 0) {
544#if (DEBUG & 0x2)
545 printf("PHY auto neg 0 failed...\n");
546#endif
547 return -1;
548 }
549
63ff004c 550 if (miiphy_read(dev->name, phyAddr, 0x1, &phyStatus) != 0) {
945af8d7
WD
551#if (DEBUG & 0x2)
552 printf("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
553#endif
554 return -1;
555 }
7e780369 556 } while (!(phyStatus & 0x0004));
945af8d7
WD
557
558#if (DEBUG & 0x2)
559 printf("PHY auto neg complete! \n");
560#endif
561 }
562
563 }
564
945af8d7 565#if (DEBUG & 0x2)
d4ca31c4 566 if (fec->xcv_type != SEVENWIRE)
63ff004c 567 mpc5xxx_fec_phydump (dev->name);
945af8d7 568#endif
d4ca31c4 569
945af8d7
WD
570
571#if (DEBUG & 0x1)
6c1362cf 572 printf("mpc5xxx_fec_init_phy... Done \n");
945af8d7
WD
573#endif
574
013dc8d9 575 return 1;
945af8d7
WD
576}
577
578/********************************************************************/
579static void mpc5xxx_fec_halt(struct eth_device *dev)
580{
77846748 581#if defined(CONFIG_MPC5200)
945af8d7 582 struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA;
77846748
WD
583#endif
584 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
945af8d7
WD
585 int counter = 0xffff;
586
587#if (DEBUG & 0x2)
d4ca31c4 588 if (fec->xcv_type != SEVENWIRE)
6dedf3d4 589 mpc5xxx_fec_phydump (dev->name);
945af8d7
WD
590#endif
591
945af8d7
WD
592 /*
593 * mask FEC chip interrupts
594 */
595 fec->eth->imask = 0;
596
597 /*
598 * issue graceful stop command to the FEC transmitter if necessary
599 */
600 fec->eth->x_cntrl |= 0x00000001;
601
602 /*
603 * wait for graceful stop to register
604 */
605 while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ;
606
945af8d7
WD
607 /*
608 * Disable SmartDMA tasks
609 */
610 SDMA_TASK_DISABLE (FEC_XMIT_TASK_NO);
611 SDMA_TASK_DISABLE (FEC_RECV_TASK_NO);
612
613#if defined(CONFIG_MPC5200)
614 /*
615 * Turn on COMM bus prefetch in the MGT5200 BestComm after we're
616 * done. It doesn't work w/ the current receive task.
617 */
618 sdma->PtdCntrl &= ~0x00000001;
619#endif
620
621 /*
622 * Disable the Ethernet Controller
623 */
624 fec->eth->ecntrl &= 0xfffffffd;
625
626 /*
627 * Clear FIFO status registers
628 */
629 fec->eth->rfifo_status &= 0x00700000;
630 fec->eth->tfifo_status &= 0x00700000;
631
632 fec->eth->reset_cntrl = 0x01000000;
633
634 /*
635 * Issue a reset command to the FEC chip
636 */
637 fec->eth->ecntrl |= 0x1;
638
639 /*
640 * wait at least 16 clock cycles
641 */
642 udelay(10);
643
644#if (DEBUG & 0x3)
645 printf("Ethernet task stopped\n");
646#endif
647}
648
649#if (DEBUG & 0x60)
650/********************************************************************/
651
63ff004c 652static void tfifo_print(char *devname, mpc5xxx_fec_priv *fec)
945af8d7 653{
d4ca31c4 654 uint16 phyAddr = CONFIG_PHY_ADDR;
945af8d7
WD
655 uint16 phyStatus;
656
657 if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr)
658 || (fec->eth->tfifo_rdptr != fec->eth->tfifo_wrptr)) {
659
63ff004c 660 miiphy_read(devname, phyAddr, 0x1, &phyStatus);
945af8d7
WD
661 printf("\nphyStatus: 0x%04x\n", phyStatus);
662 printf("ecntrl: 0x%08x\n", fec->eth->ecntrl);
663 printf("ievent: 0x%08x\n", fec->eth->ievent);
664 printf("x_status: 0x%08x\n", fec->eth->x_status);
665 printf("tfifo: status 0x%08x\n", fec->eth->tfifo_status);
666
667 printf(" control 0x%08x\n", fec->eth->tfifo_cntrl);
668 printf(" lrfp 0x%08x\n", fec->eth->tfifo_lrf_ptr);
669 printf(" lwfp 0x%08x\n", fec->eth->tfifo_lwf_ptr);
670 printf(" alarm 0x%08x\n", fec->eth->tfifo_alarm);
671 printf(" readptr 0x%08x\n", fec->eth->tfifo_rdptr);
672 printf(" writptr 0x%08x\n", fec->eth->tfifo_wrptr);
673 }
674}
675
63ff004c 676static void rfifo_print(char *devname, mpc5xxx_fec_priv *fec)
945af8d7 677{
d4ca31c4 678 uint16 phyAddr = CONFIG_PHY_ADDR;
945af8d7
WD
679 uint16 phyStatus;
680
681 if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr)
682 || (fec->eth->rfifo_rdptr != fec->eth->rfifo_wrptr)) {
683
63ff004c 684 miiphy_read(devname, phyAddr, 0x1, &phyStatus);
945af8d7
WD
685 printf("\nphyStatus: 0x%04x\n", phyStatus);
686 printf("ecntrl: 0x%08x\n", fec->eth->ecntrl);
687 printf("ievent: 0x%08x\n", fec->eth->ievent);
688 printf("x_status: 0x%08x\n", fec->eth->x_status);
689 printf("rfifo: status 0x%08x\n", fec->eth->rfifo_status);
690
691 printf(" control 0x%08x\n", fec->eth->rfifo_cntrl);
692 printf(" lrfp 0x%08x\n", fec->eth->rfifo_lrf_ptr);
693 printf(" lwfp 0x%08x\n", fec->eth->rfifo_lwf_ptr);
694 printf(" alarm 0x%08x\n", fec->eth->rfifo_alarm);
695 printf(" readptr 0x%08x\n", fec->eth->rfifo_rdptr);
696 printf(" writptr 0x%08x\n", fec->eth->rfifo_wrptr);
697 }
698}
699#endif /* DEBUG */
700
701/********************************************************************/
702
703static int mpc5xxx_fec_send(struct eth_device *dev, volatile void *eth_data,
704 int data_length)
705{
706 /*
707 * This routine transmits one frame. This routine only accepts
708 * 6-byte Ethernet addresses.
709 */
710 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
151ab83a 711 volatile FEC_TBD *pTbd;
945af8d7
WD
712
713#if (DEBUG & 0x20)
714 printf("tbd status: 0x%04x\n", fec->tbdBase[0].status);
63ff004c 715 tfifo_print(dev->name, fec);
945af8d7
WD
716#endif
717
718 /*
719 * Clear Tx BD ring at first
720 */
721 mpc5xxx_fec_tbd_scrub(fec);
722
723 /*
724 * Check for valid length of data.
725 */
726 if ((data_length > 1500) || (data_length <= 0)) {
727 return -1;
728 }
729
730 /*
731 * Check the number of vacant TxBDs.
732 */
733 if (fec->cleanTbdNum < 1) {
734#if (DEBUG & 0x20)
735 printf("No available TxBDs ...\n");
736#endif
737 return -1;
738 }
739
740 /*
741 * Get the first TxBD to send the mac header
742 */
743 pTbd = &fec->tbdBase[fec->tbdIndex];
744 pTbd->dataLength = data_length;
745 pTbd->dataPointer = (uint32)eth_data;
77846748 746 pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
945af8d7
WD
747 fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
748
749#if (DEBUG & 0x100)
750 printf("SDMA_TASK_ENABLE, fec->tbdIndex = %d \n", fec->tbdIndex);
751#endif
752
753 /*
754 * Kick the MII i/f
755 */
756 if (fec->xcv_type != SEVENWIRE) {
757 uint16 phyStatus;
63ff004c 758 miiphy_read(dev->name, 0, 0x1, &phyStatus);
945af8d7
WD
759 }
760
761 /*
762 * Enable SmartDMA transmit task
763 */
764
765#if (DEBUG & 0x20)
63ff004c 766 tfifo_print(dev->name, fec);
945af8d7
WD
767#endif
768 SDMA_TASK_ENABLE (FEC_XMIT_TASK_NO);
769#if (DEBUG & 0x20)
63ff004c 770 tfifo_print(dev->name, fec);
945af8d7
WD
771#endif
772#if (DEBUG & 0x8)
773 printf( "+" );
774#endif
775
776 fec->cleanTbdNum -= 1;
777
778#if (DEBUG & 0x129) && (DEBUG & 0x80000000)
779 printf ("smartDMA ethernet Tx task enabled\n");
780#endif
781 /*
782 * wait until frame is sent .
783 */
784 while (pTbd->status & FEC_TBD_READY) {
785 udelay(10);
786#if (DEBUG & 0x8)
787 printf ("TDB status = %04x\n", pTbd->status);
788#endif
789 }
790
791 return 0;
792}
793
794
795/********************************************************************/
796static int mpc5xxx_fec_recv(struct eth_device *dev)
797{
798 /*
799 * This command pulls one frame from the card
800 */
801 mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv;
151ab83a 802 volatile FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
945af8d7 803 unsigned long ievent;
77846748
WD
804 int frame_length, len = 0;
805 NBUF *frame;
77ddac94 806 uchar buff[FEC_MAX_PKT_SIZE];
945af8d7
WD
807
808#if (DEBUG & 0x1)
809 printf ("mpc5xxx_fec_recv %d Start...\n", fec->rbdIndex);
810#endif
811#if (DEBUG & 0x8)
812 printf( "-" );
813#endif
814
815 /*
816 * Check if any critical events have happened
817 */
818 ievent = fec->eth->ievent;
819 fec->eth->ievent = ievent;
820 if (ievent & 0x20060000) {
821 /* BABT, Rx/Tx FIFO errors */
822 mpc5xxx_fec_halt(dev);
823 mpc5xxx_fec_init(dev, NULL);
824 return 0;
825 }
826 if (ievent & 0x80000000) {
827 /* Heartbeat error */
828 fec->eth->x_cntrl |= 0x00000001;
829 }
830 if (ievent & 0x10000000) {
831 /* Graceful stop complete */
832 if (fec->eth->x_cntrl & 0x00000001) {
833 mpc5xxx_fec_halt(dev);
834 fec->eth->x_cntrl &= ~0x00000001;
835 mpc5xxx_fec_init(dev, NULL);
836 }
837 }
838
77846748
WD
839 if (!(pRbd->status & FEC_RBD_EMPTY)) {
840 if ((pRbd->status & FEC_RBD_LAST) && !(pRbd->status & FEC_RBD_ERR) &&
841 ((pRbd->dataLength - 4) > 14)) {
945af8d7 842
77846748
WD
843 /*
844 * Get buffer address and size
845 */
846 frame = (NBUF *)pRbd->dataPointer;
847 frame_length = pRbd->dataLength - 4;
848
849#if (DEBUG & 0x20)
850 {
851 int i;
852 printf("recv data hdr:");
853 for (i = 0; i < 14; i++)
854 printf("%x ", *(frame->head + i));
855 printf("\n");
856 }
945af8d7 857#endif
77846748
WD
858 /*
859 * Fill the buffer and pass it to upper layers
860 */
861 memcpy(buff, frame->head, 14);
862 memcpy(buff + 14, frame->data, frame_length);
863 NetReceive(buff, frame_length);
864 len = frame_length;
865 }
866 /*
867 * Reset buffer descriptor as empty
868 */
869 mpc5xxx_fec_rbd_clean(fec, pRbd);
945af8d7 870 }
77846748
WD
871 SDMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
872 return len;
945af8d7
WD
873}
874
875
876/********************************************************************/
877int mpc5xxx_fec_initialize(bd_t * bis)
878{
879 mpc5xxx_fec_priv *fec;
880 struct eth_device *dev;
12f34241
WD
881 char *tmp, *end;
882 char env_enetaddr[6];
883 int i;
945af8d7
WD
884
885 fec = (mpc5xxx_fec_priv *)malloc(sizeof(*fec));
886 dev = (struct eth_device *)malloc(sizeof(*dev));
53677ef1 887 memset(dev, 0, sizeof *dev);
945af8d7
WD
888
889 fec->eth = (ethernet_regs *)MPC5XXX_FEC;
890 fec->tbdBase = (FEC_TBD *)FEC_BD_BASE;
891 fec->rbdBase = (FEC_RBD *)(FEC_BD_BASE + FEC_TBD_NUM * sizeof(FEC_TBD));
fa1df308 892#if defined(CONFIG_CANMB) || \
86b116b1 893 defined(CONFIG_CM5200) || \
fa1df308
BS
894 defined(CONFIG_HMI1001) || \
895 defined(CONFIG_ICECUBE) || \
896 defined(CONFIG_INKA4X0) || \
897 defined(CONFIG_JUPITER) || \
898 defined(CONFIG_MCC200) || \
899 defined(CONFIG_MOTIONPRO) || \
900 defined(CONFIG_O2DNT) || \
901 defined(CONFIG_PM520) || \
902 defined(CONFIG_TOP5200) || \
903 defined(CONFIG_TQM5200) || \
904 defined(CONFIG_UC101) || \
6341d9d7
HS
905 defined(CONFIG_V38B) || \
906 defined(CONFIG_MUNICES)
efa329cb 907# ifndef CONFIG_FEC_10MBIT
945af8d7 908 fec->xcv_type = MII100;
efa329cb 909# else
a57106fc 910 fec->xcv_type = MII10;
efa329cb 911# endif
6c7a1408
WD
912#elif defined(CONFIG_TOTAL5200)
913 fec->xcv_type = SEVENWIRE;
a57106fc
WD
914#else
915#error fec->xcv_type not initialized.
945af8d7
WD
916#endif
917
918 dev->priv = (void *)fec;
919 dev->iobase = MPC5XXX_FEC;
920 dev->init = mpc5xxx_fec_init;
921 dev->halt = mpc5xxx_fec_halt;
922 dev->send = mpc5xxx_fec_send;
923 dev->recv = mpc5xxx_fec_recv;
924
77846748 925 sprintf(dev->name, "FEC ETHERNET");
945af8d7
WD
926 eth_register(dev);
927
4431283c 928#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
63ff004c
MB
929 miiphy_register (dev->name,
930 fec5xxx_miiphy_read, fec5xxx_miiphy_write);
931#endif
932
12f34241
WD
933 /*
934 * Try to set the mac address now. The fec mac address is
42d1f039 935 * a garbage after reset. When not using fec for booting
12f34241
WD
936 * the Linux fec driver will try to work with this garbage.
937 */
938 tmp = getenv("ethaddr");
939 if (tmp) {
940 for (i=0; i<6; i++) {
941 env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
942 if (tmp)
943 tmp = (*end) ? end+1 : end;
944 }
945 mpc5xxx_fec_set_hwaddr(fec, env_enetaddr);
946 }
947
6c1362cf 948 mpc5xxx_fec_init_phy(dev, bis);
63ff004c 949
945af8d7
WD
950 return 1;
951}
952
953/* MII-interface related functions */
954/********************************************************************/
63ff004c 955int fec5xxx_miiphy_read(char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal)
945af8d7
WD
956{
957 ethernet_regs *eth = (ethernet_regs *)MPC5XXX_FEC;
958 uint32 reg; /* convenient holder for the PHY register */
959 uint32 phy; /* convenient holder for the PHY */
960 int timeout = 0xffff;
961
962 /*
963 * reading from any PHY's register is done by properly
964 * programming the FEC's MII data register.
965 */
966 reg = regAddr << FEC_MII_DATA_RA_SHIFT;
967 phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
968
969 eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy | reg);
970
971 /*
972 * wait for the related interrupt
973 */
974 while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
975
976 if (timeout == 0) {
977#if (DEBUG & 0x2)
978 printf ("Read MDIO failed...\n");
979#endif
980 return -1;
981 }
982
983 /*
984 * clear mii interrupt bit
985 */
986 eth->ievent = 0x00800000;
987
988 /*
989 * it's now safe to read the PHY's register
990 */
991 *retVal = (uint16) eth->mii_data;
992
993 return 0;
994}
995
996/********************************************************************/
63ff004c 997int fec5xxx_miiphy_write(char *devname, uint8 phyAddr, uint8 regAddr, uint16 data)
945af8d7
WD
998{
999 ethernet_regs *eth = (ethernet_regs *)MPC5XXX_FEC;
1000 uint32 reg; /* convenient holder for the PHY register */
1001 uint32 phy; /* convenient holder for the PHY */
1002 int timeout = 0xffff;
1003
1004 reg = regAddr << FEC_MII_DATA_RA_SHIFT;
1005 phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
1006
1007 eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
1008 FEC_MII_DATA_TA | phy | reg | data);
1009
1010 /*
1011 * wait for the MII interrupt
1012 */
1013 while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
1014
1015 if (timeout == 0) {
1016#if (DEBUG & 0x2)
1017 printf ("Write MDIO failed...\n");
1018#endif
1019 return -1;
1020 }
1021
1022 /*
1023 * clear MII interrupt bit
1024 */
1025 eth->ievent = 0x00800000;
1026
1027 return 0;
1028}
1029
1030#if (DEBUG & 0x40)
1031static uint32 local_crc32(char *string, unsigned int crc_value, int len)
1032{
1033 int i;
1034 char c;
1035 unsigned int crc, count;
1036
1037 /*
1038 * crc32 algorithm
1039 */
1040 /*
1041 * crc = 0xffffffff; * The initialized value should be 0xffffffff
1042 */
1043 crc = crc_value;
1044
1045 for (i = len; --i >= 0;) {
1046 c = *string++;
1047 for (count = 0; count < 8; count++) {
1048 if ((c & 0x01) ^ (crc & 0x01)) {
1049 crc >>= 1;
1050 crc = crc ^ 0xedb88320;
1051 } else {
1052 crc >>= 1;
1053 }
1054 c >>= 1;
1055 }
1056 }
1057
1058 /*
1059 * In big endian system, do byte swaping for crc value
1060 */
1061 /**/ return crc;
1062}
1063#endif /* DEBUG */
1064
cbd8a35c 1065#endif /* CONFIG_MPC5xxx_FEC */