uboot/drivers/net/mpc512x_fec.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2003-2007
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 *
   5 * Derived from the MPC8xx FEC driver.
   6 * Adapted for MPC512x by Grzegorz Bernacki <gjb@semihalf.com>
   7 */
   8
   9#include <common.h>
  10#include <mpc512x.h>
  11#include <malloc.h>
  12#include <net.h>
  13#include <netdev.h>
  14#include <miiphy.h>
  15#include "mpc512x_fec.h"
  16
  17DECLARE_GLOBAL_DATA_PTR;
  18
  19#define DEBUG 0
  20
  21#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
  22        defined(CONFIG_MPC512x_FEC)
  23
  24#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
  25#error "CONFIG_MII has to be defined!"
  26#endif
  27
  28#if (DEBUG & 0x40)
  29static uint32 local_crc32(char *string, unsigned int crc_value, int len);
  30#endif
  31
  32int fec512x_miiphy_read(char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal);
  33int fec512x_miiphy_write(char *devname, uint8 phyAddr, uint8 regAddr, uint16 data);
  34int mpc512x_fec_init_phy(struct eth_device *dev, bd_t * bis);
  35
  36static uchar rx_buff[FEC_BUFFER_SIZE];
  37static int rx_buff_idx = 0;
  38
  39/********************************************************************/
  40#if (DEBUG & 0x2)
  41static void mpc512x_fec_phydump (char *devname)
  42{
  43        uint16 phyStatus, i;
  44        uint8 phyAddr = CONFIG_PHY_ADDR;
  45        uint8 reg_mask[] = {
  46                /* regs to print: 0...8, 21,27,31 */
  47                1, 1, 1, 1,  1, 1, 1, 1,     1, 0, 0, 0,  0, 0, 0, 0,
  48                0, 0, 0, 0,  0, 1, 0, 0,     0, 0, 0, 1,  0, 0, 0, 1,
  49        };
  50
  51        for (i = 0; i < 32; i++) {
  52                if (reg_mask[i]) {
  53                        miiphy_read (devname, phyAddr, i, &phyStatus);
  54                        printf ("Mii reg %d: 0x%04x\n", i, phyStatus);
  55                }
  56        }
  57}
  58#endif
  59
  60/********************************************************************/
  61static int mpc512x_fec_bd_init (mpc512x_fec_priv *fec)
  62{
  63        int ix;
  64
  65        /*
  66         * Receive BDs init
  67         */
  68        for (ix = 0; ix < FEC_RBD_NUM; ix++) {
  69                fec->bdBase->rbd[ix].dataPointer = (uint32)&fec->bdBase->recv_frames[ix];
  70                fec->bdBase->rbd[ix].status = FEC_RBD_EMPTY;
  71                fec->bdBase->rbd[ix].dataLength = 0;
  72        }
  73
  74        /*
  75         * have the last RBD to close the ring
  76         */
  77        fec->bdBase->rbd[ix - 1].status |= FEC_RBD_WRAP;
  78        fec->rbdIndex = 0;
  79
  80        /*
  81         * Trasmit BDs init
  82         */
  83        for (ix = 0; ix < FEC_TBD_NUM; ix++) {
  84                fec->bdBase->tbd[ix].status = 0;
  85        }
  86
  87        /*
  88         * Have the last TBD to close the ring
  89         */
  90        fec->bdBase->tbd[ix - 1].status |= FEC_TBD_WRAP;
  91
  92        /*
  93         * Initialize some indices
  94         */
  95        fec->tbdIndex = 0;
  96        fec->usedTbdIndex = 0;
  97        fec->cleanTbdNum = FEC_TBD_NUM;
  98
  99        return 0;
 100}
 101
 102/********************************************************************/
 103static void mpc512x_fec_rbd_clean (mpc512x_fec_priv *fec, volatile FEC_RBD * pRbd)
 104{
 105        /*
 106         * Reset buffer descriptor as empty
 107         */
 108        if ((fec->rbdIndex) == (FEC_RBD_NUM - 1))
 109                pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY);
 110        else
 111                pRbd->status = FEC_RBD_EMPTY;
 112
 113        pRbd->dataLength = 0;
 114
 115        /*
 116         * Increment BD count
 117         */
 118        fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM;
 119
 120        /*
 121         * Now, we have an empty RxBD, notify FEC
 122         */
 123        fec->eth->r_des_active = 0x01000000;    /* Descriptor polling active */
 124}
 125
 126/********************************************************************/
 127static void mpc512x_fec_tbd_scrub (mpc512x_fec_priv *fec)
 128{
 129        volatile FEC_TBD *pUsedTbd;
 130
 131#if (DEBUG & 0x1)
 132        printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n",
 133                fec->cleanTbdNum, fec->usedTbdIndex);
 134#endif
 135
 136        /*
 137         * process all the consumed TBDs
 138         */
 139        while (fec->cleanTbdNum < FEC_TBD_NUM) {
 140                pUsedTbd = &fec->bdBase->tbd[fec->usedTbdIndex];
 141                if (pUsedTbd->status & FEC_TBD_READY) {
 142#if (DEBUG & 0x20)
 143                        printf ("Cannot clean TBD %d, in use\n", fec->usedTbdIndex);
 144#endif
 145                        return;
 146                }
 147
 148                /*
 149                 * clean this buffer descriptor
 150                 */
 151                if (fec->usedTbdIndex == (FEC_TBD_NUM - 1))
 152                        pUsedTbd->status = FEC_TBD_WRAP;
 153                else
 154                        pUsedTbd->status = 0;
 155
 156                /*
 157                 * update some indeces for a correct handling of the TBD ring
 158                 */
 159                fec->cleanTbdNum++;
 160                fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM;
 161        }
 162}
 163
 164/********************************************************************/
 165static void mpc512x_fec_set_hwaddr (mpc512x_fec_priv *fec, char *mac)
 166{
 167        uint8 currByte;                 /* byte for which to compute the CRC */
 168        int byte;                       /* loop - counter */
 169        int bit;                        /* loop - counter */
 170        uint32 crc = 0xffffffff;        /* initial value */
 171
 172        /*
 173         * The algorithm used is the following:
 174         * we loop on each of the six bytes of the provided address,
 175         * and we compute the CRC by left-shifting the previous
 176         * value by one position, so that each bit in the current
 177         * byte of the address may contribute the calculation. If
 178         * the latter and the MSB in the CRC are different, then
 179         * the CRC value so computed is also ex-ored with the
 180         * "polynomium generator". The current byte of the address
 181         * is also shifted right by one bit at each iteration.
 182         * This is because the CRC generatore in hardware is implemented
 183         * as a shift-register with as many ex-ores as the radixes
 184         * in the polynomium. This suggests that we represent the
 185         * polynomiumm itself as a 32-bit constant.
 186         */
 187        for (byte = 0; byte < 6; byte++) {
 188                currByte = mac[byte];
 189                for (bit = 0; bit < 8; bit++) {
 190                        if ((currByte & 0x01) ^ (crc & 0x01)) {
 191                                crc >>= 1;
 192                                crc = crc ^ 0xedb88320;
 193                        } else {
 194                                crc >>= 1;
 195                        }
 196                        currByte >>= 1;
 197                }
 198        }
 199
 200        crc = crc >> 26;
 201
 202        /*
 203         * Set individual hash table register
 204         */
 205        if (crc >= 32) {
 206                fec->eth->iaddr1 = (1 << (crc - 32));
 207                fec->eth->iaddr2 = 0;
 208        } else {
 209                fec->eth->iaddr1 = 0;
 210                fec->eth->iaddr2 = (1 << crc);
 211        }
 212
 213        /*
 214         * Set physical address
 215         */
 216        fec->eth->paddr1 = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3];
 217        fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808;
 218}
 219
 220/********************************************************************/
 221static int mpc512x_fec_init (struct eth_device *dev, bd_t * bis)
 222{
 223        mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
 224
 225#if (DEBUG & 0x1)
 226        printf ("mpc512x_fec_init... Begin\n");
 227#endif
 228
 229        /* Set interrupt mask register */
 230        fec->eth->imask = 0x00000000;
 231
 232        /* Clear FEC-Lite interrupt event register(IEVENT) */
 233        fec->eth->ievent = 0xffffffff;
 234
 235        /* Set transmit fifo watermark register(X_WMRK), default = 64 */
 236        fec->eth->x_wmrk = 0x0;
 237
 238        /* Set Opcode/Pause Duration Register */
 239        fec->eth->op_pause = 0x00010020;
 240
 241        /* Frame length=1522; MII mode */
 242        fec->eth->r_cntrl = (FEC_MAX_FRAME_LEN << 16) | 0x24;
 243
 244        /* Half-duplex, heartbeat disabled */
 245        fec->eth->x_cntrl = 0x00000000;
 246
 247        /* Enable MIB counters */
 248        fec->eth->mib_control = 0x0;
 249
 250        /* Setup recv fifo start and buff size */
 251        fec->eth->r_fstart = 0x500;
 252        fec->eth->r_buff_size = FEC_BUFFER_SIZE;
 253
 254        /* Setup BD base addresses */
 255        fec->eth->r_des_start = (uint32)fec->bdBase->rbd;
 256        fec->eth->x_des_start = (uint32)fec->bdBase->tbd;
 257
 258        /* DMA Control */
 259        fec->eth->dma_control = 0xc0000000;
 260
 261        /* Enable FEC */
 262        fec->eth->ecntrl |= 0x00000006;
 263
 264        /* Initilize addresses and status words of BDs */
 265        mpc512x_fec_bd_init (fec);
 266
 267         /* Descriptor polling active */
 268        fec->eth->r_des_active = 0x01000000;
 269
 270#if (DEBUG & 0x1)
 271        printf("mpc512x_fec_init... Done \n");
 272#endif
 273        return 1;
 274}
 275
 276/********************************************************************/
 277int mpc512x_fec_init_phy (struct eth_device *dev, bd_t * bis)
 278{
 279        mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
 280        const uint8 phyAddr = CONFIG_PHY_ADDR;  /* Only one PHY */
 281        int timeout = 1;
 282        uint16 phyStatus;
 283
 284#if (DEBUG & 0x1)
 285        printf ("mpc512x_fec_init_phy... Begin\n");
 286#endif
 287
 288        /*
 289         * Clear FEC-Lite interrupt event register(IEVENT)
 290         */
 291        fec->eth->ievent = 0xffffffff;
 292
 293        /*
 294         * Set interrupt mask register
 295         */
 296        fec->eth->imask = 0x00000000;
 297
 298        if (fec->xcv_type != SEVENWIRE) {
 299                /*
 300                 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
 301                 * and do not drop the Preamble.
 302                 */
 303                fec->eth->mii_speed = (((gd->ips_clk / 1000000) / 5) + 1) << 1;
 304
 305                /*
 306                 * Reset PHY, then delay 300ns
 307                 */
 308                miiphy_write (dev->name, phyAddr, 0x0, 0x8000);
 309                udelay (1000);
 310
 311                if (fec->xcv_type == MII10) {
 312                /*
 313                 * Force 10Base-T, FDX operation
 314                 */
 315#if (DEBUG & 0x2)
 316                        printf ("Forcing 10 Mbps ethernet link... ");
 317#endif
 318                        miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
 319
 320                        miiphy_write (dev->name, phyAddr, 0x0, 0x0180);
 321
 322                        timeout = 20;
 323                        do {    /* wait for link status to go down */
 324                                udelay (10000);
 325                                if ((timeout--) == 0) {
 326#if (DEBUG & 0x2)
 327                                        printf ("hmmm, should not have waited...");
 328#endif
 329                                        break;
 330                                }
 331                                miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
 332#if (DEBUG & 0x2)
 333                                printf ("=");
 334#endif
 335                        } while ((phyStatus & 0x0004)); /* !link up */
 336
 337                        timeout = 1000;
 338                        do {    /* wait for link status to come back up */
 339                                udelay (10000);
 340                                if ((timeout--) == 0) {
 341                                        printf ("failed. Link is down.\n");
 342                                        break;
 343                                }
 344                                miiphy_read (dev->name, phyAddr, 0x1, &phyStatus);
 345#if (DEBUG & 0x2)
 346                                printf ("+");
 347#endif
 348                        } while (!(phyStatus & 0x0004)); /* !link up */
 349
 350#if (DEBUG & 0x2)
 351                        printf ("done.\n");
 352#endif
 353                } else {        /* MII100 */
 354                        /*
 355                         * Set the auto-negotiation advertisement register bits
 356                         */
 357                        miiphy_write (dev->name, phyAddr, 0x4, 0x01e1);
 358
 359                        /*
 360                         * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation
 361                         */
 362                        miiphy_write (dev->name, phyAddr, 0x0, 0x1200);
 363
 364                        /*
 365                         * Wait for AN completion
 366                         */
 367                        timeout = 2500;
 368                        do {
 369                                udelay (1000);
 370
 371                                if ((timeout--) == 0) {
 372#if (DEBUG & 0x2)
 373                                        printf ("PHY auto neg 0 failed...\n");
 374#endif
 375                                        return -1;
 376                                }
 377
 378                                if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) != 0) {
 379#if (DEBUG & 0x2)
 380                                        printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus);
 381#endif
 382                                        return -1;
 383                                }
 384                        } while (!(phyStatus & 0x0004));
 385
 386#if (DEBUG & 0x2)
 387                        printf ("PHY auto neg complete! \n");
 388#endif
 389                }
 390        }
 391
 392#if (DEBUG & 0x2)
 393        if (fec->xcv_type != SEVENWIRE)
 394                mpc512x_fec_phydump (dev->name);
 395#endif
 396
 397#if (DEBUG & 0x1)
 398        printf ("mpc512x_fec_init_phy... Done \n");
 399#endif
 400        return 1;
 401}
 402
 403/********************************************************************/
 404static void mpc512x_fec_halt (struct eth_device *dev)
 405{
 406        mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
 407        int counter = 0xffff;
 408
 409#if (DEBUG & 0x2)
 410        if (fec->xcv_type != SEVENWIRE)
 411                mpc512x_fec_phydump (dev->name);
 412#endif
 413
 414        /*
 415         * mask FEC chip interrupts
 416         */
 417        fec->eth->imask = 0;
 418
 419        /*
 420         * issue graceful stop command to the FEC transmitter if necessary
 421         */
 422        fec->eth->x_cntrl |= 0x00000001;
 423
 424        /*
 425         * wait for graceful stop to register
 426         */
 427        while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ;
 428
 429        /*
 430         * Disable the Ethernet Controller
 431         */
 432        fec->eth->ecntrl &= 0xfffffffd;
 433
 434        /*
 435         * Issue a reset command to the FEC chip
 436         */
 437        fec->eth->ecntrl |= 0x1;
 438
 439        /*
 440         * wait at least 16 clock cycles
 441         */
 442        udelay (10);
 443#if (DEBUG & 0x3)
 444        printf ("Ethernet task stopped\n");
 445#endif
 446}
 447
 448/********************************************************************/
 449
 450static int mpc512x_fec_send (struct eth_device *dev, volatile void *eth_data,
 451                int data_length)
 452{
 453        /*
 454         * This routine transmits one frame.  This routine only accepts
 455         * 6-byte Ethernet addresses.
 456         */
 457        mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
 458        volatile FEC_TBD *pTbd;
 459
 460#if (DEBUG & 0x20)
 461        printf("tbd status: 0x%04x\n", fec->tbdBase[fec->tbdIndex].status);
 462#endif
 463
 464        /*
 465         * Clear Tx BD ring at first
 466         */
 467        mpc512x_fec_tbd_scrub (fec);
 468
 469        /*
 470         * Check for valid length of data.
 471         */
 472        if ((data_length > 1500) || (data_length <= 0)) {
 473                return -1;
 474        }
 475
 476        /*
 477         * Check the number of vacant TxBDs.
 478         */
 479        if (fec->cleanTbdNum < 1) {
 480#if (DEBUG & 0x20)
 481                printf ("No available TxBDs ...\n");
 482#endif
 483                return -1;
 484        }
 485
 486        /*
 487         * Get the first TxBD to send the mac header
 488         */
 489        pTbd = &fec->bdBase->tbd[fec->tbdIndex];
 490        pTbd->dataLength = data_length;
 491        pTbd->dataPointer = (uint32)eth_data;
 492        pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
 493        fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM;
 494
 495        /* Activate transmit Buffer Descriptor polling */
 496        fec->eth->x_des_active = 0x01000000;    /* Descriptor polling active    */
 497
 498#if (DEBUG & 0x8)
 499        printf ( "+" );
 500#endif
 501
 502        fec->cleanTbdNum -= 1;
 503
 504        /*
 505         * wait until frame is sent .
 506         */
 507        while (pTbd->status & FEC_TBD_READY) {
 508                udelay (10);
 509#if (DEBUG & 0x8)
 510                printf ("TDB status = %04x\n", pTbd->status);
 511#endif
 512        }
 513
 514        return 0;
 515}
 516
 517
 518/********************************************************************/
 519static int mpc512x_fec_recv (struct eth_device *dev)
 520{
 521        /*
 522         * This command pulls one frame from the card
 523         */
 524        mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv;
 525        volatile FEC_RBD *pRbd = &fec->bdBase->rbd[fec->rbdIndex];
 526        unsigned long ievent;
 527        int frame_length = 0;
 528
 529#if (DEBUG & 0x1)
 530        printf ("mpc512x_fec_recv %d Start...\n", fec->rbdIndex);
 531#endif
 532#if (DEBUG & 0x8)
 533        printf( "-" );
 534#endif
 535
 536        /*
 537         * Check if any critical events have happened
 538         */
 539        ievent = fec->eth->ievent;
 540        fec->eth->ievent = ievent;
 541        if (ievent & 0x20060000) {
 542                /* BABT, Rx/Tx FIFO errors */
 543                mpc512x_fec_halt (dev);
 544                mpc512x_fec_init (dev, NULL);
 545                return 0;
 546        }
 547        if (ievent & 0x80000000) {
 548                /* Heartbeat error */
 549                fec->eth->x_cntrl |= 0x00000001;
 550        }
 551        if (ievent & 0x10000000) {
 552                /* Graceful stop complete */
 553                if (fec->eth->x_cntrl & 0x00000001) {
 554                        mpc512x_fec_halt (dev);
 555                        fec->eth->x_cntrl &= ~0x00000001;
 556                        mpc512x_fec_init (dev, NULL);
 557                }
 558        }
 559
 560        if (!(pRbd->status & FEC_RBD_EMPTY)) {
 561                if (!(pRbd->status & FEC_RBD_ERR) &&
 562                        ((pRbd->dataLength - 4) > 14)) {
 563
 564                        /*
 565                         * Get buffer size
 566                         */
 567                        if (pRbd->status & FEC_RBD_LAST)
 568                                frame_length = pRbd->dataLength - 4;
 569                        else
 570                                frame_length = pRbd->dataLength;
 571#if (DEBUG & 0x20)
 572                        {
 573                                int i;
 574                                printf ("recv data length 0x%08x data hdr: ",
 575                                        pRbd->dataLength);
 576                                for (i = 0; i < 14; i++)
 577                                        printf ("%x ", *((uint8*)pRbd->dataPointer + i));
 578                                printf("\n");
 579                        }
 580#endif
 581                        /*
 582                         *  Fill the buffer and pass it to upper layers
 583                         */
 584                        memcpy (&rx_buff[rx_buff_idx], (void*)pRbd->dataPointer,
 585                                frame_length - rx_buff_idx);
 586                        rx_buff_idx = frame_length;
 587
 588                        if (pRbd->status & FEC_RBD_LAST) {
 589                                NetReceive ((uchar*)rx_buff, frame_length);
 590                                rx_buff_idx = 0;
 591                        }
 592                }
 593
 594                /*
 595                 * Reset buffer descriptor as empty
 596                 */
 597                mpc512x_fec_rbd_clean (fec, pRbd);
 598        }
 599
 600        /* Try to fill Buffer Descriptors */
 601        fec->eth->r_des_active = 0x01000000;    /* Descriptor polling active */
 602        return frame_length;
 603}
 604
 605/********************************************************************/
 606int mpc512x_fec_initialize (bd_t * bis)
 607{
 608        mpc512x_fec_priv *fec;
 609        struct eth_device *dev;
 610        int i;
 611        char *tmp, *end, env_enetaddr[6];
 612        void * bd;
 613
 614        fec = (mpc512x_fec_priv *) malloc (sizeof(*fec));
 615        dev = (struct eth_device *) malloc (sizeof(*dev));
 616        memset (dev, 0, sizeof *dev);
 617
 618        fec->eth = (ethernet_regs *) MPC512X_FEC;
 619
 620# ifndef CONFIG_FEC_10MBIT
 621        fec->xcv_type = MII100;
 622# else
 623        fec->xcv_type = MII10;
 624# endif
 625        dev->priv = (void *)fec;
 626        dev->iobase = MPC512X_FEC;
 627        dev->init = mpc512x_fec_init;
 628        dev->halt = mpc512x_fec_halt;
 629        dev->send = mpc512x_fec_send;
 630        dev->recv = mpc512x_fec_recv;
 631
 632        sprintf (dev->name, "FEC ETHERNET");
 633        eth_register (dev);
 634
 635#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
 636        miiphy_register (dev->name,
 637                        fec512x_miiphy_read, fec512x_miiphy_write);
 638#endif
 639
 640        /* Clean up space FEC's MIB and FIFO RAM ...*/
 641        memset ((void *) MPC512X_FEC + 0x200, 0x00, 0x400);
 642
 643        /*
 644         * Malloc space for BDs  (must be quad word-aligned)
 645         * this pointer is lost, so cannot be freed
 646         */
 647        bd = malloc (sizeof(mpc512x_buff_descs) + 0x1f);
 648        fec->bdBase = (mpc512x_buff_descs*)((uint32)bd & 0xfffffff0);
 649        memset ((void *) bd, 0x00, sizeof(mpc512x_buff_descs) + 0x1f);
 650
 651        /*
 652         * Set interrupt mask register
 653         */
 654        fec->eth->imask = 0x00000000;
 655
 656        /*
 657         * Clear FEC-Lite interrupt event register(IEVENT)
 658         */
 659        fec->eth->ievent = 0xffffffff;
 660
 661        /*
 662         * Try to set the mac address now. The fec mac address is
 663         * a garbage after reset. When not using fec for booting
 664         * the Linux fec driver will try to work with this garbage.
 665         */
 666        tmp = getenv ("ethaddr");
 667        if (tmp) {
 668                for (i=0; i<6; i++) {
 669                        env_enetaddr[i] = tmp ? simple_strtoul (tmp, &end, 16) : 0;
 670                        if (tmp)
 671                                tmp = (*end) ? end+1 : end;
 672                }
 673                mpc512x_fec_set_hwaddr (fec, env_enetaddr);
 674                fec->eth->gaddr1 = 0x00000000;
 675                fec->eth->gaddr2 = 0x00000000;
 676        }
 677
 678        mpc512x_fec_init_phy (dev, bis);
 679
 680        return 1;
 681}
 682
 683/* MII-interface related functions */
 684/********************************************************************/
 685int fec512x_miiphy_read (char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal)
 686{
 687        ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC;
 688        uint32 reg;             /* convenient holder for the PHY register */
 689        uint32 phy;             /* convenient holder for the PHY */
 690        int timeout = 0xffff;
 691
 692        /*
 693         * reading from any PHY's register is done by properly
 694         * programming the FEC's MII data register.
 695         */
 696        reg = regAddr << FEC_MII_DATA_RA_SHIFT;
 697        phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
 698
 699        eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy | reg);
 700
 701        /*
 702         * wait for the related interrupt
 703         */
 704        while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
 705
 706        if (timeout == 0) {
 707#if (DEBUG & 0x2)
 708                printf ("Read MDIO failed...\n");
 709#endif
 710                return -1;
 711        }
 712
 713        /*
 714         * clear mii interrupt bit
 715         */
 716        eth->ievent = 0x00800000;
 717
 718        /*
 719         * it's now safe to read the PHY's register
 720         */
 721        *retVal = (uint16) eth->mii_data;
 722
 723        return 0;
 724}
 725
 726/********************************************************************/
 727int fec512x_miiphy_write (char *devname, uint8 phyAddr, uint8 regAddr, uint16 data)
 728{
 729        ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC;
 730        uint32 reg;             /* convenient holder for the PHY register */
 731        uint32 phy;             /* convenient holder for the PHY */
 732        int timeout = 0xffff;
 733
 734        reg = regAddr << FEC_MII_DATA_RA_SHIFT;
 735        phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
 736
 737        eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
 738                        FEC_MII_DATA_TA | phy | reg | data);
 739
 740        /*
 741         * wait for the MII interrupt
 742         */
 743        while ((timeout--) && (!(eth->ievent & 0x00800000))) ;
 744
 745        if (timeout == 0) {
 746#if (DEBUG & 0x2)
 747                printf ("Write MDIO failed...\n");
 748#endif
 749                return -1;
 750        }
 751
 752        /*
 753         * clear MII interrupt bit
 754         */
 755        eth->ievent = 0x00800000;
 756
 757        return 0;
 758}
 759
 760#if (DEBUG & 0x40)
 761static uint32 local_crc32 (char *string, unsigned int crc_value, int len)
 762{
 763        int i;
 764        char c;
 765        unsigned int crc, count;
 766
 767        /*
 768         * crc32 algorithm
 769         */
 770        /*
 771         * crc = 0xffffffff; * The initialized value should be 0xffffffff
 772         */
 773        crc = crc_value;
 774
 775        for (i = len; --i >= 0;) {
 776                c = *string++;
 777                for (count = 0; count < 8; count++) {
 778                        if ((c & 0x01) ^ (crc & 0x01)) {
 779                                crc >>= 1;
 780                                crc = crc ^ 0xedb88320;
 781                        } else {
 782                                crc >>= 1;
 783                        }
 784                        c >>= 1;
 785                }
 786        }
 787
 788        /*
 789         * In big endian system, do byte swaping for crc value
 790         */
 791         /**/ return crc;
 792}
 793#endif  /* DEBUG */
 794
 795#endif /* CONFIG_MPC512x_FEC */
 796