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