uboot/drivers/qe/uec_phy.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005 Freescale Semiconductor, Inc.
   3 *
   4 * Author: Shlomi Gridish
   5 *
   6 * Description: UCC GETH Driver -- PHY handling
   7 *              Driver for UEC on QE
   8 *              Based on 8260_io/fcc_enet.c
   9 *
  10 * This program is free software; you can redistribute  it and/or modify it
  11 * under  the terms of  the GNU General  Public License as published by the
  12 * Free Software Foundation;  either version 2 of the  License, or (at your
  13 * option) any later version.
  14 *
  15 */
  16
  17#include "common.h"
  18#include "net.h"
  19#include "malloc.h"
  20#include "asm/errno.h"
  21#include "asm/immap_qe.h"
  22#include "asm/io.h"
  23#include "qe.h"
  24#include "uccf.h"
  25#include "uec.h"
  26#include "uec_phy.h"
  27#include "miiphy.h"
  28
  29#define ugphy_printk(format, arg...)  \
  30        printf(format "\n", ## arg)
  31
  32#define ugphy_dbg(format, arg...)            \
  33        ugphy_printk(format , ## arg)
  34#define ugphy_err(format, arg...)            \
  35        ugphy_printk(format , ## arg)
  36#define ugphy_info(format, arg...)           \
  37        ugphy_printk(format , ## arg)
  38#define ugphy_warn(format, arg...)           \
  39        ugphy_printk(format , ## arg)
  40
  41#ifdef UEC_VERBOSE_DEBUG
  42#define ugphy_vdbg ugphy_dbg
  43#else
  44#define ugphy_vdbg(ugeth, fmt, args...) do { } while (0)
  45#endif /* UEC_VERBOSE_DEBUG */
  46
  47/*--------------------------------------------------------------------+
  48 * Fixed PHY (PHY-less) support for Ethernet Ports.
  49 *
  50 * Copied from arch/powerpc/cpu/ppc4xx/4xx_enet.c
  51 *--------------------------------------------------------------------*/
  52
  53/*
  54 * Some boards do not have a PHY for each ethernet port. These ports are known
  55 * as Fixed PHY (or PHY-less) ports. For such ports, set the appropriate
  56 * CONFIG_SYS_UECx_PHY_ADDR equal to CONFIG_FIXED_PHY_ADDR (an unused address)
  57 * When the drver tries to identify the PHYs, CONFIG_FIXED_PHY will be returned
  58 * and the driver will search CONFIG_SYS_FIXED_PHY_PORTS to find what network
  59 * speed and duplex should be for the port.
  60 *
  61 * Example board header configuration file:
  62 *     #define CONFIG_FIXED_PHY   0xFFFFFFFF
  63 *     #define CONFIG_SYS_FIXED_PHY_ADDR 0x1E (pick an unused phy address)
  64 *
  65 *     #define CONFIG_SYS_UEC1_PHY_ADDR CONFIG_SYS_FIXED_PHY_ADDR
  66 *     #define CONFIG_SYS_UEC2_PHY_ADDR 0x02
  67 *     #define CONFIG_SYS_UEC3_PHY_ADDR CONFIG_SYS_FIXED_PHY_ADDR
  68 *     #define CONFIG_SYS_UEC4_PHY_ADDR 0x04
  69 *
  70 *     #define CONFIG_SYS_FIXED_PHY_PORT(name,speed,duplex) \
  71 *                 {name, speed, duplex},
  72 *
  73 *     #define CONFIG_SYS_FIXED_PHY_PORTS \
  74 *                 CONFIG_SYS_FIXED_PHY_PORT("FSL UEC0",SPEED_100,DUPLEX_FULL) \
  75 *                 CONFIG_SYS_FIXED_PHY_PORT("FSL UEC2",SPEED_100,DUPLEX_HALF)
  76 */
  77
  78#ifndef CONFIG_FIXED_PHY
  79#define CONFIG_FIXED_PHY        0xFFFFFFFF /* Fixed PHY (PHY-less) */
  80#endif
  81
  82#ifndef CONFIG_SYS_FIXED_PHY_PORTS
  83#define CONFIG_SYS_FIXED_PHY_PORTS      /* default is an empty array */
  84#endif
  85
  86struct fixed_phy_port {
  87        char name[NAMESIZE];    /* ethernet port name */
  88        unsigned int speed;     /* specified speed 10,100 or 1000 */
  89        unsigned int duplex;    /* specified duplex FULL or HALF */
  90};
  91
  92static const struct fixed_phy_port fixed_phy_port[] = {
  93        CONFIG_SYS_FIXED_PHY_PORTS /* defined in board configuration file */
  94};
  95
  96/*--------------------------------------------------------------------+
  97 * BitBang MII support for ethernet ports
  98 *
  99 * Based from MPC8560ADS implementation
 100 *--------------------------------------------------------------------*/
 101/*
 102 * Example board header file to define bitbang ethernet ports:
 103 *
 104 * #define CONFIG_SYS_BITBANG_PHY_PORT(name) name,
 105 * #define CONFIG_SYS_BITBANG_PHY_PORTS CONFIG_SYS_BITBANG_PHY_PORT("FSL UEC0")
 106*/
 107#ifndef CONFIG_SYS_BITBANG_PHY_PORTS
 108#define CONFIG_SYS_BITBANG_PHY_PORTS    /* default is an empty array */
 109#endif
 110
 111#if defined(CONFIG_BITBANGMII)
 112static const char *bitbang_phy_port[] = {
 113        CONFIG_SYS_BITBANG_PHY_PORTS /* defined in board configuration file */
 114};
 115#endif /* CONFIG_BITBANGMII */
 116
 117static void config_genmii_advert (struct uec_mii_info *mii_info);
 118static void genmii_setup_forced (struct uec_mii_info *mii_info);
 119static void genmii_restart_aneg (struct uec_mii_info *mii_info);
 120static int gbit_config_aneg (struct uec_mii_info *mii_info);
 121static int genmii_config_aneg (struct uec_mii_info *mii_info);
 122static int genmii_update_link (struct uec_mii_info *mii_info);
 123static int genmii_read_status (struct uec_mii_info *mii_info);
 124u16 phy_read (struct uec_mii_info *mii_info, u16 regnum);
 125void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val);
 126
 127/* Write value to the PHY for this device to the register at regnum, */
 128/* waiting until the write is done before it returns.  All PHY */
 129/* configuration has to be done through the TSEC1 MIIM regs */
 130void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int value)
 131{
 132        uec_private_t *ugeth = (uec_private_t *) dev->priv;
 133        uec_mii_t *ug_regs;
 134        enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
 135        u32 tmp_reg;
 136
 137
 138#if defined(CONFIG_BITBANGMII)
 139        u32 i = 0;
 140
 141        for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) {
 142                if (strncmp(dev->name, bitbang_phy_port[i],
 143                        sizeof(dev->name)) == 0) {
 144                        (void)bb_miiphy_write(NULL, mii_id, regnum, value);
 145                        return;
 146                }
 147        }
 148#endif /* CONFIG_BITBANGMII */
 149
 150        ug_regs = ugeth->uec_mii_regs;
 151
 152        /* Stop the MII management read cycle */
 153        out_be32 (&ug_regs->miimcom, 0);
 154        /* Setting up the MII Mangement Address Register */
 155        tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
 156        out_be32 (&ug_regs->miimadd, tmp_reg);
 157
 158        /* Setting up the MII Mangement Control Register with the value */
 159        out_be32 (&ug_regs->miimcon, (u32) value);
 160        sync();
 161
 162        /* Wait till MII management write is complete */
 163        while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY);
 164}
 165
 166/* Reads from register regnum in the PHY for device dev, */
 167/* returning the value.  Clears miimcom first.  All PHY */
 168/* configuration has to be done through the TSEC1 MIIM regs */
 169int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum)
 170{
 171        uec_private_t *ugeth = (uec_private_t *) dev->priv;
 172        uec_mii_t *ug_regs;
 173        enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
 174        u32 tmp_reg;
 175        u16 value;
 176
 177
 178#if defined(CONFIG_BITBANGMII)
 179        u32 i = 0;
 180
 181        for (i = 0; i < ARRAY_SIZE(bitbang_phy_port); i++) {
 182                if (strncmp(dev->name, bitbang_phy_port[i],
 183                        sizeof(dev->name)) == 0) {
 184                        (void)bb_miiphy_read(NULL, mii_id, regnum, &value);
 185                        return (value);
 186                }
 187        }
 188#endif /* CONFIG_BITBANGMII */
 189
 190        ug_regs = ugeth->uec_mii_regs;
 191
 192        /* Setting up the MII Mangement Address Register */
 193        tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
 194        out_be32 (&ug_regs->miimadd, tmp_reg);
 195
 196        /* clear MII management command cycle */
 197        out_be32 (&ug_regs->miimcom, 0);
 198        sync();
 199
 200        /* Perform an MII management read cycle */
 201        out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE);
 202
 203        /* Wait till MII management write is complete */
 204        while ((in_be32 (&ug_regs->miimind)) &
 205               (MIIMIND_NOT_VALID | MIIMIND_BUSY));
 206
 207        /* Read MII management status  */
 208        value = (u16) in_be32 (&ug_regs->miimstat);
 209        if (value == 0xffff)
 210                ugphy_vdbg
 211                        ("read wrong value : mii_id %d,mii_reg %d, base %08x",
 212                         mii_id, mii_reg, (u32) & (ug_regs->miimcfg));
 213
 214        return (value);
 215}
 216
 217void mii_clear_phy_interrupt (struct uec_mii_info *mii_info)
 218{
 219        if (mii_info->phyinfo->ack_interrupt)
 220                mii_info->phyinfo->ack_interrupt (mii_info);
 221}
 222
 223void mii_configure_phy_interrupt (struct uec_mii_info *mii_info,
 224                                  u32 interrupts)
 225{
 226        mii_info->interrupts = interrupts;
 227        if (mii_info->phyinfo->config_intr)
 228                mii_info->phyinfo->config_intr (mii_info);
 229}
 230
 231/* Writes MII_ADVERTISE with the appropriate values, after
 232 * sanitizing advertise to make sure only supported features
 233 * are advertised
 234 */
 235static void config_genmii_advert (struct uec_mii_info *mii_info)
 236{
 237        u32 advertise;
 238        u16 adv;
 239
 240        /* Only allow advertising what this PHY supports */
 241        mii_info->advertising &= mii_info->phyinfo->features;
 242        advertise = mii_info->advertising;
 243
 244        /* Setup standard advertisement */
 245        adv = phy_read (mii_info, PHY_ANAR);
 246        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
 247        if (advertise & ADVERTISED_10baseT_Half)
 248                adv |= ADVERTISE_10HALF;
 249        if (advertise & ADVERTISED_10baseT_Full)
 250                adv |= ADVERTISE_10FULL;
 251        if (advertise & ADVERTISED_100baseT_Half)
 252                adv |= ADVERTISE_100HALF;
 253        if (advertise & ADVERTISED_100baseT_Full)
 254                adv |= ADVERTISE_100FULL;
 255        phy_write (mii_info, PHY_ANAR, adv);
 256}
 257
 258static void genmii_setup_forced (struct uec_mii_info *mii_info)
 259{
 260        u16 ctrl;
 261        u32 features = mii_info->phyinfo->features;
 262
 263        ctrl = phy_read (mii_info, PHY_BMCR);
 264
 265        ctrl &= ~(PHY_BMCR_DPLX | PHY_BMCR_100_MBPS |
 266                  PHY_BMCR_1000_MBPS | PHY_BMCR_AUTON);
 267        ctrl |= PHY_BMCR_RESET;
 268
 269        switch (mii_info->speed) {
 270        case SPEED_1000:
 271                if (features & (SUPPORTED_1000baseT_Half
 272                                | SUPPORTED_1000baseT_Full)) {
 273                        ctrl |= PHY_BMCR_1000_MBPS;
 274                        break;
 275                }
 276                mii_info->speed = SPEED_100;
 277        case SPEED_100:
 278                if (features & (SUPPORTED_100baseT_Half
 279                                | SUPPORTED_100baseT_Full)) {
 280                        ctrl |= PHY_BMCR_100_MBPS;
 281                        break;
 282                }
 283                mii_info->speed = SPEED_10;
 284        case SPEED_10:
 285                if (features & (SUPPORTED_10baseT_Half
 286                                | SUPPORTED_10baseT_Full))
 287                        break;
 288        default:                /* Unsupported speed! */
 289                ugphy_err ("%s: Bad speed!", mii_info->dev->name);
 290                break;
 291        }
 292
 293        phy_write (mii_info, PHY_BMCR, ctrl);
 294}
 295
 296/* Enable and Restart Autonegotiation */
 297static void genmii_restart_aneg (struct uec_mii_info *mii_info)
 298{
 299        u16 ctl;
 300
 301        ctl = phy_read (mii_info, PHY_BMCR);
 302        ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
 303        phy_write (mii_info, PHY_BMCR, ctl);
 304}
 305
 306static int gbit_config_aneg (struct uec_mii_info *mii_info)
 307{
 308        u16 adv;
 309        u32 advertise;
 310
 311        if (mii_info->autoneg) {
 312                /* Configure the ADVERTISE register */
 313                config_genmii_advert (mii_info);
 314                advertise = mii_info->advertising;
 315
 316                adv = phy_read (mii_info, MII_1000BASETCONTROL);
 317                adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
 318                         MII_1000BASETCONTROL_HALFDUPLEXCAP);
 319                if (advertise & SUPPORTED_1000baseT_Half)
 320                        adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
 321                if (advertise & SUPPORTED_1000baseT_Full)
 322                        adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
 323                phy_write (mii_info, MII_1000BASETCONTROL, adv);
 324
 325                /* Start/Restart aneg */
 326                genmii_restart_aneg (mii_info);
 327        } else
 328                genmii_setup_forced (mii_info);
 329
 330        return 0;
 331}
 332
 333static int marvell_config_aneg (struct uec_mii_info *mii_info)
 334{
 335        /* The Marvell PHY has an errata which requires
 336         * that certain registers get written in order
 337         * to restart autonegotiation */
 338        phy_write (mii_info, PHY_BMCR, PHY_BMCR_RESET);
 339
 340        phy_write (mii_info, 0x1d, 0x1f);
 341        phy_write (mii_info, 0x1e, 0x200c);
 342        phy_write (mii_info, 0x1d, 0x5);
 343        phy_write (mii_info, 0x1e, 0);
 344        phy_write (mii_info, 0x1e, 0x100);
 345
 346        gbit_config_aneg (mii_info);
 347
 348        return 0;
 349}
 350
 351static int genmii_config_aneg (struct uec_mii_info *mii_info)
 352{
 353        if (mii_info->autoneg) {
 354                config_genmii_advert (mii_info);
 355                genmii_restart_aneg (mii_info);
 356        } else
 357                genmii_setup_forced (mii_info);
 358
 359        return 0;
 360}
 361
 362static int genmii_update_link (struct uec_mii_info *mii_info)
 363{
 364        u16 status;
 365
 366        /* Status is read once to clear old link state */
 367        phy_read (mii_info, PHY_BMSR);
 368
 369        /*
 370         * Wait if the link is up, and autonegotiation is in progress
 371         * (ie - we're capable and it's not done)
 372         */
 373        status = phy_read(mii_info, PHY_BMSR);
 374        if ((status & PHY_BMSR_LS) && (status & PHY_BMSR_AUTN_ABLE)
 375            && !(status & PHY_BMSR_AUTN_COMP)) {
 376                int i = 0;
 377
 378                while (!(status & PHY_BMSR_AUTN_COMP)) {
 379                        /*
 380                         * Timeout reached ?
 381                         */
 382                        if (i > UGETH_AN_TIMEOUT) {
 383                                mii_info->link = 0;
 384                                return 0;
 385                        }
 386
 387                        i++;
 388                        udelay(1000);   /* 1 ms */
 389                        status = phy_read(mii_info, PHY_BMSR);
 390                }
 391                mii_info->link = 1;
 392                udelay(500000); /* another 500 ms (results in faster booting) */
 393        } else {
 394                if (status & PHY_BMSR_LS)
 395                        mii_info->link = 1;
 396                else
 397                        mii_info->link = 0;
 398        }
 399
 400        return 0;
 401}
 402
 403static int genmii_read_status (struct uec_mii_info *mii_info)
 404{
 405        u16 status;
 406        int err;
 407
 408        /* Update the link, but return if there
 409         * was an error */
 410        err = genmii_update_link (mii_info);
 411        if (err)
 412                return err;
 413
 414        if (mii_info->autoneg) {
 415                status = phy_read(mii_info, MII_1000BASETSTATUS);
 416
 417                if (status & (LPA_1000FULL | LPA_1000HALF)) {
 418                        mii_info->speed = SPEED_1000;
 419                        if (status & LPA_1000FULL)
 420                                mii_info->duplex = DUPLEX_FULL;
 421                        else
 422                                mii_info->duplex = DUPLEX_HALF;
 423                } else {
 424                        status = phy_read(mii_info, PHY_ANLPAR);
 425
 426                        if (status & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD))
 427                                mii_info->duplex = DUPLEX_FULL;
 428                        else
 429                                mii_info->duplex = DUPLEX_HALF;
 430                        if (status & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX))
 431                                mii_info->speed = SPEED_100;
 432                        else
 433                                mii_info->speed = SPEED_10;
 434                }
 435                mii_info->pause = 0;
 436        }
 437        /* On non-aneg, we assume what we put in BMCR is the speed,
 438         * though magic-aneg shouldn't prevent this case from occurring
 439         */
 440
 441        return 0;
 442}
 443
 444static int bcm_init(struct uec_mii_info *mii_info)
 445{
 446        struct eth_device *edev = mii_info->dev;
 447        uec_private_t *uec = edev->priv;
 448
 449        gbit_config_aneg(mii_info);
 450
 451        if ((uec->uec_info->enet_interface_type == RGMII_RXID) &&
 452           (uec->uec_info->speed == 1000)) {
 453                u16 val;
 454                int cnt = 50;
 455
 456                /* Wait for aneg to complete. */
 457                do
 458                        val = phy_read(mii_info, PHY_BMSR);
 459                while (--cnt && !(val & PHY_BMSR_AUTN_COMP));
 460
 461                /* Set RDX clk delay. */
 462                phy_write(mii_info, 0x18, 0x7 | (7 << 12));
 463
 464                val = phy_read(mii_info, 0x18);
 465                /* Set RDX-RXC skew. */
 466                val |= (1 << 8);
 467                val |= (7 | (7 << 12));
 468                /* Write bits 14:0. */
 469                val |= (1 << 15);
 470                phy_write(mii_info, 0x18, val);
 471        }
 472
 473         return 0;
 474}
 475
 476static int marvell_init(struct uec_mii_info *mii_info)
 477{
 478        struct eth_device *edev = mii_info->dev;
 479        uec_private_t *uec = edev->priv;
 480        enum enet_interface_type iface = uec->uec_info->enet_interface_type;
 481        int     speed = uec->uec_info->speed;
 482
 483        if ((speed == 1000) &&
 484           (iface == RGMII_ID ||
 485            iface == RGMII_RXID ||
 486            iface == RGMII_TXID)) {
 487                int temp;
 488
 489                temp = phy_read(mii_info, MII_M1111_PHY_EXT_CR);
 490                if (iface == RGMII_ID) {
 491                        temp |= MII_M1111_RX_DELAY | MII_M1111_TX_DELAY;
 492                } else if (iface == RGMII_RXID) {
 493                        temp &= ~MII_M1111_TX_DELAY;
 494                        temp |= MII_M1111_RX_DELAY;
 495                } else if (iface == RGMII_TXID) {
 496                        temp &= ~MII_M1111_RX_DELAY;
 497                        temp |= MII_M1111_TX_DELAY;
 498                }
 499                phy_write(mii_info, MII_M1111_PHY_EXT_CR, temp);
 500
 501                temp = phy_read(mii_info, MII_M1111_PHY_EXT_SR);
 502                temp &= ~MII_M1111_HWCFG_MODE_MASK;
 503                temp |= MII_M1111_HWCFG_MODE_RGMII;
 504                phy_write(mii_info, MII_M1111_PHY_EXT_SR, temp);
 505
 506                phy_write(mii_info, PHY_BMCR, PHY_BMCR_RESET);
 507        }
 508
 509        return 0;
 510}
 511
 512static int marvell_read_status (struct uec_mii_info *mii_info)
 513{
 514        u16 status;
 515        int err;
 516
 517        /* Update the link, but return if there
 518         * was an error */
 519        err = genmii_update_link (mii_info);
 520        if (err)
 521                return err;
 522
 523        /* If the link is up, read the speed and duplex */
 524        /* If we aren't autonegotiating, assume speeds
 525         * are as set */
 526        if (mii_info->autoneg && mii_info->link) {
 527                int speed;
 528
 529                status = phy_read (mii_info, MII_M1011_PHY_SPEC_STATUS);
 530
 531                /* Get the duplexity */
 532                if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
 533                        mii_info->duplex = DUPLEX_FULL;
 534                else
 535                        mii_info->duplex = DUPLEX_HALF;
 536
 537                /* Get the speed */
 538                speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
 539                switch (speed) {
 540                case MII_M1011_PHY_SPEC_STATUS_1000:
 541                        mii_info->speed = SPEED_1000;
 542                        break;
 543                case MII_M1011_PHY_SPEC_STATUS_100:
 544                        mii_info->speed = SPEED_100;
 545                        break;
 546                default:
 547                        mii_info->speed = SPEED_10;
 548                        break;
 549                }
 550                mii_info->pause = 0;
 551        }
 552
 553        return 0;
 554}
 555
 556static int marvell_ack_interrupt (struct uec_mii_info *mii_info)
 557{
 558        /* Clear the interrupts by reading the reg */
 559        phy_read (mii_info, MII_M1011_IEVENT);
 560
 561        return 0;
 562}
 563
 564static int marvell_config_intr (struct uec_mii_info *mii_info)
 565{
 566        if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
 567                phy_write (mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
 568        else
 569                phy_write (mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
 570
 571        return 0;
 572}
 573
 574static int dm9161_init (struct uec_mii_info *mii_info)
 575{
 576        /* Reset the PHY */
 577        phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) |
 578                   PHY_BMCR_RESET);
 579        /* PHY and MAC connect */
 580        phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) &
 581                   ~PHY_BMCR_ISO);
 582
 583        phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT);
 584
 585        config_genmii_advert (mii_info);
 586        /* Start/restart aneg */
 587        genmii_config_aneg (mii_info);
 588
 589        return 0;
 590}
 591
 592static int dm9161_config_aneg (struct uec_mii_info *mii_info)
 593{
 594        return 0;
 595}
 596
 597static int dm9161_read_status (struct uec_mii_info *mii_info)
 598{
 599        u16 status;
 600        int err;
 601
 602        /* Update the link, but return if there was an error */
 603        err = genmii_update_link (mii_info);
 604        if (err)
 605                return err;
 606        /* If the link is up, read the speed and duplex
 607           If we aren't autonegotiating assume speeds are as set */
 608        if (mii_info->autoneg && mii_info->link) {
 609                status = phy_read (mii_info, MII_DM9161_SCSR);
 610                if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
 611                        mii_info->speed = SPEED_100;
 612                else
 613                        mii_info->speed = SPEED_10;
 614
 615                if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
 616                        mii_info->duplex = DUPLEX_FULL;
 617                else
 618                        mii_info->duplex = DUPLEX_HALF;
 619        }
 620
 621        return 0;
 622}
 623
 624static int dm9161_ack_interrupt (struct uec_mii_info *mii_info)
 625{
 626        /* Clear the interrupt by reading the reg */
 627        phy_read (mii_info, MII_DM9161_INTR);
 628
 629        return 0;
 630}
 631
 632static int dm9161_config_intr (struct uec_mii_info *mii_info)
 633{
 634        if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
 635                phy_write (mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
 636        else
 637                phy_write (mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
 638
 639        return 0;
 640}
 641
 642static void dm9161_close (struct uec_mii_info *mii_info)
 643{
 644}
 645
 646static int fixed_phy_aneg (struct uec_mii_info *mii_info)
 647{
 648        mii_info->autoneg = 0; /* Turn off auto negotiation for fixed phy */
 649        return 0;
 650}
 651
 652static int fixed_phy_read_status (struct uec_mii_info *mii_info)
 653{
 654        int i = 0;
 655
 656        for (i = 0; i < ARRAY_SIZE(fixed_phy_port); i++) {
 657                if (strncmp(mii_info->dev->name, fixed_phy_port[i].name,
 658                                strlen(mii_info->dev->name)) == 0) {
 659                        mii_info->speed = fixed_phy_port[i].speed;
 660                        mii_info->duplex = fixed_phy_port[i].duplex;
 661                        mii_info->link = 1; /* Link is always UP */
 662                        mii_info->pause = 0;
 663                        break;
 664                }
 665        }
 666        return 0;
 667}
 668
 669static int smsc_config_aneg (struct uec_mii_info *mii_info)
 670{
 671        return 0;
 672}
 673
 674static int smsc_read_status (struct uec_mii_info *mii_info)
 675{
 676        u16 status;
 677        int err;
 678
 679        /* Update the link, but return if there
 680         * was an error */
 681        err = genmii_update_link (mii_info);
 682        if (err)
 683                return err;
 684
 685        /* If the link is up, read the speed and duplex */
 686        /* If we aren't autonegotiating, assume speeds
 687         * are as set */
 688        if (mii_info->autoneg && mii_info->link) {
 689                int     val;
 690
 691                status = phy_read (mii_info, 0x1f);
 692                val = (status & 0x1c) >> 2;
 693
 694                switch (val) {
 695                        case 1:
 696                                mii_info->duplex = DUPLEX_HALF;
 697                                mii_info->speed = SPEED_10;
 698                                break;
 699                        case 5:
 700                                mii_info->duplex = DUPLEX_FULL;
 701                                mii_info->speed = SPEED_10;
 702                                break;
 703                        case 2:
 704                                mii_info->duplex = DUPLEX_HALF;
 705                                mii_info->speed = SPEED_100;
 706                                break;
 707                        case 6:
 708                                mii_info->duplex = DUPLEX_FULL;
 709                                mii_info->speed = SPEED_100;
 710                                break;
 711                }
 712                mii_info->pause = 0;
 713        }
 714
 715        return 0;
 716}
 717
 718static struct phy_info phy_info_dm9161 = {
 719        .phy_id = 0x0181b880,
 720        .phy_id_mask = 0x0ffffff0,
 721        .name = "Davicom DM9161E",
 722        .init = dm9161_init,
 723        .config_aneg = dm9161_config_aneg,
 724        .read_status = dm9161_read_status,
 725        .close = dm9161_close,
 726};
 727
 728static struct phy_info phy_info_dm9161a = {
 729        .phy_id = 0x0181b8a0,
 730        .phy_id_mask = 0x0ffffff0,
 731        .name = "Davicom DM9161A",
 732        .features = MII_BASIC_FEATURES,
 733        .init = dm9161_init,
 734        .config_aneg = dm9161_config_aneg,
 735        .read_status = dm9161_read_status,
 736        .ack_interrupt = dm9161_ack_interrupt,
 737        .config_intr = dm9161_config_intr,
 738        .close = dm9161_close,
 739};
 740
 741static struct phy_info phy_info_marvell = {
 742        .phy_id = 0x01410c00,
 743        .phy_id_mask = 0xffffff00,
 744        .name = "Marvell 88E11x1",
 745        .features = MII_GBIT_FEATURES,
 746        .init = &marvell_init,
 747        .config_aneg = &marvell_config_aneg,
 748        .read_status = &marvell_read_status,
 749        .ack_interrupt = &marvell_ack_interrupt,
 750        .config_intr = &marvell_config_intr,
 751};
 752
 753static struct phy_info phy_info_bcm5481 = {
 754        .phy_id = 0x0143bca0,
 755        .phy_id_mask = 0xffffff0,
 756        .name = "Broadcom 5481",
 757        .features = MII_GBIT_FEATURES,
 758        .read_status = genmii_read_status,
 759        .init = bcm_init,
 760};
 761
 762static struct phy_info phy_info_fixedphy = {
 763        .phy_id = CONFIG_FIXED_PHY,
 764        .phy_id_mask = CONFIG_FIXED_PHY,
 765        .name = "Fixed PHY",
 766        .config_aneg = fixed_phy_aneg,
 767        .read_status = fixed_phy_read_status,
 768};
 769
 770static struct phy_info phy_info_smsclan8700 = {
 771        .phy_id = 0x0007c0c0,
 772        .phy_id_mask = 0xfffffff0,
 773        .name = "SMSC LAN8700",
 774        .features = MII_BASIC_FEATURES,
 775        .config_aneg = smsc_config_aneg,
 776        .read_status = smsc_read_status,
 777};
 778
 779static struct phy_info phy_info_genmii = {
 780        .phy_id = 0x00000000,
 781        .phy_id_mask = 0x00000000,
 782        .name = "Generic MII",
 783        .features = MII_BASIC_FEATURES,
 784        .config_aneg = genmii_config_aneg,
 785        .read_status = genmii_read_status,
 786};
 787
 788static struct phy_info *phy_info[] = {
 789        &phy_info_dm9161,
 790        &phy_info_dm9161a,
 791        &phy_info_marvell,
 792        &phy_info_bcm5481,
 793        &phy_info_smsclan8700,
 794        &phy_info_fixedphy,
 795        &phy_info_genmii,
 796        NULL
 797};
 798
 799u16 phy_read (struct uec_mii_info *mii_info, u16 regnum)
 800{
 801        return mii_info->mdio_read (mii_info->dev, mii_info->mii_id, regnum);
 802}
 803
 804void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val)
 805{
 806        mii_info->mdio_write (mii_info->dev, mii_info->mii_id, regnum, val);
 807}
 808
 809/* Use the PHY ID registers to determine what type of PHY is attached
 810 * to device dev.  return a struct phy_info structure describing that PHY
 811 */
 812struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info)
 813{
 814        u16 phy_reg;
 815        u32 phy_ID;
 816        int i;
 817        struct phy_info *theInfo = NULL;
 818
 819        /* Grab the bits from PHYIR1, and put them in the upper half */
 820        phy_reg = phy_read (mii_info, PHY_PHYIDR1);
 821        phy_ID = (phy_reg & 0xffff) << 16;
 822
 823        /* Grab the bits from PHYIR2, and put them in the lower half */
 824        phy_reg = phy_read (mii_info, PHY_PHYIDR2);
 825        phy_ID |= (phy_reg & 0xffff);
 826
 827        /* loop through all the known PHY types, and find one that */
 828        /* matches the ID we read from the PHY. */
 829        for (i = 0; phy_info[i]; i++)
 830                if (phy_info[i]->phy_id ==
 831                    (phy_ID & phy_info[i]->phy_id_mask)) {
 832                        theInfo = phy_info[i];
 833                        break;
 834                }
 835
 836        /* This shouldn't happen, as we have generic PHY support */
 837        if (theInfo == NULL) {
 838                ugphy_info ("UEC: PHY id %x is not supported!", phy_ID);
 839                return NULL;
 840        } else {
 841                ugphy_info ("UEC: PHY is %s (%x)", theInfo->name, phy_ID);
 842        }
 843
 844        return theInfo;
 845}
 846
 847void marvell_phy_interface_mode (struct eth_device *dev,
 848                                 enet_interface_type_e type,
 849                                 int speed
 850                                )
 851{
 852        uec_private_t *uec = (uec_private_t *) dev->priv;
 853        struct uec_mii_info *mii_info;
 854        u16 status;
 855
 856        if (!uec->mii_info) {
 857                printf ("%s: the PHY not initialized\n", __FUNCTION__);
 858                return;
 859        }
 860        mii_info = uec->mii_info;
 861
 862        if (type == RGMII) {
 863                if (speed == 100) {
 864                        phy_write (mii_info, 0x00, 0x9140);
 865                        phy_write (mii_info, 0x1d, 0x001f);
 866                        phy_write (mii_info, 0x1e, 0x200c);
 867                        phy_write (mii_info, 0x1d, 0x0005);
 868                        phy_write (mii_info, 0x1e, 0x0000);
 869                        phy_write (mii_info, 0x1e, 0x0100);
 870                        phy_write (mii_info, 0x09, 0x0e00);
 871                        phy_write (mii_info, 0x04, 0x01e1);
 872                        phy_write (mii_info, 0x00, 0x9140);
 873                        phy_write (mii_info, 0x00, 0x1000);
 874                        udelay (100000);
 875                        phy_write (mii_info, 0x00, 0x2900);
 876                        phy_write (mii_info, 0x14, 0x0cd2);
 877                        phy_write (mii_info, 0x00, 0xa100);
 878                        phy_write (mii_info, 0x09, 0x0000);
 879                        phy_write (mii_info, 0x1b, 0x800b);
 880                        phy_write (mii_info, 0x04, 0x05e1);
 881                        phy_write (mii_info, 0x00, 0xa100);
 882                        phy_write (mii_info, 0x00, 0x2100);
 883                        udelay (1000000);
 884                } else if (speed == 10) {
 885                        phy_write (mii_info, 0x14, 0x8e40);
 886                        phy_write (mii_info, 0x1b, 0x800b);
 887                        phy_write (mii_info, 0x14, 0x0c82);
 888                        phy_write (mii_info, 0x00, 0x8100);
 889                        udelay (1000000);
 890                }
 891        }
 892
 893        /* handle 88e1111 rev.B2 erratum 5.6 */
 894        if (mii_info->autoneg) {
 895                status = phy_read (mii_info, PHY_BMCR);
 896                phy_write (mii_info, PHY_BMCR, status | PHY_BMCR_AUTON);
 897        }
 898        /* now the B2 will correctly report autoneg completion status */
 899}
 900
 901void change_phy_interface_mode (struct eth_device *dev,
 902                                enet_interface_type_e type, int speed)
 903{
 904#ifdef CONFIG_PHY_MODE_NEED_CHANGE
 905        marvell_phy_interface_mode (dev, type, speed);
 906#endif
 907}
 908