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