linux/drivers/net/sungem_phy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * PHY drivers for the sungem ethernet driver.
   4 *
   5 * This file could be shared with other drivers.
   6 *
   7 * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
   8 *
   9 * TODO:
  10 *  - Add support for PHYs that provide an IRQ line
  11 *  - Eventually moved the entire polling state machine in
  12 *    there (out of the eth driver), so that it can easily be
  13 *    skipped on PHYs that implement it in hardware.
  14 *  - On LXT971 & BCM5201, Apple uses some chip specific regs
  15 *    to read the link status. Figure out why and if it makes
  16 *    sense to do the same (magic aneg ?)
  17 *  - Apple has some additional power management code for some
  18 *    Broadcom PHYs that they "hide" from the OpenSource version
  19 *    of darwin, still need to reverse engineer that
  20 */
  21
  22
  23#include <linux/module.h>
  24
  25#include <linux/kernel.h>
  26#include <linux/types.h>
  27#include <linux/netdevice.h>
  28#include <linux/etherdevice.h>
  29#include <linux/mii.h>
  30#include <linux/ethtool.h>
  31#include <linux/delay.h>
  32
  33#ifdef CONFIG_PPC_PMAC
  34#include <asm/prom.h>
  35#endif
  36
  37#include <linux/sungem_phy.h>
  38
  39/* Link modes of the BCM5400 PHY */
  40static const int phy_BCM5400_link_table[8][3] = {
  41        { 0, 0, 0 },    /* No link */
  42        { 0, 0, 0 },    /* 10BT Half Duplex */
  43        { 1, 0, 0 },    /* 10BT Full Duplex */
  44        { 0, 1, 0 },    /* 100BT Half Duplex */
  45        { 0, 1, 0 },    /* 100BT Half Duplex */
  46        { 1, 1, 0 },    /* 100BT Full Duplex*/
  47        { 1, 0, 1 },    /* 1000BT */
  48        { 1, 0, 1 },    /* 1000BT */
  49};
  50
  51static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
  52{
  53        return phy->mdio_read(phy->dev, id, reg);
  54}
  55
  56static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
  57{
  58        phy->mdio_write(phy->dev, id, reg, val);
  59}
  60
  61static inline int sungem_phy_read(struct mii_phy* phy, int reg)
  62{
  63        return phy->mdio_read(phy->dev, phy->mii_id, reg);
  64}
  65
  66static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
  67{
  68        phy->mdio_write(phy->dev, phy->mii_id, reg, val);
  69}
  70
  71static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
  72{
  73        u16 val;
  74        int limit = 10000;
  75
  76        val = __sungem_phy_read(phy, phy_id, MII_BMCR);
  77        val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
  78        val |= BMCR_RESET;
  79        __sungem_phy_write(phy, phy_id, MII_BMCR, val);
  80
  81        udelay(100);
  82
  83        while (--limit) {
  84                val = __sungem_phy_read(phy, phy_id, MII_BMCR);
  85                if ((val & BMCR_RESET) == 0)
  86                        break;
  87                udelay(10);
  88        }
  89        if ((val & BMCR_ISOLATE) && limit > 0)
  90                __sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
  91
  92        return limit <= 0;
  93}
  94
  95static int bcm5201_init(struct mii_phy* phy)
  96{
  97        u16 data;
  98
  99        data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
 100        data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
 101        sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
 102
 103        sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
 104
 105        return 0;
 106}
 107
 108static int bcm5201_suspend(struct mii_phy* phy)
 109{
 110        sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
 111        sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
 112
 113        return 0;
 114}
 115
 116static int bcm5221_init(struct mii_phy* phy)
 117{
 118        u16 data;
 119
 120        data = sungem_phy_read(phy, MII_BCM5221_TEST);
 121        sungem_phy_write(phy, MII_BCM5221_TEST,
 122                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 123
 124        data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
 125        sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
 126                data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
 127
 128        data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
 129        sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
 130                data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
 131
 132        data = sungem_phy_read(phy, MII_BCM5221_TEST);
 133        sungem_phy_write(phy, MII_BCM5221_TEST,
 134                data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
 135
 136        return 0;
 137}
 138
 139static int bcm5221_suspend(struct mii_phy* phy)
 140{
 141        u16 data;
 142
 143        data = sungem_phy_read(phy, MII_BCM5221_TEST);
 144        sungem_phy_write(phy, MII_BCM5221_TEST,
 145                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 146
 147        data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
 148        sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
 149                  data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
 150
 151        return 0;
 152}
 153
 154static int bcm5241_init(struct mii_phy* phy)
 155{
 156        u16 data;
 157
 158        data = sungem_phy_read(phy, MII_BCM5221_TEST);
 159        sungem_phy_write(phy, MII_BCM5221_TEST,
 160                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 161
 162        data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
 163        sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
 164                data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
 165
 166        data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
 167        sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
 168                data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
 169
 170        data = sungem_phy_read(phy, MII_BCM5221_TEST);
 171        sungem_phy_write(phy, MII_BCM5221_TEST,
 172                data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
 173
 174        return 0;
 175}
 176
 177static int bcm5241_suspend(struct mii_phy* phy)
 178{
 179        u16 data;
 180
 181        data = sungem_phy_read(phy, MII_BCM5221_TEST);
 182        sungem_phy_write(phy, MII_BCM5221_TEST,
 183                data | MII_BCM5221_TEST_ENABLE_SHADOWS);
 184
 185        data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
 186        sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
 187                  data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
 188
 189        return 0;
 190}
 191
 192static int bcm5400_init(struct mii_phy* phy)
 193{
 194        u16 data;
 195
 196        /* Configure for gigabit full duplex */
 197        data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
 198        data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
 199        sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
 200
 201        data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
 202        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
 203        sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
 204
 205        udelay(100);
 206
 207        /* Reset and configure cascaded 10/100 PHY */
 208        (void)reset_one_mii_phy(phy, 0x1f);
 209
 210        data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
 211        data |= MII_BCM5201_MULTIPHY_SERIALMODE;
 212        __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
 213
 214        data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
 215        data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
 216        sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
 217
 218        return 0;
 219}
 220
 221static int bcm5400_suspend(struct mii_phy* phy)
 222{
 223#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
 224        sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
 225#endif
 226        return 0;
 227}
 228
 229static int bcm5401_init(struct mii_phy* phy)
 230{
 231        u16 data;
 232        int rev;
 233
 234        rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
 235        if (rev == 0 || rev == 3) {
 236                /* Some revisions of 5401 appear to need this
 237                 * initialisation sequence to disable, according
 238                 * to OF, "tap power management"
 239                 *
 240                 * WARNING ! OF and Darwin don't agree on the
 241                 * register addresses. OF seem to interpret the
 242                 * register numbers below as decimal
 243                 *
 244                 * Note: This should (and does) match tg3_init_5401phy_dsp
 245                 *       in the tg3.c driver. -DaveM
 246                 */
 247                sungem_phy_write(phy, 0x18, 0x0c20);
 248                sungem_phy_write(phy, 0x17, 0x0012);
 249                sungem_phy_write(phy, 0x15, 0x1804);
 250                sungem_phy_write(phy, 0x17, 0x0013);
 251                sungem_phy_write(phy, 0x15, 0x1204);
 252                sungem_phy_write(phy, 0x17, 0x8006);
 253                sungem_phy_write(phy, 0x15, 0x0132);
 254                sungem_phy_write(phy, 0x17, 0x8006);
 255                sungem_phy_write(phy, 0x15, 0x0232);
 256                sungem_phy_write(phy, 0x17, 0x201f);
 257                sungem_phy_write(phy, 0x15, 0x0a20);
 258        }
 259
 260        /* Configure for gigabit full duplex */
 261        data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
 262        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
 263        sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
 264
 265        udelay(10);
 266
 267        /* Reset and configure cascaded 10/100 PHY */
 268        (void)reset_one_mii_phy(phy, 0x1f);
 269
 270        data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
 271        data |= MII_BCM5201_MULTIPHY_SERIALMODE;
 272        __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
 273
 274        return 0;
 275}
 276
 277static int bcm5401_suspend(struct mii_phy* phy)
 278{
 279#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
 280        sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
 281#endif
 282        return 0;
 283}
 284
 285static int bcm5411_init(struct mii_phy* phy)
 286{
 287        u16 data;
 288
 289        /* Here's some more Apple black magic to setup
 290         * some voltage stuffs.
 291         */
 292        sungem_phy_write(phy, 0x1c, 0x8c23);
 293        sungem_phy_write(phy, 0x1c, 0x8ca3);
 294        sungem_phy_write(phy, 0x1c, 0x8c23);
 295
 296        /* Here, Apple seems to want to reset it, do
 297         * it as well
 298         */
 299        sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
 300        sungem_phy_write(phy, MII_BMCR, 0x1340);
 301
 302        data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
 303        data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
 304        sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
 305
 306        udelay(10);
 307
 308        /* Reset and configure cascaded 10/100 PHY */
 309        (void)reset_one_mii_phy(phy, 0x1f);
 310
 311        return 0;
 312}
 313
 314static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
 315{
 316        u16 ctl, adv;
 317
 318        phy->autoneg = 1;
 319        phy->speed = SPEED_10;
 320        phy->duplex = DUPLEX_HALF;
 321        phy->pause = 0;
 322        phy->advertising = advertise;
 323
 324        /* Setup standard advertise */
 325        adv = sungem_phy_read(phy, MII_ADVERTISE);
 326        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
 327        if (advertise & ADVERTISED_10baseT_Half)
 328                adv |= ADVERTISE_10HALF;
 329        if (advertise & ADVERTISED_10baseT_Full)
 330                adv |= ADVERTISE_10FULL;
 331        if (advertise & ADVERTISED_100baseT_Half)
 332                adv |= ADVERTISE_100HALF;
 333        if (advertise & ADVERTISED_100baseT_Full)
 334                adv |= ADVERTISE_100FULL;
 335        sungem_phy_write(phy, MII_ADVERTISE, adv);
 336
 337        /* Start/Restart aneg */
 338        ctl = sungem_phy_read(phy, MII_BMCR);
 339        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
 340        sungem_phy_write(phy, MII_BMCR, ctl);
 341
 342        return 0;
 343}
 344
 345static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
 346{
 347        u16 ctl;
 348
 349        phy->autoneg = 0;
 350        phy->speed = speed;
 351        phy->duplex = fd;
 352        phy->pause = 0;
 353
 354        ctl = sungem_phy_read(phy, MII_BMCR);
 355        ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
 356
 357        /* First reset the PHY */
 358        sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
 359
 360        /* Select speed & duplex */
 361        switch(speed) {
 362        case SPEED_10:
 363                break;
 364        case SPEED_100:
 365                ctl |= BMCR_SPEED100;
 366                break;
 367        case SPEED_1000:
 368        default:
 369                return -EINVAL;
 370        }
 371        if (fd == DUPLEX_FULL)
 372                ctl |= BMCR_FULLDPLX;
 373        sungem_phy_write(phy, MII_BMCR, ctl);
 374
 375        return 0;
 376}
 377
 378static int genmii_poll_link(struct mii_phy *phy)
 379{
 380        u16 status;
 381
 382        (void)sungem_phy_read(phy, MII_BMSR);
 383        status = sungem_phy_read(phy, MII_BMSR);
 384        if ((status & BMSR_LSTATUS) == 0)
 385                return 0;
 386        if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
 387                return 0;
 388        return 1;
 389}
 390
 391static int genmii_read_link(struct mii_phy *phy)
 392{
 393        u16 lpa;
 394
 395        if (phy->autoneg) {
 396                lpa = sungem_phy_read(phy, MII_LPA);
 397
 398                if (lpa & (LPA_10FULL | LPA_100FULL))
 399                        phy->duplex = DUPLEX_FULL;
 400                else
 401                        phy->duplex = DUPLEX_HALF;
 402                if (lpa & (LPA_100FULL | LPA_100HALF))
 403                        phy->speed = SPEED_100;
 404                else
 405                        phy->speed = SPEED_10;
 406                phy->pause = 0;
 407        }
 408        /* On non-aneg, we assume what we put in BMCR is the speed,
 409         * though magic-aneg shouldn't prevent this case from occurring
 410         */
 411
 412         return 0;
 413}
 414
 415static int generic_suspend(struct mii_phy* phy)
 416{
 417        sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
 418
 419        return 0;
 420}
 421
 422static int bcm5421_init(struct mii_phy* phy)
 423{
 424        u16 data;
 425        unsigned int id;
 426
 427        id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
 428
 429        /* Revision 0 of 5421 needs some fixups */
 430        if (id == 0x002060e0) {
 431                /* This is borrowed from MacOS
 432                 */
 433                sungem_phy_write(phy, 0x18, 0x1007);
 434                data = sungem_phy_read(phy, 0x18);
 435                sungem_phy_write(phy, 0x18, data | 0x0400);
 436                sungem_phy_write(phy, 0x18, 0x0007);
 437                data = sungem_phy_read(phy, 0x18);
 438                sungem_phy_write(phy, 0x18, data | 0x0800);
 439                sungem_phy_write(phy, 0x17, 0x000a);
 440                data = sungem_phy_read(phy, 0x15);
 441                sungem_phy_write(phy, 0x15, data | 0x0200);
 442        }
 443
 444        /* Pick up some init code from OF for K2 version */
 445        if ((id & 0xfffffff0) == 0x002062e0) {
 446                sungem_phy_write(phy, 4, 0x01e1);
 447                sungem_phy_write(phy, 9, 0x0300);
 448        }
 449
 450        /* Check if we can enable automatic low power */
 451#ifdef CONFIG_PPC_PMAC
 452        if (phy->platform_data) {
 453                struct device_node *np = of_get_parent(phy->platform_data);
 454                int can_low_power = 1;
 455                if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
 456                        can_low_power = 0;
 457                if (can_low_power) {
 458                        /* Enable automatic low-power */
 459                        sungem_phy_write(phy, 0x1c, 0x9002);
 460                        sungem_phy_write(phy, 0x1c, 0xa821);
 461                        sungem_phy_write(phy, 0x1c, 0x941d);
 462                }
 463        }
 464#endif /* CONFIG_PPC_PMAC */
 465
 466        return 0;
 467}
 468
 469static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
 470{
 471        u16 ctl, adv;
 472
 473        phy->autoneg = 1;
 474        phy->speed = SPEED_10;
 475        phy->duplex = DUPLEX_HALF;
 476        phy->pause = 0;
 477        phy->advertising = advertise;
 478
 479        /* Setup standard advertise */
 480        adv = sungem_phy_read(phy, MII_ADVERTISE);
 481        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
 482        if (advertise & ADVERTISED_10baseT_Half)
 483                adv |= ADVERTISE_10HALF;
 484        if (advertise & ADVERTISED_10baseT_Full)
 485                adv |= ADVERTISE_10FULL;
 486        if (advertise & ADVERTISED_100baseT_Half)
 487                adv |= ADVERTISE_100HALF;
 488        if (advertise & ADVERTISED_100baseT_Full)
 489                adv |= ADVERTISE_100FULL;
 490        if (advertise & ADVERTISED_Pause)
 491                adv |= ADVERTISE_PAUSE_CAP;
 492        if (advertise & ADVERTISED_Asym_Pause)
 493                adv |= ADVERTISE_PAUSE_ASYM;
 494        sungem_phy_write(phy, MII_ADVERTISE, adv);
 495
 496        /* Setup 1000BT advertise */
 497        adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
 498        adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
 499        if (advertise & SUPPORTED_1000baseT_Half)
 500                adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
 501        if (advertise & SUPPORTED_1000baseT_Full)
 502                adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
 503        sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
 504
 505        /* Start/Restart aneg */
 506        ctl = sungem_phy_read(phy, MII_BMCR);
 507        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
 508        sungem_phy_write(phy, MII_BMCR, ctl);
 509
 510        return 0;
 511}
 512
 513static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
 514{
 515        u16 ctl;
 516
 517        phy->autoneg = 0;
 518        phy->speed = speed;
 519        phy->duplex = fd;
 520        phy->pause = 0;
 521
 522        ctl = sungem_phy_read(phy, MII_BMCR);
 523        ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
 524
 525        /* First reset the PHY */
 526        sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
 527
 528        /* Select speed & duplex */
 529        switch(speed) {
 530        case SPEED_10:
 531                break;
 532        case SPEED_100:
 533                ctl |= BMCR_SPEED100;
 534                break;
 535        case SPEED_1000:
 536                ctl |= BMCR_SPD2;
 537        }
 538        if (fd == DUPLEX_FULL)
 539                ctl |= BMCR_FULLDPLX;
 540
 541        // XXX Should we set the sungem to GII now on 1000BT ?
 542
 543        sungem_phy_write(phy, MII_BMCR, ctl);
 544
 545        return 0;
 546}
 547
 548static int bcm54xx_read_link(struct mii_phy *phy)
 549{
 550        int link_mode;
 551        u16 val;
 552
 553        if (phy->autoneg) {
 554                val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
 555                link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
 556                             MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
 557                phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
 558                        DUPLEX_FULL : DUPLEX_HALF;
 559                phy->speed = phy_BCM5400_link_table[link_mode][2] ?
 560                                SPEED_1000 :
 561                                (phy_BCM5400_link_table[link_mode][1] ?
 562                                 SPEED_100 : SPEED_10);
 563                val = sungem_phy_read(phy, MII_LPA);
 564                phy->pause = (phy->duplex == DUPLEX_FULL) &&
 565                        ((val & LPA_PAUSE) != 0);
 566        }
 567        /* On non-aneg, we assume what we put in BMCR is the speed,
 568         * though magic-aneg shouldn't prevent this case from occurring
 569         */
 570
 571        return 0;
 572}
 573
 574static int marvell88e1111_init(struct mii_phy* phy)
 575{
 576        u16 rev;
 577
 578        /* magic init sequence for rev 0 */
 579        rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
 580        if (rev == 0) {
 581                sungem_phy_write(phy, 0x1d, 0x000a);
 582                sungem_phy_write(phy, 0x1e, 0x0821);
 583
 584                sungem_phy_write(phy, 0x1d, 0x0006);
 585                sungem_phy_write(phy, 0x1e, 0x8600);
 586
 587                sungem_phy_write(phy, 0x1d, 0x000b);
 588                sungem_phy_write(phy, 0x1e, 0x0100);
 589
 590                sungem_phy_write(phy, 0x1d, 0x0004);
 591                sungem_phy_write(phy, 0x1e, 0x4850);
 592        }
 593        return 0;
 594}
 595
 596#define BCM5421_MODE_MASK       (1 << 5)
 597
 598static int bcm5421_poll_link(struct mii_phy* phy)
 599{
 600        u32 phy_reg;
 601        int mode;
 602
 603        /* find out in what mode we are */
 604        sungem_phy_write(phy, MII_NCONFIG, 0x1000);
 605        phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 606
 607        mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
 608
 609        if ( mode == BCM54XX_COPPER)
 610                return genmii_poll_link(phy);
 611
 612        /* try to find out whether we have a link */
 613        sungem_phy_write(phy, MII_NCONFIG, 0x2000);
 614        phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 615
 616        if (phy_reg & 0x0020)
 617                return 0;
 618        else
 619                return 1;
 620}
 621
 622static int bcm5421_read_link(struct mii_phy* phy)
 623{
 624        u32 phy_reg;
 625        int mode;
 626
 627        /* find out in what mode we are */
 628        sungem_phy_write(phy, MII_NCONFIG, 0x1000);
 629        phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 630
 631        mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
 632
 633        if ( mode == BCM54XX_COPPER)
 634                return bcm54xx_read_link(phy);
 635
 636        phy->speed = SPEED_1000;
 637
 638        /* find out whether we are running half- or full duplex */
 639        sungem_phy_write(phy, MII_NCONFIG, 0x2000);
 640        phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 641
 642        if ( (phy_reg & 0x0080) >> 7)
 643                phy->duplex |=  DUPLEX_HALF;
 644        else
 645                phy->duplex |=  DUPLEX_FULL;
 646
 647        return 0;
 648}
 649
 650static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
 651{
 652        /* enable fiber mode */
 653        sungem_phy_write(phy, MII_NCONFIG, 0x9020);
 654        /* LEDs active in both modes, autosense prio = fiber */
 655        sungem_phy_write(phy, MII_NCONFIG, 0x945f);
 656
 657        if (!autoneg) {
 658                /* switch off fibre autoneg */
 659                sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
 660                sungem_phy_write(phy, 0x0b, 0x0004);
 661        }
 662
 663        phy->autoneg = autoneg;
 664
 665        return 0;
 666}
 667
 668#define BCM5461_FIBER_LINK      (1 << 2)
 669#define BCM5461_MODE_MASK       (3 << 1)
 670
 671static int bcm5461_poll_link(struct mii_phy* phy)
 672{
 673        u32 phy_reg;
 674        int mode;
 675
 676        /* find out in what mode we are */
 677        sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
 678        phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 679
 680        mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
 681
 682        if ( mode == BCM54XX_COPPER)
 683                return genmii_poll_link(phy);
 684
 685        /* find out whether we have a link */
 686        sungem_phy_write(phy, MII_NCONFIG, 0x7000);
 687        phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 688
 689        if (phy_reg & BCM5461_FIBER_LINK)
 690                return 1;
 691        else
 692                return 0;
 693}
 694
 695#define BCM5461_FIBER_DUPLEX    (1 << 3)
 696
 697static int bcm5461_read_link(struct mii_phy* phy)
 698{
 699        u32 phy_reg;
 700        int mode;
 701
 702        /* find out in what mode we are */
 703        sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
 704        phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 705
 706        mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
 707
 708        if ( mode == BCM54XX_COPPER) {
 709                return bcm54xx_read_link(phy);
 710        }
 711
 712        phy->speed = SPEED_1000;
 713
 714        /* find out whether we are running half- or full duplex */
 715        sungem_phy_write(phy, MII_NCONFIG, 0x7000);
 716        phy_reg = sungem_phy_read(phy, MII_NCONFIG);
 717
 718        if (phy_reg & BCM5461_FIBER_DUPLEX)
 719                phy->duplex |=  DUPLEX_FULL;
 720        else
 721                phy->duplex |=  DUPLEX_HALF;
 722
 723        return 0;
 724}
 725
 726static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
 727{
 728        /* select fiber mode, enable 1000 base-X registers */
 729        sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
 730
 731        if (autoneg) {
 732                /* enable fiber with no autonegotiation */
 733                sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
 734                sungem_phy_write(phy, MII_BMCR, 0x1140);
 735        } else {
 736                /* enable fiber with autonegotiation */
 737                sungem_phy_write(phy, MII_BMCR, 0x0140);
 738        }
 739
 740        phy->autoneg = autoneg;
 741
 742        return 0;
 743}
 744
 745static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
 746{
 747        u16 ctl, adv;
 748
 749        phy->autoneg = 1;
 750        phy->speed = SPEED_10;
 751        phy->duplex = DUPLEX_HALF;
 752        phy->pause = 0;
 753        phy->advertising = advertise;
 754
 755        /* Setup standard advertise */
 756        adv = sungem_phy_read(phy, MII_ADVERTISE);
 757        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
 758        if (advertise & ADVERTISED_10baseT_Half)
 759                adv |= ADVERTISE_10HALF;
 760        if (advertise & ADVERTISED_10baseT_Full)
 761                adv |= ADVERTISE_10FULL;
 762        if (advertise & ADVERTISED_100baseT_Half)
 763                adv |= ADVERTISE_100HALF;
 764        if (advertise & ADVERTISED_100baseT_Full)
 765                adv |= ADVERTISE_100FULL;
 766        if (advertise & ADVERTISED_Pause)
 767                adv |= ADVERTISE_PAUSE_CAP;
 768        if (advertise & ADVERTISED_Asym_Pause)
 769                adv |= ADVERTISE_PAUSE_ASYM;
 770        sungem_phy_write(phy, MII_ADVERTISE, adv);
 771
 772        /* Setup 1000BT advertise & enable crossover detect
 773         * XXX How do we advertise 1000BT ? Darwin source is
 774         * confusing here, they read from specific control and
 775         * write to control... Someone has specs for those
 776         * beasts ?
 777         */
 778        adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
 779        adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
 780        adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
 781                        MII_1000BASETCONTROL_HALFDUPLEXCAP);
 782        if (advertise & SUPPORTED_1000baseT_Half)
 783                adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
 784        if (advertise & SUPPORTED_1000baseT_Full)
 785                adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
 786        sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
 787
 788        /* Start/Restart aneg */
 789        ctl = sungem_phy_read(phy, MII_BMCR);
 790        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
 791        sungem_phy_write(phy, MII_BMCR, ctl);
 792
 793        return 0;
 794}
 795
 796static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
 797{
 798        u16 ctl, ctl2;
 799
 800        phy->autoneg = 0;
 801        phy->speed = speed;
 802        phy->duplex = fd;
 803        phy->pause = 0;
 804
 805        ctl = sungem_phy_read(phy, MII_BMCR);
 806        ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
 807        ctl |= BMCR_RESET;
 808
 809        /* Select speed & duplex */
 810        switch(speed) {
 811        case SPEED_10:
 812                break;
 813        case SPEED_100:
 814                ctl |= BMCR_SPEED100;
 815                break;
 816        /* I'm not sure about the one below, again, Darwin source is
 817         * quite confusing and I lack chip specs
 818         */
 819        case SPEED_1000:
 820                ctl |= BMCR_SPD2;
 821        }
 822        if (fd == DUPLEX_FULL)
 823                ctl |= BMCR_FULLDPLX;
 824
 825        /* Disable crossover. Again, the way Apple does it is strange,
 826         * though I don't assume they are wrong ;)
 827         */
 828        ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
 829        ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
 830                MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
 831                MII_1000BASETCONTROL_FULLDUPLEXCAP |
 832                MII_1000BASETCONTROL_HALFDUPLEXCAP);
 833        if (speed == SPEED_1000)
 834                ctl2 |= (fd == DUPLEX_FULL) ?
 835                        MII_1000BASETCONTROL_FULLDUPLEXCAP :
 836                        MII_1000BASETCONTROL_HALFDUPLEXCAP;
 837        sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
 838
 839        // XXX Should we set the sungem to GII now on 1000BT ?
 840
 841        sungem_phy_write(phy, MII_BMCR, ctl);
 842
 843        return 0;
 844}
 845
 846static int marvell_read_link(struct mii_phy *phy)
 847{
 848        u16 status, pmask;
 849
 850        if (phy->autoneg) {
 851                status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
 852                if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
 853                        return -EAGAIN;
 854                if (status & MII_M1011_PHY_SPEC_STATUS_1000)
 855                        phy->speed = SPEED_1000;
 856                else if (status & MII_M1011_PHY_SPEC_STATUS_100)
 857                        phy->speed = SPEED_100;
 858                else
 859                        phy->speed = SPEED_10;
 860                if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
 861                        phy->duplex = DUPLEX_FULL;
 862                else
 863                        phy->duplex = DUPLEX_HALF;
 864                pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
 865                        MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
 866                phy->pause = (status & pmask) == pmask;
 867        }
 868        /* On non-aneg, we assume what we put in BMCR is the speed,
 869         * though magic-aneg shouldn't prevent this case from occurring
 870         */
 871
 872        return 0;
 873}
 874
 875#define MII_BASIC_FEATURES \
 876        (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |      \
 877         SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |    \
 878         SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |     \
 879         SUPPORTED_Pause)
 880
 881/* On gigabit capable PHYs, we advertise Pause support but not asym pause
 882 * support for now as I'm not sure it's supported and Darwin doesn't do
 883 * it neither. --BenH.
 884 */
 885#define MII_GBIT_FEATURES \
 886        (MII_BASIC_FEATURES |   \
 887         SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
 888
 889/* Broadcom BCM 5201 */
 890static const struct mii_phy_ops bcm5201_phy_ops = {
 891        .init           = bcm5201_init,
 892        .suspend        = bcm5201_suspend,
 893        .setup_aneg     = genmii_setup_aneg,
 894        .setup_forced   = genmii_setup_forced,
 895        .poll_link      = genmii_poll_link,
 896        .read_link      = genmii_read_link,
 897};
 898
 899static struct mii_phy_def bcm5201_phy_def = {
 900        .phy_id         = 0x00406210,
 901        .phy_id_mask    = 0xfffffff0,
 902        .name           = "BCM5201",
 903        .features       = MII_BASIC_FEATURES,
 904        .magic_aneg     = 1,
 905        .ops            = &bcm5201_phy_ops
 906};
 907
 908/* Broadcom BCM 5221 */
 909static const struct mii_phy_ops bcm5221_phy_ops = {
 910        .suspend        = bcm5221_suspend,
 911        .init           = bcm5221_init,
 912        .setup_aneg     = genmii_setup_aneg,
 913        .setup_forced   = genmii_setup_forced,
 914        .poll_link      = genmii_poll_link,
 915        .read_link      = genmii_read_link,
 916};
 917
 918static struct mii_phy_def bcm5221_phy_def = {
 919        .phy_id         = 0x004061e0,
 920        .phy_id_mask    = 0xfffffff0,
 921        .name           = "BCM5221",
 922        .features       = MII_BASIC_FEATURES,
 923        .magic_aneg     = 1,
 924        .ops            = &bcm5221_phy_ops
 925};
 926
 927/* Broadcom BCM 5241 */
 928static const struct mii_phy_ops bcm5241_phy_ops = {
 929        .suspend        = bcm5241_suspend,
 930        .init           = bcm5241_init,
 931        .setup_aneg     = genmii_setup_aneg,
 932        .setup_forced   = genmii_setup_forced,
 933        .poll_link      = genmii_poll_link,
 934        .read_link      = genmii_read_link,
 935};
 936static struct mii_phy_def bcm5241_phy_def = {
 937        .phy_id         = 0x0143bc30,
 938        .phy_id_mask    = 0xfffffff0,
 939        .name           = "BCM5241",
 940        .features       = MII_BASIC_FEATURES,
 941        .magic_aneg     = 1,
 942        .ops            = &bcm5241_phy_ops
 943};
 944
 945/* Broadcom BCM 5400 */
 946static const struct mii_phy_ops bcm5400_phy_ops = {
 947        .init           = bcm5400_init,
 948        .suspend        = bcm5400_suspend,
 949        .setup_aneg     = bcm54xx_setup_aneg,
 950        .setup_forced   = bcm54xx_setup_forced,
 951        .poll_link      = genmii_poll_link,
 952        .read_link      = bcm54xx_read_link,
 953};
 954
 955static struct mii_phy_def bcm5400_phy_def = {
 956        .phy_id         = 0x00206040,
 957        .phy_id_mask    = 0xfffffff0,
 958        .name           = "BCM5400",
 959        .features       = MII_GBIT_FEATURES,
 960        .magic_aneg     = 1,
 961        .ops            = &bcm5400_phy_ops
 962};
 963
 964/* Broadcom BCM 5401 */
 965static const struct mii_phy_ops bcm5401_phy_ops = {
 966        .init           = bcm5401_init,
 967        .suspend        = bcm5401_suspend,
 968        .setup_aneg     = bcm54xx_setup_aneg,
 969        .setup_forced   = bcm54xx_setup_forced,
 970        .poll_link      = genmii_poll_link,
 971        .read_link      = bcm54xx_read_link,
 972};
 973
 974static struct mii_phy_def bcm5401_phy_def = {
 975        .phy_id         = 0x00206050,
 976        .phy_id_mask    = 0xfffffff0,
 977        .name           = "BCM5401",
 978        .features       = MII_GBIT_FEATURES,
 979        .magic_aneg     = 1,
 980        .ops            = &bcm5401_phy_ops
 981};
 982
 983/* Broadcom BCM 5411 */
 984static const struct mii_phy_ops bcm5411_phy_ops = {
 985        .init           = bcm5411_init,
 986        .suspend        = generic_suspend,
 987        .setup_aneg     = bcm54xx_setup_aneg,
 988        .setup_forced   = bcm54xx_setup_forced,
 989        .poll_link      = genmii_poll_link,
 990        .read_link      = bcm54xx_read_link,
 991};
 992
 993static struct mii_phy_def bcm5411_phy_def = {
 994        .phy_id         = 0x00206070,
 995        .phy_id_mask    = 0xfffffff0,
 996        .name           = "BCM5411",
 997        .features       = MII_GBIT_FEATURES,
 998        .magic_aneg     = 1,
 999        .ops            = &bcm5411_phy_ops
1000};
1001
1002/* Broadcom BCM 5421 */
1003static const struct mii_phy_ops bcm5421_phy_ops = {
1004        .init           = bcm5421_init,
1005        .suspend        = generic_suspend,
1006        .setup_aneg     = bcm54xx_setup_aneg,
1007        .setup_forced   = bcm54xx_setup_forced,
1008        .poll_link      = bcm5421_poll_link,
1009        .read_link      = bcm5421_read_link,
1010        .enable_fiber   = bcm5421_enable_fiber,
1011};
1012
1013static struct mii_phy_def bcm5421_phy_def = {
1014        .phy_id         = 0x002060e0,
1015        .phy_id_mask    = 0xfffffff0,
1016        .name           = "BCM5421",
1017        .features       = MII_GBIT_FEATURES,
1018        .magic_aneg     = 1,
1019        .ops            = &bcm5421_phy_ops
1020};
1021
1022/* Broadcom BCM 5421 built-in K2 */
1023static const struct mii_phy_ops bcm5421k2_phy_ops = {
1024        .init           = bcm5421_init,
1025        .suspend        = generic_suspend,
1026        .setup_aneg     = bcm54xx_setup_aneg,
1027        .setup_forced   = bcm54xx_setup_forced,
1028        .poll_link      = genmii_poll_link,
1029        .read_link      = bcm54xx_read_link,
1030};
1031
1032static struct mii_phy_def bcm5421k2_phy_def = {
1033        .phy_id         = 0x002062e0,
1034        .phy_id_mask    = 0xfffffff0,
1035        .name           = "BCM5421-K2",
1036        .features       = MII_GBIT_FEATURES,
1037        .magic_aneg     = 1,
1038        .ops            = &bcm5421k2_phy_ops
1039};
1040
1041static const struct mii_phy_ops bcm5461_phy_ops = {
1042        .init           = bcm5421_init,
1043        .suspend        = generic_suspend,
1044        .setup_aneg     = bcm54xx_setup_aneg,
1045        .setup_forced   = bcm54xx_setup_forced,
1046        .poll_link      = bcm5461_poll_link,
1047        .read_link      = bcm5461_read_link,
1048        .enable_fiber   = bcm5461_enable_fiber,
1049};
1050
1051static struct mii_phy_def bcm5461_phy_def = {
1052        .phy_id         = 0x002060c0,
1053        .phy_id_mask    = 0xfffffff0,
1054        .name           = "BCM5461",
1055        .features       = MII_GBIT_FEATURES,
1056        .magic_aneg     = 1,
1057        .ops            = &bcm5461_phy_ops
1058};
1059
1060/* Broadcom BCM 5462 built-in Vesta */
1061static const struct mii_phy_ops bcm5462V_phy_ops = {
1062        .init           = bcm5421_init,
1063        .suspend        = generic_suspend,
1064        .setup_aneg     = bcm54xx_setup_aneg,
1065        .setup_forced   = bcm54xx_setup_forced,
1066        .poll_link      = genmii_poll_link,
1067        .read_link      = bcm54xx_read_link,
1068};
1069
1070static struct mii_phy_def bcm5462V_phy_def = {
1071        .phy_id         = 0x002060d0,
1072        .phy_id_mask    = 0xfffffff0,
1073        .name           = "BCM5462-Vesta",
1074        .features       = MII_GBIT_FEATURES,
1075        .magic_aneg     = 1,
1076        .ops            = &bcm5462V_phy_ops
1077};
1078
1079/* Marvell 88E1101 amd 88E1111 */
1080static const struct mii_phy_ops marvell88e1101_phy_ops = {
1081        .suspend        = generic_suspend,
1082        .setup_aneg     = marvell_setup_aneg,
1083        .setup_forced   = marvell_setup_forced,
1084        .poll_link      = genmii_poll_link,
1085        .read_link      = marvell_read_link
1086};
1087
1088static const struct mii_phy_ops marvell88e1111_phy_ops = {
1089        .init           = marvell88e1111_init,
1090        .suspend        = generic_suspend,
1091        .setup_aneg     = marvell_setup_aneg,
1092        .setup_forced   = marvell_setup_forced,
1093        .poll_link      = genmii_poll_link,
1094        .read_link      = marvell_read_link
1095};
1096
1097/* two revs in darwin for the 88e1101 ... I could use a datasheet
1098 * to get the proper names...
1099 */
1100static struct mii_phy_def marvell88e1101v1_phy_def = {
1101        .phy_id         = 0x01410c20,
1102        .phy_id_mask    = 0xfffffff0,
1103        .name           = "Marvell 88E1101v1",
1104        .features       = MII_GBIT_FEATURES,
1105        .magic_aneg     = 1,
1106        .ops            = &marvell88e1101_phy_ops
1107};
1108static struct mii_phy_def marvell88e1101v2_phy_def = {
1109        .phy_id         = 0x01410c60,
1110        .phy_id_mask    = 0xfffffff0,
1111        .name           = "Marvell 88E1101v2",
1112        .features       = MII_GBIT_FEATURES,
1113        .magic_aneg     = 1,
1114        .ops            = &marvell88e1101_phy_ops
1115};
1116static struct mii_phy_def marvell88e1111_phy_def = {
1117        .phy_id         = 0x01410cc0,
1118        .phy_id_mask    = 0xfffffff0,
1119        .name           = "Marvell 88E1111",
1120        .features       = MII_GBIT_FEATURES,
1121        .magic_aneg     = 1,
1122        .ops            = &marvell88e1111_phy_ops
1123};
1124
1125/* Generic implementation for most 10/100 PHYs */
1126static const struct mii_phy_ops generic_phy_ops = {
1127        .setup_aneg     = genmii_setup_aneg,
1128        .setup_forced   = genmii_setup_forced,
1129        .poll_link      = genmii_poll_link,
1130        .read_link      = genmii_read_link
1131};
1132
1133static struct mii_phy_def genmii_phy_def = {
1134        .phy_id         = 0x00000000,
1135        .phy_id_mask    = 0x00000000,
1136        .name           = "Generic MII",
1137        .features       = MII_BASIC_FEATURES,
1138        .magic_aneg     = 0,
1139        .ops            = &generic_phy_ops
1140};
1141
1142static struct mii_phy_def* mii_phy_table[] = {
1143        &bcm5201_phy_def,
1144        &bcm5221_phy_def,
1145        &bcm5241_phy_def,
1146        &bcm5400_phy_def,
1147        &bcm5401_phy_def,
1148        &bcm5411_phy_def,
1149        &bcm5421_phy_def,
1150        &bcm5421k2_phy_def,
1151        &bcm5461_phy_def,
1152        &bcm5462V_phy_def,
1153        &marvell88e1101v1_phy_def,
1154        &marvell88e1101v2_phy_def,
1155        &marvell88e1111_phy_def,
1156        &genmii_phy_def,
1157        NULL
1158};
1159
1160int sungem_phy_probe(struct mii_phy *phy, int mii_id)
1161{
1162        int rc;
1163        u32 id;
1164        struct mii_phy_def* def;
1165        int i;
1166
1167        /* We do not reset the mii_phy structure as the driver
1168         * may re-probe the PHY regulary
1169         */
1170        phy->mii_id = mii_id;
1171
1172        /* Take PHY out of isloate mode and reset it. */
1173        rc = reset_one_mii_phy(phy, mii_id);
1174        if (rc)
1175                goto fail;
1176
1177        /* Read ID and find matching entry */
1178        id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
1179        printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
1180               id, mii_id);
1181        for (i=0; (def = mii_phy_table[i]) != NULL; i++)
1182                if ((id & def->phy_id_mask) == def->phy_id)
1183                        break;
1184        /* Should never be NULL (we have a generic entry), but... */
1185        if (def == NULL)
1186                goto fail;
1187
1188        phy->def = def;
1189
1190        return 0;
1191fail:
1192        phy->speed = 0;
1193        phy->duplex = 0;
1194        phy->pause = 0;
1195        phy->advertising = 0;
1196        return -ENODEV;
1197}
1198
1199EXPORT_SYMBOL(sungem_phy_probe);
1200MODULE_LICENSE("GPL");
1201