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