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