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