arm: mach-omap2: Generate MLO file from SD boot capable targets
[platform/kernel/u-boot.git] / drivers / net / mpc512x_fec.c
1 /*
2  * (C) Copyright 2003-2010
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 <malloc.h>
11 #include <net.h>
12 #include <netdev.h>
13 #include <miiphy.h>
14 #include <asm/io.h>
15 #include "mpc512x_fec.h"
16
17 DECLARE_GLOBAL_DATA_PTR;
18
19 #define DEBUG 0
20
21 #if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
22 #error "CONFIG_MII has to be defined!"
23 #endif
24
25 int fec512x_miiphy_read(struct mii_dev *bus, int phyAddr, int devad,
26                         int regAddr);
27 int fec512x_miiphy_write(struct mii_dev *bus, int phyAddr, int devad,
28                          int regAddr, u16 data);
29 int mpc512x_fec_init_phy(struct eth_device *dev, bd_t * bis);
30
31 static uchar rx_buff[FEC_BUFFER_SIZE];
32 static int rx_buff_idx = 0;
33
34 /********************************************************************/
35 #if (DEBUG & 0x2)
36 static void mpc512x_fec_phydump (char *devname)
37 {
38         u16 phyStatus, i;
39         u8 phyAddr = CONFIG_PHY_ADDR;
40         u8 reg_mask[] = {
41                 /* regs to print: 0...8, 21,27,31 */
42                 1, 1, 1, 1,  1, 1, 1, 1,     1, 0, 0, 0,  0, 0, 0, 0,
43                 0, 0, 0, 0,  0, 1, 0, 0,     0, 0, 0, 1,  0, 0, 0, 1,
44         };
45
46         for (i = 0; i < 32; i++) {
47                 if (reg_mask[i]) {
48                         miiphy_read (devname, phyAddr, i, &phyStatus);
49                         printf ("Mii reg %d: 0x%04x\n", i, phyStatus);
50                 }
51         }
52 }
53 #endif
54
55 /********************************************************************/
56 static int mpc512x_fec_bd_init (mpc512x_fec_priv *fec)
57 {
58         int ix;
59
60         /*
61          * Receive BDs init
62          */
63         for (ix = 0; ix < FEC_RBD_NUM; ix++) {
64                 fec->bdBase->rbd[ix].dataPointer =
65                                 (u32)&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          * Set Descriptor polling active
119          */
120         out_be32(&fec->eth->r_des_active, 0x01000000);
121 }
122
123 /********************************************************************/
124 static void mpc512x_fec_tbd_scrub (mpc512x_fec_priv *fec)
125 {
126         volatile FEC_TBD *pUsedTbd;
127
128 #if (DEBUG & 0x1)
129         printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
130                 fec->cleanTbdNum, fec->usedTbdIndex);
131 #endif
132
133         /*
134          * process all the consumed TBDs
135          */
136         while (fec->cleanTbdNum < FEC_TBD_NUM) {
137                 pUsedTbd = &fec->bdBase->tbd[fec->usedTbdIndex];
138                 if (pUsedTbd->status & FEC_TBD_READY) {
139 #if (DEBUG & 0x20)
140                         printf ("Cannot clean TBD %d, in use\n", fec->usedTbdIndex);
141 #endif
142                         return;
143                 }
144
145                 /*
146                  * clean this buffer descriptor
147                  */
148                 if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
149                         pUsedTbd->status = FEC_TBD_WRAP;
150                 else
151                         pUsedTbd->status = 0;
152
153                 /*
154                  * update some indeces for a correct handling of the TBD ring
155                  */
156                 fec->cleanTbdNum++;
157                 fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
158         }
159 }
160
161 /********************************************************************/
162 static void mpc512x_fec_set_hwaddr (mpc512x_fec_priv *fec, unsigned char *mac)
163 {
164         u8 currByte;                    /* byte for which to compute the CRC */
165         int byte;                       /* loop - counter */
166         int bit;                        /* loop - counter */
167         u32 crc = 0xffffffff;           /* initial value */
168
169         /*
170          * The algorithm used is the following:
171          * we loop on each of the six bytes of the provided address,
172          * and we compute the CRC by left-shifting the previous
173          * value by one position, so that each bit in the current
174          * byte of the address may contribute the calculation. If
175          * the latter and the MSB in the CRC are different, then
176          * the CRC value so computed is also ex-ored with the
177          * "polynomium generator". The current byte of the address
178          * is also shifted right by one bit at each iteration.
179          * This is because the CRC generatore in hardware is implemented
180          * as a shift-register with as many ex-ores as the radixes
181          * in the polynomium. This suggests that we represent the
182          * polynomiumm itself as a 32-bit constant.
183          */
184         for (byte = 0; byte < 6; byte++) {
185                 currByte = mac[byte];
186                 for (bit = 0; bit < 8; bit++) {
187                         if ((currByte & 0x01) ^ (crc & 0x01)) {
188                                 crc >>= 1;
189                                 crc = crc ^ 0xedb88320;
190                         } else {
191                                 crc >>= 1;
192                         }
193                         currByte >>= 1;
194                 }
195         }
196
197         crc = crc >> 26;
198
199         /*
200          * Set individual hash table register
201          */
202         if (crc >= 32) {
203                 out_be32(&fec->eth->iaddr1, (1 << (crc - 32)));
204                 out_be32(&fec->eth->iaddr2, 0);
205         } else {
206                 out_be32(&fec->eth->iaddr1, 0);
207                 out_be32(&fec->eth->iaddr2, (1 << crc));
208         }
209
210         /*
211          * Set physical address
212          */
213         out_be32(&fec->eth->paddr1, (mac[0] << 24) + (mac[1] << 16) +
214                                     (mac[2] <<  8) + mac[3]);
215         out_be32(&fec->eth->paddr2, (mac[4] << 24) + (mac[5] << 16) +
216                                      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         mpc512x_fec_set_hwaddr (fec, dev->enetaddr);
229         out_be32(&fec->eth->gaddr1, 0x00000000);
230         out_be32(&fec->eth->gaddr2, 0x00000000);
231
232         mpc512x_fec_init_phy (dev, bis);
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, (u32)fec->bdBase->rbd);
261         out_be32(&fec->eth->x_des_start, (u32)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 u8 phyAddr = CONFIG_PHY_ADDR;     /* Only one PHY */
286         int timeout = 1;
287         u16 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->arch.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, 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 = (u32)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 ", *((u8*)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                                 net_process_received_packet((uchar *)rx_buff,
597                                                             frame_length);
598                                 rx_buff_idx = 0;
599                         }
600                 }
601
602                 /*
603                  * Reset buffer descriptor as empty
604                  */
605                 mpc512x_fec_rbd_clean (fec, pRbd);
606         }
607
608         /* Try to fill Buffer Descriptors */
609         out_be32(&fec->eth->r_des_active, 0x01000000);
610
611         return frame_length;
612 }
613
614 /********************************************************************/
615 int mpc512x_fec_initialize (bd_t * bis)
616 {
617         volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
618         mpc512x_fec_priv *fec;
619         struct eth_device *dev;
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 = &im->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 = (int)&im->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         strcpy(dev->name, "FEC");
641         eth_register (dev);
642
643 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
644         int retval;
645         struct mii_dev *mdiodev = mdio_alloc();
646         if (!mdiodev)
647                 return -ENOMEM;
648         strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
649         mdiodev->read = fec512x_miiphy_read;
650         mdiodev->write = fec512x_miiphy_write;
651
652         retval = mdio_register(mdiodev);
653         if (retval < 0)
654                 return retval;
655 #endif
656
657         /* Clean up space FEC's MIB and FIFO RAM ...*/
658         memset ((void *)&im->fec.mib,  0x00, sizeof(im->fec.mib));
659         memset ((void *)&im->fec.fifo, 0x00, sizeof(im->fec.fifo));
660
661         /*
662          * Malloc space for BDs  (must be quad word-aligned)
663          * this pointer is lost, so cannot be freed
664          */
665         bd = malloc (sizeof(mpc512x_buff_descs) + 0x1f);
666         fec->bdBase = (mpc512x_buff_descs*)((u32)bd & 0xfffffff0);
667         memset ((void *) bd, 0x00, sizeof(mpc512x_buff_descs) + 0x1f);
668
669         /*
670          * Set interrupt mask register
671          */
672         out_be32(&fec->eth->imask, 0x00000000);
673
674         /*
675          * Clear FEC-Lite interrupt event register(IEVENT)
676          */
677         out_be32(&fec->eth->ievent, 0xffffffff);
678
679         return 1;
680 }
681
682 /* MII-interface related functions */
683 /********************************************************************/
684 int fec512x_miiphy_read(struct mii_dev *bus, int phyAddr, int devad,
685                         int regAddr)
686 {
687         u16 retVal = 0;
688         volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
689         volatile fec512x_t *eth = &im->fec;
690         u32 reg;                /* convenient holder for the PHY register */
691         u32 phy;                /* convenient holder for the PHY */
692         int timeout = 0xffff;
693
694         /*
695          * reading from any PHY's register is done by properly
696          * programming the FEC's MII data register.
697          */
698         reg = regAddr << FEC_MII_DATA_RA_SHIFT;
699         phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
700
701         out_be32(&eth->mii_data, FEC_MII_DATA_ST |
702                                  FEC_MII_DATA_OP_RD |
703                                  FEC_MII_DATA_TA |
704                                  phy | reg);
705
706         /*
707          * wait for the related interrupt
708          */
709         while ((timeout--) && (!(in_be32(&eth->ievent) & 0x00800000)))
710                 ;
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         out_be32(&eth->ievent, 0x00800000);
723
724         /*
725          * it's now safe to read the PHY's register
726          */
727         retVal = (u16) in_be32(&eth->mii_data);
728
729         return retVal;
730 }
731
732 /********************************************************************/
733 int fec512x_miiphy_write(struct mii_dev *bus, int phyAddr, int devad,
734                          int regAddr, u16 data)
735 {
736         volatile immap_t *im = (immap_t *) CONFIG_SYS_IMMR;
737         volatile fec512x_t *eth = &im->fec;
738         u32 reg;                /* convenient holder for the PHY register */
739         u32 phy;                /* convenient holder for the PHY */
740         int timeout = 0xffff;
741
742         reg = regAddr << FEC_MII_DATA_RA_SHIFT;
743         phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
744
745         out_be32(&eth->mii_data, FEC_MII_DATA_ST |
746                                  FEC_MII_DATA_OP_WR |
747                                  FEC_MII_DATA_TA |
748                                  phy | reg | data);
749
750         /*
751          * wait for the MII interrupt
752          */
753         while ((timeout--) && (!(in_be32(&eth->ievent) & 0x00800000)))
754                 ;
755
756         if (timeout == 0) {
757 #if (DEBUG & 0x2)
758                 printf ("Write MDIO failed...\n");
759 #endif
760                 return -1;
761         }
762
763         /*
764          * clear MII interrupt bit
765          */
766         out_be32(&eth->ievent, 0x00800000);
767
768         return 0;
769 }