Merge with git://www.denx.de/git/u-boot.git
[platform/kernel/u-boot.git] / cpu / mpc512x / fec.c
1 /*
2  * (C) Copyright 2003-2007
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * Derived from the MPC8xx FEC driver.
6  * Adapted for MPC512x by Grzegorz Bernacki <gjb@semihalf.com>
7  */
8
9 #include <common.h>
10 #include <mpc512x.h>
11 #include <malloc.h>
12 #include <net.h>
13 #include <miiphy.h>
14 #include "fec.h"
15
16 DECLARE_GLOBAL_DATA_PTR;
17
18 #define DEBUG 0
19
20 #if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
21         defined(CONFIG_MPC512x_FEC)
22
23 #if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
24 #error "CONFIG_MII has to be defined!"
25 #endif
26
27 #if (DEBUG & 0x40)
28 static uint32 local_crc32(char *string, unsigned int crc_value, int len);
29 #endif
30
31 int fec512x_miiphy_read(char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal);
32 int fec512x_miiphy_write(char *devname, uint8 phyAddr, uint8 regAddr, uint16 data);
33 int mpc512x_fec_init_phy(struct eth_device *dev, bd_t * bis);
34
35 /********************************************************************/
36 #if (DEBUG & 0x2)
37 static void mpc512x_fec_phydump (char *devname)
38 {
39         uint16 phyStatus, i;
40         uint8 phyAddr = CONFIG_PHY_ADDR;
41         uint8 reg_mask[] = {
42                 /* regs to print: 0...8, 21,27,31 */
43                 1, 1, 1, 1,  1, 1, 1, 1,     1, 0, 0, 0,  0, 0, 0, 0,
44                 0, 0, 0, 0,  0, 1, 0, 0,     0, 0, 0, 1,  0, 0, 0, 1,
45         };
46
47         for (i = 0; i < 32; i++) {
48                 if (reg_mask[i]) {
49                         miiphy_read (devname, phyAddr, i, &phyStatus);
50                         printf ("Mii reg %d: 0x%04x\n", i, phyStatus);
51                 }
52         }
53 }
54 #endif
55
56 /********************************************************************/
57 static int mpc512x_fec_bd_init (mpc512x_fec_priv *fec)
58 {
59         int ix;
60
61         /*
62          * Receive BDs init
63          */
64         for (ix = 0; ix < FEC_RBD_NUM; ix++) {
65                 fec->bdBase->rbd[ix].dataPointer = (uint32)&fec->bdBase->recv_frames[ix];
66                 fec->bdBase->rbd[ix].status = FEC_RBD_EMPTY;
67                 fec->bdBase->rbd[ix].dataLength = 0;
68         }
69
70         /*
71          * have the last RBD to close the ring
72          */
73         fec->bdBase->rbd[ix - 1].status |= FEC_RBD_WRAP;
74         fec->rbdIndex = 0;
75
76         /*
77          * Trasmit BDs init
78          */
79         for (ix = 0; ix < FEC_TBD_NUM; ix++) {
80                 fec->bdBase->tbd[ix].status = 0;
81         }
82
83         /*
84          * Have the last TBD to close the ring
85          */
86         fec->bdBase->tbd[ix - 1].status |= FEC_TBD_WRAP;
87
88         /*
89          * Initialize some indices
90          */
91         fec->tbdIndex = 0;
92         fec->usedTbdIndex = 0;
93         fec->cleanTbdNum = FEC_TBD_NUM;
94
95         return 0;
96 }
97
98 /********************************************************************/
99 static void mpc512x_fec_rbd_clean (mpc512x_fec_priv *fec, volatile FEC_RBD * pRbd)
100 {
101         /*
102          * Reset buffer descriptor as empty
103          */
104         if ((fec->rbdIndex) == (FEC_RBD_NUM - 1))
105                 pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY);
106         else
107                 pRbd->status = FEC_RBD_EMPTY;
108
109         pRbd->dataLength = 0;
110
111         /*
112          * Increment BD count
113          */
114         fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM;
115
116         /*
117          * Now, we have an empty RxBD, notify FEC
118          */
119         fec->eth->r_des_active = 0x01000000;    /* Descriptor polling active */
120 }
121
122 /********************************************************************/
123 static void mpc512x_fec_tbd_scrub (mpc512x_fec_priv *fec)
124 {
125         volatile FEC_TBD *pUsedTbd;
126
127 #if (DEBUG & 0x1)
128         printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
129                 fec->cleanTbdNum, fec->usedTbdIndex);
130 #endif
131
132         /*
133          * process all the consumed TBDs
134          */
135         while (fec->cleanTbdNum < FEC_TBD_NUM) {
136                 pUsedTbd = &fec->bdBase->tbd[fec->usedTbdIndex];
137                 if (pUsedTbd->status & FEC_TBD_READY) {
138 #if (DEBUG & 0x20)
139                         printf ("Cannot clean TBD %d, in use\n", fec->usedTbdIndex);
140 #endif
141                         return;
142                 }
143
144                 /*
145                  * clean this buffer descriptor
146                  */
147                 if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
148                         pUsedTbd->status = FEC_TBD_WRAP;
149                 else
150                         pUsedTbd->status = 0;
151
152                 /*
153                  * update some indeces for a correct handling of the TBD ring
154                  */
155                 fec->cleanTbdNum++;
156                 fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
157         }
158 }
159
160 /********************************************************************/
161 static void mpc512x_fec_set_hwaddr (mpc512x_fec_priv *fec, char *mac)
162 {
163         uint8 currByte;                 /* byte for which to compute the CRC */
164         int byte;                       /* loop - counter */
165         int bit;                        /* loop - counter */
166         uint32 crc = 0xffffffff;        /* initial value */
167
168         /*
169          * The algorithm used is the following:
170          * we loop on each of the six bytes of the provided address,
171          * and we compute the CRC by left-shifting the previous
172          * value by one position, so that each bit in the current
173          * byte of the address may contribute the calculation. If
174          * the latter and the MSB in the CRC are different, then
175          * the CRC value so computed is also ex-ored with the
176          * "polynomium generator". The current byte of the address
177          * is also shifted right by one bit at each iteration.
178          * This is because the CRC generatore in hardware is implemented
179          * as a shift-register with as many ex-ores as the radixes
180          * in the polynomium. This suggests that we represent the
181          * polynomiumm itself as a 32-bit constant.
182          */
183         for (byte = 0; byte < 6; byte++) {
184                 currByte = mac[byte];
185                 for (bit = 0; bit < 8; bit++) {
186                         if ((currByte & 0x01) ^ (crc & 0x01)) {
187                                 crc >>= 1;
188                                 crc = crc ^ 0xedb88320;
189                         } else {
190                                 crc >>= 1;
191                         }
192                         currByte >>= 1;
193                 }
194         }
195
196         crc = crc >> 26;
197
198         /*
199          * Set individual hash table register
200          */
201         if (crc >= 32) {
202                 fec->eth->iaddr1 = (1 << (crc - 32));
203                 fec->eth->iaddr2 = 0;
204         } else {
205                 fec->eth->iaddr1 = 0;
206                 fec->eth->iaddr2 = (1 << crc);
207         }
208
209         /*
210          * Set physical address
211          */
212         fec->eth->paddr1 = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
213         fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
214 }
215
216 /********************************************************************/
217 static int mpc512x_fec_init (struct eth_device *dev, bd_t * bis)
218 {
219         mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
220
221 #if (DEBUG & 0x1)
222         printf ("mpc512x_fec_init... Begin\n");
223 #endif
224
225         /* Set interrupt mask register */
226         fec->eth->imask = 0x00000000;
227
228         /* Clear FEC-Lite interrupt event register(IEVENT) */
229         fec->eth->ievent = 0xffffffff;
230
231         /* Set transmit fifo watermark register(X_WMRK), default = 64 */
232         fec->eth->x_wmrk = 0x0;
233
234         /* Set Opcode/Pause Duration Register */
235         fec->eth->op_pause = 0x00010020;
236
237         /* Frame length=1518; MII mode */
238         fec->eth->r_cntrl = 0x05ee000c;
239
240         /* Half-duplex, heartbeat disabled */
241         fec->eth->x_cntrl = 0x00000000;
242
243         /* Enable MIB counters */
244         fec->eth->mib_control = 0x0;
245
246         /* Setup recv fifo start and buff size */
247         fec->eth->r_fstart = 0x500;
248         fec->eth->r_buff_size = 0x5e0;
249
250         /* Setup BD base addresses */
251         fec->eth->r_des_start = (uint32)fec->bdBase->rbd;
252         fec->eth->x_des_start = (uint32)fec->bdBase->tbd;
253
254         /* DMA Control */
255         fec->eth->dma_control = 0xc0000000;
256
257         /* Enable FEC */
258         fec->eth->ecntrl |= 0x00000006;
259
260         /* Initilize addresses and status words of BDs */
261         mpc512x_fec_bd_init (fec);
262
263          /* Descriptor polling active */
264         fec->eth->r_des_active = 0x01000000;
265
266 #if (DEBUG & 0x1)
267         printf("mpc512x_fec_init... Done \n");
268 #endif
269         return 1;
270 }
271
272 /********************************************************************/
273 int mpc512x_fec_init_phy (struct eth_device *dev, bd_t * bis)
274 {
275         mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
276         const uint8 phyAddr = CONFIG_PHY_ADDR;  /* Only one PHY */
277         int timeout = 1;
278         uint16 phyStatus;
279
280 #if (DEBUG & 0x1)
281         printf ("mpc512x_fec_init_phy... Begin\n");
282 #endif
283
284         /*
285          * Clear FEC-Lite interrupt event register(IEVENT)
286          */
287         fec->eth->ievent = 0xffffffff;
288
289         /*
290          * Set interrupt mask register
291          */
292         fec->eth->imask = 0x00000000;
293
294         if (fec->xcv_type != SEVENWIRE) {
295                 /*
296                  * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
297                  * and do not drop the Preamble.
298                  */
299                 fec->eth->mii_speed = (((gd->ipb_clk / 1000000) / 5) + 1) << 1;
300
301                 /*
302                  * Reset PHY, then delay 300ns
303                  */
304                 miiphy_write (dev->name, phyAddr, 0x0, 0x8000);
305                 udelay (1000);
306
307                 if (fec->xcv_type == MII10) {
308                 /*
309                  * Force 10Base-T, FDX operation
310                  */
311 #if (DEBUG & 0x2)
312                         printf ("Forcing 10 Mbps ethernet link... ");
313 #endif
314                         miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
315
316                         miiphy_write (dev->name, phyAddr, 0x0, 0x0180);
317
318                         timeout = 20;
319                         do {    /* wait for link status to go down */
320                                 udelay (10000);
321                                 if ((timeout--) == 0) {
322 #if (DEBUG & 0x2)
323                                         printf ("hmmm, should not have waited...");
324 #endif
325                                         break;
326                                 }
327                                 miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
328 #if (DEBUG & 0x2)
329                                 printf ("=");
330 #endif
331                         } while ((phyStatus & 0x0004)); /* !link up */
332
333                         timeout = 1000;
334                         do {    /* wait for link status to come back up */
335                                 udelay (10000);
336                                 if ((timeout--) == 0) {
337                                         printf ("failed. Link is down.\n");
338                                         break;
339                                 }
340                                 miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
341 #if (DEBUG & 0x2)
342                                 printf ("+");
343 #endif
344                         } while (!(phyStatus & 0x0004)); /* !link up */
345
346 #if (DEBUG & 0x2)
347                         printf ("done.\n");
348 #endif
349                 } else {        /* MII100 */
350                         /*
351                          * Set the auto-negotiation advertisement register bits
352                          */
353                         miiphy_write (dev->name, phyAddr, 0x4, 0x01e1);
354
355                         /*
356                          * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
357                          */
358                         miiphy_write (dev->name, phyAddr, 0x0, 0x1200);
359
360                         /*
361                          * Wait for AN completion
362                          */
363                         timeout = 50000;
364                         do {
365                                 udelay (1000);
366
367                                 if ((timeout--) == 0) {
368 #if (DEBUG & 0x2)
369                                         printf ("PHY auto neg 0 failed...\n");
370 #endif
371                                         return -1;
372                                 }
373
374                                 if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) != 0) {
375 #if (DEBUG & 0x2)
376                                         printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
377 #endif
378                                         return -1;
379                                 }
380                         } while (!(phyStatus & 0x0004));
381
382 #if (DEBUG & 0x2)
383                         printf ("PHY auto neg complete! \n");
384 #endif
385                 }
386         }
387
388 #if (DEBUG & 0x2)
389         if (fec->xcv_type != SEVENWIRE)
390                 mpc512x_fec_phydump (dev->name);
391 #endif
392
393 #if (DEBUG & 0x1)
394         printf ("mpc512x_fec_init_phy... Done \n");
395 #endif
396         return 1;
397 }
398
399 /********************************************************************/
400 static void mpc512x_fec_halt (struct eth_device *dev)
401 {
402         mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
403         int counter = 0xffff;
404
405 #if (DEBUG & 0x2)
406         if (fec->xcv_type != SEVENWIRE)
407                 mpc512x_fec_phydump (dev->name);
408 #endif
409
410         /*
411          * mask FEC chip interrupts
412          */
413         fec->eth->imask = 0;
414
415         /*
416          * issue graceful stop command to the FEC transmitter if necessary
417          */
418         fec->eth->x_cntrl |= 0x00000001;
419
420         /*
421          * wait for graceful stop to register
422          */
423         while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ;
424
425         /*
426          * Disable the Ethernet Controller
427          */
428         fec->eth->ecntrl &= 0xfffffffd;
429
430         /*
431          * Issue a reset command to the FEC chip
432          */
433         fec->eth->ecntrl |= 0x1;
434
435         /*
436          * wait at least 16 clock cycles
437          */
438         udelay (10);
439 #if (DEBUG & 0x3)
440         printf ("Ethernet task stopped\n");
441 #endif
442 }
443
444 /********************************************************************/
445
446 static int mpc512x_fec_send (struct eth_device *dev, volatile void *eth_data,
447                 int data_length)
448 {
449         /*
450          * This routine transmits one frame.  This routine only accepts
451          * 6-byte Ethernet addresses.
452          */
453         mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
454         volatile FEC_TBD *pTbd;
455
456 #if (DEBUG & 0x20)
457         printf("tbd status: 0x%04x\n", fec->tbdBase[fec->tbdIndex].status);
458 #endif
459
460         /*
461          * Clear Tx BD ring at first
462          */
463         mpc512x_fec_tbd_scrub (fec);
464
465         /*
466          * Check for valid length of data.
467          */
468         if ((data_length > 1500) || (data_length <= 0)) {
469                 return -1;
470         }
471
472         /*
473          * Check the number of vacant TxBDs.
474          */
475         if (fec->cleanTbdNum < 1) {
476 #if (DEBUG & 0x20)
477                 printf ("No available TxBDs ...\n");
478 #endif
479                 return -1;
480         }
481
482         /*
483          * Get the first TxBD to send the mac header
484          */
485         pTbd = &fec->bdBase->tbd[fec->tbdIndex];
486         pTbd->dataLength = data_length;
487         pTbd->dataPointer = (uint32)eth_data;
488         pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
489         fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
490
491         /* Activate transmit Buffer Descriptor polling */
492         fec->eth->x_des_active = 0x01000000;    /* Descriptor polling active    */
493
494 #if (DEBUG & 0x8)
495         printf ( "+" );
496 #endif
497
498         fec->cleanTbdNum -= 1;
499
500         /*
501          * wait until frame is sent .
502          */
503         while (pTbd->status & FEC_TBD_READY) {
504                 udelay (10);
505 #if (DEBUG & 0x8)
506                 printf ("TDB status = %04x\n", pTbd->status);
507 #endif
508         }
509
510         return 0;
511 }
512
513
514 /********************************************************************/
515 static int mpc512x_fec_recv (struct eth_device *dev)
516 {
517         /*
518          * This command pulls one frame from the card
519          */
520         mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
521         volatile FEC_RBD *pRbd = &fec->bdBase->rbd[fec->rbdIndex];
522         unsigned long ievent;
523         int frame_length, len = 0;
524         uchar buff[FEC_MAX_PKT_SIZE];
525
526 #if (DEBUG & 0x1)
527         printf ("mpc512x_fec_recv %d Start...\n", fec->rbdIndex);
528 #endif
529 #if (DEBUG & 0x8)
530         printf( "-" );
531 #endif
532
533         /*
534          * Check if any critical events have happened
535          */
536         ievent = fec->eth->ievent;
537         fec->eth->ievent = ievent;
538         if (ievent & 0x20060000) {
539                 /* BABT, Rx/Tx FIFO errors */
540                 mpc512x_fec_halt (dev);
541                 mpc512x_fec_init (dev, NULL);
542                 return 0;
543         }
544         if (ievent & 0x80000000) {
545                 /* Heartbeat error */
546                 fec->eth->x_cntrl |= 0x00000001;
547         }
548         if (ievent & 0x10000000) {
549                 /* Graceful stop complete */
550                 if (fec->eth->x_cntrl & 0x00000001) {
551                         mpc512x_fec_halt (dev);
552                         fec->eth->x_cntrl &= ~0x00000001;
553                         mpc512x_fec_init (dev, NULL);
554                 }
555         }
556
557         if (!(pRbd->status & FEC_RBD_EMPTY)) {
558                 if ((pRbd->status & FEC_RBD_LAST) &&
559                         !(pRbd->status & FEC_RBD_ERR) &&
560                         ((pRbd->dataLength - 4) > 14)) {
561
562                         /*
563                          * Get buffer size
564                          */
565                         frame_length = pRbd->dataLength - 4;
566
567 #if (DEBUG & 0x20)
568                         {
569                                 int i;
570                                 printf ("recv data hdr:");
571                                 for (i = 0; i < 14; i++)
572                                         printf ("%x ", *((uint8*)pRbd->dataPointer + i));
573                                 printf("\n");
574                         }
575 #endif
576
577                         /*
578                          *  Fill the buffer and pass it to upper layers
579                          */
580                         memcpy (buff, (void*)pRbd->dataPointer, frame_length);
581                         NetReceive ((uchar*)buff, frame_length);
582                         len = frame_length;
583                 }
584
585                 /*
586                  * Reset buffer descriptor as empty
587                  */
588                 mpc512x_fec_rbd_clean (fec, pRbd);
589         }
590
591         /* Try to fill Buffer Descriptors */
592         fec->eth->r_des_active = 0x01000000;    /* Descriptor polling active */
593         return len;
594 }
595
596 /********************************************************************/
597 int mpc512x_fec_initialize (bd_t * bis)
598 {
599
600         immap_t *im = (immap_t*) CFG_IMMR;
601         mpc512x_fec_priv *fec;
602         struct eth_device *dev;
603         int i;
604         char *tmp, *end, env_enetaddr[6];
605         uint32 *reg;
606         void * bd;
607
608         fec = (mpc512x_fec_priv *) malloc (sizeof(*fec));
609         dev = (struct eth_device *) malloc (sizeof(*dev));
610         memset (dev, 0, sizeof *dev);
611
612         fec->eth = (ethernet_regs *) MPC512X_FEC;
613
614 # ifndef CONFIG_FEC_10MBIT
615         fec->xcv_type = MII100;
616 # else
617         fec->xcv_type = MII10;
618 # endif
619         dev->priv = (void *)fec;
620         dev->iobase = MPC512X_FEC;
621         dev->init = mpc512x_fec_init;
622         dev->halt = mpc512x_fec_halt;
623         dev->send = mpc512x_fec_send;
624         dev->recv = mpc512x_fec_recv;
625
626         sprintf (dev->name, "FEC ETHERNET");
627         eth_register (dev);
628
629 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
630         miiphy_register (dev->name,
631                         fec512x_miiphy_read, fec512x_miiphy_write);
632 #endif
633
634         /*
635          * Initialize I\O pins
636          */
637         reg = (uint32 *) &(im->io_ctrl.regs[PSC0_0_IDX]);
638
639         for (i = 0; i < 15; i++)
640                 reg[i] = IOCTRL_MUX_FEC | 0x00000001;
641
642         im->io_ctrl.regs[SPDIF_TXCLOCK_IDX] = IOCTRL_MUX_FEC | 0x00000001;
643         im->io_ctrl.regs[SPDIF_TX_IDX] = IOCTRL_MUX_FEC | 0x00000001;
644         im->io_ctrl.regs[SPDIF_RX_IDX] = IOCTRL_MUX_FEC | 0x00000001;
645
646         /* Clean up space FEC's MIB and FIFO RAM ...*/
647         memset ((void *) MPC512X_FEC + 0x200, 0x00, 0x400);
648
649         /*
650          * Malloc space for BDs  (must be quad word-aligned)
651          * this pointer is lost, so cannot be freed
652          */
653         bd = malloc (sizeof(mpc512x_buff_descs) + 0x1f);
654         fec->bdBase = (mpc512x_buff_descs*)((uint32)bd & 0xfffffff0);
655         memset ((void *) bd, 0x00, sizeof(mpc512x_buff_descs) + 0x1f);
656
657         /*
658          * Set interrupt mask register
659          */
660         fec->eth->imask = 0x00000000;
661
662         /*
663          * Clear FEC-Lite interrupt event register(IEVENT)
664          */
665         fec->eth->ievent = 0xffffffff;
666
667         /*
668          * Try to set the mac address now. The fec mac address is
669          * a garbage after reset. When not using fec for booting
670          * the Linux fec driver will try to work with this garbage.
671          */
672         tmp = getenv ("ethaddr");
673         if (tmp) {
674                 for (i=0; i<6; i++) {
675                         env_enetaddr[i] = tmp ? simple_strtoul (tmp, &end, 16) : 0;
676                         if (tmp)
677                                 tmp = (*end) ? end+1 : end;
678                 }
679                 mpc512x_fec_set_hwaddr (fec, env_enetaddr);
680                 fec->eth->gaddr1 = 0x00000000;
681                 fec->eth->gaddr2 = 0x00000000;
682         }
683
684         mpc512x_fec_init_phy (dev, bis);
685
686         return 1;
687 }
688
689 /* MII-interface related functions */
690 /********************************************************************/
691 int fec512x_miiphy_read (char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal)
692 {
693         ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC;
694         uint32 reg;             /* convenient holder for the PHY register */
695         uint32 phy;             /* convenient holder for the PHY */
696         int timeout = 0xffff;
697
698         /*
699          * reading from any PHY's register is done by properly
700          * programming the FEC's MII data register.
701          */
702         reg = regAddr << FEC_MII_DATA_RA_SHIFT;
703         phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
704
705         eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy | reg);
706
707         /*
708          * wait for the related interrupt
709          */
710         while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
711
712         if (timeout == 0) {
713 #if (DEBUG & 0x2)
714                 printf ("Read MDIO failed...\n");
715 #endif
716                 return -1;
717         }
718
719         /*
720          * clear mii interrupt bit
721          */
722         eth->ievent = 0x00800000;
723
724         /*
725          * it's now safe to read the PHY's register
726          */
727         *retVal = (uint16) eth->mii_data;
728
729         return 0;
730 }
731
732 /********************************************************************/
733 int fec512x_miiphy_write (char *devname, uint8 phyAddr, uint8 regAddr, uint16 data)
734 {
735         ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC;
736         uint32 reg;             /* convenient holder for the PHY register */
737         uint32 phy;             /* convenient holder for the PHY */
738         int timeout = 0xffff;
739
740         reg = regAddr << FEC_MII_DATA_RA_SHIFT;
741         phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
742
743         eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
744                         FEC_MII_DATA_TA | phy | reg | data);
745
746         /*
747          * wait for the MII interrupt
748          */
749         while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
750
751         if (timeout == 0) {
752 #if (DEBUG & 0x2)
753                 printf ("Write MDIO failed...\n");
754 #endif
755                 return -1;
756         }
757
758         /*
759          * clear MII interrupt bit
760          */
761         eth->ievent = 0x00800000;
762
763         return 0;
764 }
765
766 #if (DEBUG & 0x40)
767 static uint32 local_crc32 (char *string, unsigned int crc_value, int len)
768 {
769         int i;
770         char c;
771         unsigned int crc, count;
772
773         /*
774          * crc32 algorithm
775          */
776         /*
777          * crc = 0xffffffff; * The initialized value should be 0xffffffff
778          */
779         crc = crc_value;
780
781         for (i = len; --i >= 0;) {
782                 c = *string++;
783                 for (count = 0; count < 8; count++) {
784                         if ((c & 0x01) ^ (crc & 0x01)) {
785                                 crc >>= 1;
786                                 crc = crc ^ 0xedb88320;
787                         } else {
788                                 crc >>= 1;
789                         }
790                         c >>= 1;
791                 }
792         }
793
794         /*
795          * In big endian system, do byte swaping for crc value
796          */
797          /**/ return crc;
798 }
799 #endif  /* DEBUG */
800
801 #endif /* CONFIG_MPC512x_FEC */