]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/powerpc/cpu/mpc8220/fec.c
43fa802ca96db0a5a4e6f0542fb5873877d3ecd5
[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                 /*
292                  * tbd - rtm
293                  * fec->eth->mii_speed = (((gd->arch.ipb_clk >> 20) / 5) << 1);
294                  * No MII for 7-wire mode
295                  */
296                 fec->eth->mii_speed = 0x00000030;
297         }
298
299         /*
300          * Set Opcode/Pause Duration Register
301          */
302         fec->eth->op_pause = 0x00010020;        /*FIXME0xffff0020; */
303
304         /*
305          * Set Rx FIFO alarm and granularity value
306          */
307         fec->eth->rfifo_cntrl = 0x0c000000;
308         fec->eth->rfifo_alarm = 0x0000030c;
309 #ifdef DEBUG
310         if (fec->eth->rfifo_status & 0x00700000) {
311                 printf ("mpc8220_fec_init() RFIFO error\n");
312         }
313 #endif
314
315         /*
316          * Set Tx FIFO granularity value
317          */
318         /*fec->eth->tfifo_cntrl = 0x0c000000; */ /*tbd - rtm */
319         fec->eth->tfifo_cntrl = 0x0e000000;
320 #ifdef DEBUG
321         printf ("tfifo_status: 0x%08x\n", fec->eth->tfifo_status);
322         printf ("tfifo_alarm: 0x%08x\n", fec->eth->tfifo_alarm);
323 #endif
324
325         /*
326          * Set transmit fifo watermark register(X_WMRK), default = 64
327          */
328         fec->eth->tfifo_alarm = 0x00000080;
329         fec->eth->x_wmrk = 0x2;
330
331         /*
332          * Set individual address filter for unicast address
333          * and set physical address registers.
334          */
335         mpc8220_fec_set_hwaddr (fec, (char *)(dev->enetaddr));
336
337         /*
338          * Set multicast address filter
339          */
340         fec->eth->gaddr1 = 0x00000000;
341         fec->eth->gaddr2 = 0x00000000;
342
343         /*
344          * Turn ON cheater FSM: ????
345          */
346         fec->eth->xmit_fsm = 0x03000000;
347
348 #if 1
349 /*#if defined(CONFIG_MPC5200)*/
350         /*
351          * Turn off COMM bus prefetch in the MGT5200 BestComm. It doesn't
352          * work w/ the current receive task.
353          */
354         dma->PtdCntrl |= 0x00000001;
355 #endif
356
357         /*
358          * Set priority of different initiators
359          */
360         dma->IPR0 = 7;          /* always */
361         dma->IPR3 = 6;          /* Eth RX */
362         dma->IPR4 = 5;          /* Eth Tx */
363
364         /*
365          * Clear SmartDMA task interrupt pending bits
366          */
367         DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO);
368
369         /*
370          * Initialize SmartDMA parameters stored in SRAM
371          */
372         *(int *) FEC_TBD_BASE = (int) fec->tbdBase;
373         *(int *) FEC_RBD_BASE = (int) fec->rbdBase;
374         *(int *) FEC_TBD_NEXT = (int) fec->tbdBase;
375         *(int *) FEC_RBD_NEXT = (int) fec->rbdBase;
376
377         if (fec->xcv_type != SEVENWIRE) {
378                 /*
379                  * Initialize PHY(LXT971A):
380                  *
381                  *   Generally, on power up, the LXT971A reads its configuration
382                  *   pins to check for forced operation, If not cofigured for
383                  *   forced operation, it uses auto-negotiation/parallel detection
384                  *   to automatically determine line operating conditions.
385                  *   If the PHY device on the other side of the link supports
386                  *   auto-negotiation, the LXT971A auto-negotiates with it
387                  *   using Fast Link Pulse(FLP) Bursts. If the PHY partner does not
388                  *   support auto-negotiation, the LXT971A automatically detects
389                  *   the presence of either link pulses(10Mbps PHY) or Idle
390                  *   symbols(100Mbps) and sets its operating conditions accordingly.
391                  *
392                  *   When auto-negotiation is controlled by software, the following
393                  *   steps are recommended.
394                  *
395                  * Note:
396                  *   The physical address is dependent on hardware configuration.
397                  *
398                  */
399                 int timeout = 1;
400                 u16 phyStatus;
401
402                 /*
403                  * Reset PHY, then delay 300ns
404                  */
405                 miiphy_write (dev->name, phyAddr, 0x0, 0x8000);
406                 udelay (1000);
407
408                 if (fec->xcv_type == MII10) {
409                         /*
410                          * Force 10Base-T, FDX operation
411                          */
412 #ifdef DEBUG
413                         printf ("Forcing 10 Mbps ethernet link... ");
414 #endif
415                         miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
416                         /*
417                            miiphy_write(fec, phyAddr, 0x0, 0x0100);
418                          */
419                         miiphy_write (dev->name, phyAddr, 0x0, 0x0180);
420
421                         timeout = 20;
422                         do {    /* wait for link status to go down */
423                                 udelay (10000);
424                                 if ((timeout--) == 0) {
425 #ifdef DEBUG
426                                         printf ("hmmm, should not have waited...");
427 #endif
428                                         break;
429                                 }
430                                 miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
431 #ifdef DEBUG
432                                 printf ("=");
433 #endif
434                         } while ((phyStatus & 0x0004)); /* !link up */
435
436                         timeout = 1000;
437                         do {    /* wait for link status to come back up */
438                                 udelay (10000);
439                                 if ((timeout--) == 0) {
440                                         printf ("failed. Link is down.\n");
441                                         break;
442                                 }
443                                 miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
444 #ifdef DEBUG
445                                 printf ("+");
446 #endif
447                         } while (!(phyStatus & 0x0004));        /* !link up */
448
449 #ifdef DEBUG
450                         printf ("done.\n");
451 #endif
452                 } else {        /* MII100 */
453                         /*
454                          * Set the auto-negotiation advertisement register bits
455                          */
456                         miiphy_write (dev->name, phyAddr, 0x4, 0x01e1);
457
458                         /*
459                          * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
460                          */
461                         miiphy_write (dev->name, phyAddr, 0x0, 0x1200);
462
463                         /*
464                          * Wait for AN completion
465                          */
466                         timeout = 5000;
467                         do {
468                                 udelay (1000);
469
470                                 if ((timeout--) == 0) {
471 #ifdef DEBUG
472                                         printf ("PHY auto neg 0 failed...\n");
473 #endif
474                                         return -1;
475                                 }
476
477                                 if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) !=
478                                     0) {
479 #ifdef DEBUG
480                                         printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
481 #endif
482                                         return -1;
483                                 }
484                         } while (!(phyStatus & 0x0004));
485
486 #ifdef DEBUG
487                         printf ("PHY auto neg complete! \n");
488 #endif
489                 }
490
491         }
492
493         /*
494          * Enable FEC-Lite controller
495          */
496         fec->eth->ecntrl |= 0x00000006;
497
498 #ifdef DEBUG
499         if (fec->xcv_type != SEVENWIRE)
500                 mpc8220_fec_phydump (dev->name);
501 #endif
502
503         /*
504          * Enable SmartDMA receive task
505          */
506         DMA_TASK_ENABLE (FEC_RECV_TASK_NO);
507
508 #ifdef DEBUG
509         printf ("mpc8220_fec_init... Done \n");
510 #endif
511
512         return 1;
513 }
514
515 /********************************************************************/
516 static void mpc8220_fec_halt (struct eth_device *dev)
517 {
518         mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
519         int counter = 0xffff;
520
521 #ifdef DEBUG
522         if (fec->xcv_type != SEVENWIRE)
523                 mpc8220_fec_phydump (dev->name);
524 #endif
525
526         /*
527          * mask FEC chip interrupts
528          */
529         fec->eth->imask = 0;
530
531         /*
532          * issue graceful stop command to the FEC transmitter if necessary
533          */
534         fec->eth->x_cntrl |= 0x00000001;
535
536         /*
537          * wait for graceful stop to register
538          */
539         while ((counter--) && (!(fec->eth->ievent & 0x10000000)));
540
541         /*
542          * Disable SmartDMA tasks
543          */
544         DMA_TASK_DISABLE (FEC_XMIT_TASK_NO);
545         DMA_TASK_DISABLE (FEC_RECV_TASK_NO);
546
547         /*
548          * Disable the Ethernet Controller
549          */
550         fec->eth->ecntrl &= 0xfffffffd;
551
552         /*
553          * Clear FIFO status registers
554          */
555         fec->eth->rfifo_status &= 0x00700000;
556         fec->eth->tfifo_status &= 0x00700000;
557
558         fec->eth->reset_cntrl = 0x01000000;
559
560         /*
561          * Issue a reset command to the FEC chip
562          */
563         fec->eth->ecntrl |= 0x1;
564
565         /*
566          * wait at least 16 clock cycles
567          */
568         udelay (10);
569
570 #ifdef DEBUG
571         printf ("Ethernet task stopped\n");
572 #endif
573 }
574
575 #ifdef DEBUG
576 /********************************************************************/
577
578 static void tfifo_print (char *devname, mpc8220_fec_priv * fec)
579 {
580         u16 phyAddr = CONFIG_PHY_ADDR;
581         u16 phyStatus;
582
583         if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr)
584             || (fec->eth->tfifo_rdptr != fec->eth->tfifo_wrptr)) {
585
586                 miiphy_read (devname, phyAddr, 0x1, &phyStatus);
587                 printf ("\nphyStatus: 0x%04x\n", phyStatus);
588                 printf ("ecntrl:   0x%08x\n", fec->eth->ecntrl);
589                 printf ("ievent:   0x%08x\n", fec->eth->ievent);
590                 printf ("x_status: 0x%08x\n", fec->eth->x_status);
591                 printf ("tfifo: status  0x%08x\n", fec->eth->tfifo_status);
592
593                 printf ("       control 0x%08x\n", fec->eth->tfifo_cntrl);
594                 printf ("       lrfp    0x%08x\n", fec->eth->tfifo_lrf_ptr);
595                 printf ("       lwfp    0x%08x\n", fec->eth->tfifo_lwf_ptr);
596                 printf ("       alarm   0x%08x\n", fec->eth->tfifo_alarm);
597                 printf ("       readptr 0x%08x\n", fec->eth->tfifo_rdptr);
598                 printf ("       writptr 0x%08x\n", fec->eth->tfifo_wrptr);
599         }
600 }
601
602 static void rfifo_print (char *devname, mpc8220_fec_priv * fec)
603 {
604         u16 phyAddr = CONFIG_PHY_ADDR;
605         u16 phyStatus;
606
607         if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr)
608             || (fec->eth->rfifo_rdptr != fec->eth->rfifo_wrptr)) {
609
610                 miiphy_read (devname, phyAddr, 0x1, &phyStatus);
611                 printf ("\nphyStatus: 0x%04x\n", phyStatus);
612                 printf ("ecntrl:   0x%08x\n", fec->eth->ecntrl);
613                 printf ("ievent:   0x%08x\n", fec->eth->ievent);
614                 printf ("x_status: 0x%08x\n", fec->eth->x_status);
615                 printf ("rfifo: status  0x%08x\n", fec->eth->rfifo_status);
616
617                 printf ("       control 0x%08x\n", fec->eth->rfifo_cntrl);
618                 printf ("       lrfp    0x%08x\n", fec->eth->rfifo_lrf_ptr);
619                 printf ("       lwfp    0x%08x\n", fec->eth->rfifo_lwf_ptr);
620                 printf ("       alarm   0x%08x\n", fec->eth->rfifo_alarm);
621                 printf ("       readptr 0x%08x\n", fec->eth->rfifo_rdptr);
622                 printf ("       writptr 0x%08x\n", fec->eth->rfifo_wrptr);
623         }
624 }
625 #endif /* DEBUG */
626
627 /********************************************************************/
628
629 static int mpc8220_fec_send(struct eth_device *dev, void *eth_data,
630                              int data_length)
631 {
632         /*
633          * This routine transmits one frame.  This routine only accepts
634          * 6-byte Ethernet addresses.
635          */
636         mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
637         FEC_TBD *pTbd;
638
639 #ifdef DEBUG
640         printf ("tbd status: 0x%04x\n", fec->tbdBase[0].status);
641         tfifo_print (dev->name, fec);
642 #endif
643
644         /*
645          * Clear Tx BD ring at first
646          */
647         mpc8220_fec_tbd_scrub (fec);
648
649         /*
650          * Check for valid length of data.
651          */
652         if ((data_length > 1500) || (data_length <= 0)) {
653                 return -1;
654         }
655
656         /*
657          * Check the number of vacant TxBDs.
658          */
659         if (fec->cleanTbdNum < 1) {
660 #ifdef DEBUG
661                 printf ("No available TxBDs ...\n");
662 #endif
663                 return -1;
664         }
665
666         /*
667          * Get the first TxBD to send the mac header
668          */
669         pTbd = &fec->tbdBase[fec->tbdIndex];
670         pTbd->dataLength = data_length;
671         pTbd->dataPointer = (u32) eth_data;
672         pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
673         fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
674
675 #ifdef DEBUG
676         printf ("DMA_TASK_ENABLE, fec->tbdIndex = %d \n", fec->tbdIndex);
677 #endif
678
679         /*
680          * Kick the MII i/f
681          */
682         if (fec->xcv_type != SEVENWIRE) {
683                 u16 phyStatus;
684
685                 miiphy_read (dev->name, 0, 0x1, &phyStatus);
686         }
687
688         /*
689          * Enable SmartDMA transmit task
690          */
691
692 #ifdef DEBUG
693         tfifo_print (dev->name, fec);
694 #endif
695
696         DMA_TASK_ENABLE (FEC_XMIT_TASK_NO);
697
698 #ifdef DEBUG
699         tfifo_print (dev->name, fec);
700 #endif
701
702 #ifdef DEBUG
703         printf ("+");
704 #endif
705
706         fec->cleanTbdNum -= 1;
707
708 #ifdef DEBUG
709         printf ("smartDMA ethernet Tx task enabled\n");
710 #endif
711         /*
712          * wait until frame is sent .
713          */
714         while (pTbd->status & FEC_TBD_READY) {
715                 udelay (10);
716 #ifdef DEBUG
717                 printf ("TDB status = %04x\n", pTbd->status);
718 #endif
719         }
720
721         return 0;
722 }
723
724
725 /********************************************************************/
726 static int mpc8220_fec_recv (struct eth_device *dev)
727 {
728         /*
729          * This command pulls one frame from the card
730          */
731         mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv;
732         FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex];
733         unsigned long ievent;
734         int frame_length, len = 0;
735         NBUF *frame;
736
737 #ifdef DEBUG
738         printf ("mpc8220_fec_recv %d Start...\n", fec->rbdIndex);
739         printf ("-");
740 #endif
741
742         /*
743          * Check if any critical events have happened
744          */
745         ievent = fec->eth->ievent;
746         fec->eth->ievent = ievent;
747         if (ievent & 0x20060000) {
748                 /* BABT, Rx/Tx FIFO errors */
749                 mpc8220_fec_halt (dev);
750                 mpc8220_fec_init (dev, NULL);
751                 return 0;
752         }
753         if (ievent & 0x80000000) {
754                 /* Heartbeat error */
755                 fec->eth->x_cntrl |= 0x00000001;
756         }
757         if (ievent & 0x10000000) {
758                 /* Graceful stop complete */
759                 if (fec->eth->x_cntrl & 0x00000001) {
760                         mpc8220_fec_halt (dev);
761                         fec->eth->x_cntrl &= ~0x00000001;
762                         mpc8220_fec_init (dev, NULL);
763                 }
764         }
765
766         if (!(pRbd->status & FEC_RBD_EMPTY)) {
767                 if ((pRbd->status & FEC_RBD_LAST)
768                     && !(pRbd->status & FEC_RBD_ERR)
769                     && ((pRbd->dataLength - 4) > 14)) {
770
771                         /*
772                          * Get buffer address and size
773                          */
774                         frame = (NBUF *) pRbd->dataPointer;
775                         frame_length = pRbd->dataLength - 4;
776
777                         /* DEBUG code */
778                         if (_DEBUG) {
779                                 int i;
780
781                                 printf ("recv data hdr:");
782                                 for (i = 0; i < 14; i++)
783                                         printf ("%x ", *(frame->head + i));
784                                 printf ("\n");
785                         }
786
787                         /*
788                          *  Fill the buffer and pass it to upper layers
789                          */
790 /*                      memcpy(buff, frame->head, 14);
791                         memcpy(buff + 14, frame->data, frame_length);*/
792                         NetReceive((uchar *)pRbd->dataPointer, 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 */