source: SVN/rincon/u-boot/cpu/mpc8220/fec.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 22 months ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

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