Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * PHY drivers for the sungem ethernet driver.
0004  *
0005  * This file could be shared with other drivers.
0006  *
0007  * (c) 2002-2007, Benjamin Herrenscmidt (benh@kernel.crashing.org)
0008  *
0009  * TODO:
0010  *  - Add support for PHYs that provide an IRQ line
0011  *  - Eventually moved the entire polling state machine in
0012  *    there (out of the eth driver), so that it can easily be
0013  *    skipped on PHYs that implement it in hardware.
0014  *  - On LXT971 & BCM5201, Apple uses some chip specific regs
0015  *    to read the link status. Figure out why and if it makes
0016  *    sense to do the same (magic aneg ?)
0017  *  - Apple has some additional power management code for some
0018  *    Broadcom PHYs that they "hide" from the OpenSource version
0019  *    of darwin, still need to reverse engineer that
0020  */
0021 
0022 
0023 #include <linux/module.h>
0024 
0025 #include <linux/kernel.h>
0026 #include <linux/types.h>
0027 #include <linux/netdevice.h>
0028 #include <linux/etherdevice.h>
0029 #include <linux/mii.h>
0030 #include <linux/ethtool.h>
0031 #include <linux/delay.h>
0032 #include <linux/of.h>
0033 #include <linux/sungem_phy.h>
0034 
0035 /* Link modes of the BCM5400 PHY */
0036 static const int phy_BCM5400_link_table[8][3] = {
0037     { 0, 0, 0 },    /* No link */
0038     { 0, 0, 0 },    /* 10BT Half Duplex */
0039     { 1, 0, 0 },    /* 10BT Full Duplex */
0040     { 0, 1, 0 },    /* 100BT Half Duplex */
0041     { 0, 1, 0 },    /* 100BT Half Duplex */
0042     { 1, 1, 0 },    /* 100BT Full Duplex*/
0043     { 1, 0, 1 },    /* 1000BT */
0044     { 1, 0, 1 },    /* 1000BT */
0045 };
0046 
0047 static inline int __sungem_phy_read(struct mii_phy* phy, int id, int reg)
0048 {
0049     return phy->mdio_read(phy->dev, id, reg);
0050 }
0051 
0052 static inline void __sungem_phy_write(struct mii_phy* phy, int id, int reg, int val)
0053 {
0054     phy->mdio_write(phy->dev, id, reg, val);
0055 }
0056 
0057 static inline int sungem_phy_read(struct mii_phy* phy, int reg)
0058 {
0059     return phy->mdio_read(phy->dev, phy->mii_id, reg);
0060 }
0061 
0062 static inline void sungem_phy_write(struct mii_phy* phy, int reg, int val)
0063 {
0064     phy->mdio_write(phy->dev, phy->mii_id, reg, val);
0065 }
0066 
0067 static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
0068 {
0069     u16 val;
0070     int limit = 10000;
0071 
0072     val = __sungem_phy_read(phy, phy_id, MII_BMCR);
0073     val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
0074     val |= BMCR_RESET;
0075     __sungem_phy_write(phy, phy_id, MII_BMCR, val);
0076 
0077     udelay(100);
0078 
0079     while (--limit) {
0080         val = __sungem_phy_read(phy, phy_id, MII_BMCR);
0081         if ((val & BMCR_RESET) == 0)
0082             break;
0083         udelay(10);
0084     }
0085     if ((val & BMCR_ISOLATE) && limit > 0)
0086         __sungem_phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
0087 
0088     return limit <= 0;
0089 }
0090 
0091 static int bcm5201_init(struct mii_phy* phy)
0092 {
0093     u16 data;
0094 
0095     data = sungem_phy_read(phy, MII_BCM5201_MULTIPHY);
0096     data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
0097     sungem_phy_write(phy, MII_BCM5201_MULTIPHY, data);
0098 
0099     sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
0100 
0101     return 0;
0102 }
0103 
0104 static int bcm5201_suspend(struct mii_phy* phy)
0105 {
0106     sungem_phy_write(phy, MII_BCM5201_INTERRUPT, 0);
0107     sungem_phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
0108 
0109     return 0;
0110 }
0111 
0112 static int bcm5221_init(struct mii_phy* phy)
0113 {
0114     u16 data;
0115 
0116     data = sungem_phy_read(phy, MII_BCM5221_TEST);
0117     sungem_phy_write(phy, MII_BCM5221_TEST,
0118         data | MII_BCM5221_TEST_ENABLE_SHADOWS);
0119 
0120     data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
0121     sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
0122         data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
0123 
0124     data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
0125     sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
0126         data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
0127 
0128     data = sungem_phy_read(phy, MII_BCM5221_TEST);
0129     sungem_phy_write(phy, MII_BCM5221_TEST,
0130         data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
0131 
0132     return 0;
0133 }
0134 
0135 static int bcm5221_suspend(struct mii_phy* phy)
0136 {
0137     u16 data;
0138 
0139     data = sungem_phy_read(phy, MII_BCM5221_TEST);
0140     sungem_phy_write(phy, MII_BCM5221_TEST,
0141         data | MII_BCM5221_TEST_ENABLE_SHADOWS);
0142 
0143     data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
0144     sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
0145           data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
0146 
0147     return 0;
0148 }
0149 
0150 static int bcm5241_init(struct mii_phy* phy)
0151 {
0152     u16 data;
0153 
0154     data = sungem_phy_read(phy, MII_BCM5221_TEST);
0155     sungem_phy_write(phy, MII_BCM5221_TEST,
0156         data | MII_BCM5221_TEST_ENABLE_SHADOWS);
0157 
0158     data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
0159     sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
0160         data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
0161 
0162     data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
0163     sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
0164         data & ~MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
0165 
0166     data = sungem_phy_read(phy, MII_BCM5221_TEST);
0167     sungem_phy_write(phy, MII_BCM5221_TEST,
0168         data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
0169 
0170     return 0;
0171 }
0172 
0173 static int bcm5241_suspend(struct mii_phy* phy)
0174 {
0175     u16 data;
0176 
0177     data = sungem_phy_read(phy, MII_BCM5221_TEST);
0178     sungem_phy_write(phy, MII_BCM5221_TEST,
0179         data | MII_BCM5221_TEST_ENABLE_SHADOWS);
0180 
0181     data = sungem_phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
0182     sungem_phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
0183           data | MII_BCM5241_SHDOW_AUX_MODE4_STANDBYPWR);
0184 
0185     return 0;
0186 }
0187 
0188 static int bcm5400_init(struct mii_phy* phy)
0189 {
0190     u16 data;
0191 
0192     /* Configure for gigabit full duplex */
0193     data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
0194     data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
0195     sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
0196 
0197     data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
0198     data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
0199     sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
0200 
0201     udelay(100);
0202 
0203     /* Reset and configure cascaded 10/100 PHY */
0204     (void)reset_one_mii_phy(phy, 0x1f);
0205 
0206     data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
0207     data |= MII_BCM5201_MULTIPHY_SERIALMODE;
0208     __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
0209 
0210     data = sungem_phy_read(phy, MII_BCM5400_AUXCONTROL);
0211     data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
0212     sungem_phy_write(phy, MII_BCM5400_AUXCONTROL, data);
0213 
0214     return 0;
0215 }
0216 
0217 static int bcm5400_suspend(struct mii_phy* phy)
0218 {
0219 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
0220     sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
0221 #endif
0222     return 0;
0223 }
0224 
0225 static int bcm5401_init(struct mii_phy* phy)
0226 {
0227     u16 data;
0228     int rev;
0229 
0230     rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
0231     if (rev == 0 || rev == 3) {
0232         /* Some revisions of 5401 appear to need this
0233          * initialisation sequence to disable, according
0234          * to OF, "tap power management"
0235          *
0236          * WARNING ! OF and Darwin don't agree on the
0237          * register addresses. OF seem to interpret the
0238          * register numbers below as decimal
0239          *
0240          * Note: This should (and does) match tg3_init_5401phy_dsp
0241          *       in the tg3.c driver. -DaveM
0242          */
0243         sungem_phy_write(phy, 0x18, 0x0c20);
0244         sungem_phy_write(phy, 0x17, 0x0012);
0245         sungem_phy_write(phy, 0x15, 0x1804);
0246         sungem_phy_write(phy, 0x17, 0x0013);
0247         sungem_phy_write(phy, 0x15, 0x1204);
0248         sungem_phy_write(phy, 0x17, 0x8006);
0249         sungem_phy_write(phy, 0x15, 0x0132);
0250         sungem_phy_write(phy, 0x17, 0x8006);
0251         sungem_phy_write(phy, 0x15, 0x0232);
0252         sungem_phy_write(phy, 0x17, 0x201f);
0253         sungem_phy_write(phy, 0x15, 0x0a20);
0254     }
0255 
0256     /* Configure for gigabit full duplex */
0257     data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
0258     data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
0259     sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
0260 
0261     udelay(10);
0262 
0263     /* Reset and configure cascaded 10/100 PHY */
0264     (void)reset_one_mii_phy(phy, 0x1f);
0265 
0266     data = __sungem_phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
0267     data |= MII_BCM5201_MULTIPHY_SERIALMODE;
0268     __sungem_phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
0269 
0270     return 0;
0271 }
0272 
0273 static int bcm5401_suspend(struct mii_phy* phy)
0274 {
0275 #if 0 /* Commented out in Darwin... someone has those dawn docs ? */
0276     sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
0277 #endif
0278     return 0;
0279 }
0280 
0281 static int bcm5411_init(struct mii_phy* phy)
0282 {
0283     u16 data;
0284 
0285     /* Here's some more Apple black magic to setup
0286      * some voltage stuffs.
0287      */
0288     sungem_phy_write(phy, 0x1c, 0x8c23);
0289     sungem_phy_write(phy, 0x1c, 0x8ca3);
0290     sungem_phy_write(phy, 0x1c, 0x8c23);
0291 
0292     /* Here, Apple seems to want to reset it, do
0293      * it as well
0294      */
0295     sungem_phy_write(phy, MII_BMCR, BMCR_RESET);
0296     sungem_phy_write(phy, MII_BMCR, 0x1340);
0297 
0298     data = sungem_phy_read(phy, MII_BCM5400_GB_CONTROL);
0299     data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
0300     sungem_phy_write(phy, MII_BCM5400_GB_CONTROL, data);
0301 
0302     udelay(10);
0303 
0304     /* Reset and configure cascaded 10/100 PHY */
0305     (void)reset_one_mii_phy(phy, 0x1f);
0306 
0307     return 0;
0308 }
0309 
0310 static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
0311 {
0312     u16 ctl, adv;
0313 
0314     phy->autoneg = 1;
0315     phy->speed = SPEED_10;
0316     phy->duplex = DUPLEX_HALF;
0317     phy->pause = 0;
0318     phy->advertising = advertise;
0319 
0320     /* Setup standard advertise */
0321     adv = sungem_phy_read(phy, MII_ADVERTISE);
0322     adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
0323     if (advertise & ADVERTISED_10baseT_Half)
0324         adv |= ADVERTISE_10HALF;
0325     if (advertise & ADVERTISED_10baseT_Full)
0326         adv |= ADVERTISE_10FULL;
0327     if (advertise & ADVERTISED_100baseT_Half)
0328         adv |= ADVERTISE_100HALF;
0329     if (advertise & ADVERTISED_100baseT_Full)
0330         adv |= ADVERTISE_100FULL;
0331     sungem_phy_write(phy, MII_ADVERTISE, adv);
0332 
0333     /* Start/Restart aneg */
0334     ctl = sungem_phy_read(phy, MII_BMCR);
0335     ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
0336     sungem_phy_write(phy, MII_BMCR, ctl);
0337 
0338     return 0;
0339 }
0340 
0341 static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
0342 {
0343     u16 ctl;
0344 
0345     phy->autoneg = 0;
0346     phy->speed = speed;
0347     phy->duplex = fd;
0348     phy->pause = 0;
0349 
0350     ctl = sungem_phy_read(phy, MII_BMCR);
0351     ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
0352 
0353     /* First reset the PHY */
0354     sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
0355 
0356     /* Select speed & duplex */
0357     switch(speed) {
0358     case SPEED_10:
0359         break;
0360     case SPEED_100:
0361         ctl |= BMCR_SPEED100;
0362         break;
0363     case SPEED_1000:
0364     default:
0365         return -EINVAL;
0366     }
0367     if (fd == DUPLEX_FULL)
0368         ctl |= BMCR_FULLDPLX;
0369     sungem_phy_write(phy, MII_BMCR, ctl);
0370 
0371     return 0;
0372 }
0373 
0374 static int genmii_poll_link(struct mii_phy *phy)
0375 {
0376     u16 status;
0377 
0378     (void)sungem_phy_read(phy, MII_BMSR);
0379     status = sungem_phy_read(phy, MII_BMSR);
0380     if ((status & BMSR_LSTATUS) == 0)
0381         return 0;
0382     if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
0383         return 0;
0384     return 1;
0385 }
0386 
0387 static int genmii_read_link(struct mii_phy *phy)
0388 {
0389     u16 lpa;
0390 
0391     if (phy->autoneg) {
0392         lpa = sungem_phy_read(phy, MII_LPA);
0393 
0394         if (lpa & (LPA_10FULL | LPA_100FULL))
0395             phy->duplex = DUPLEX_FULL;
0396         else
0397             phy->duplex = DUPLEX_HALF;
0398         if (lpa & (LPA_100FULL | LPA_100HALF))
0399             phy->speed = SPEED_100;
0400         else
0401             phy->speed = SPEED_10;
0402         phy->pause = 0;
0403     }
0404     /* On non-aneg, we assume what we put in BMCR is the speed,
0405      * though magic-aneg shouldn't prevent this case from occurring
0406      */
0407 
0408     return 0;
0409 }
0410 
0411 static int generic_suspend(struct mii_phy* phy)
0412 {
0413     sungem_phy_write(phy, MII_BMCR, BMCR_PDOWN);
0414 
0415     return 0;
0416 }
0417 
0418 static int bcm5421_init(struct mii_phy* phy)
0419 {
0420     u16 data;
0421     unsigned int id;
0422 
0423     id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
0424 
0425     /* Revision 0 of 5421 needs some fixups */
0426     if (id == 0x002060e0) {
0427         /* This is borrowed from MacOS
0428          */
0429         sungem_phy_write(phy, 0x18, 0x1007);
0430         data = sungem_phy_read(phy, 0x18);
0431         sungem_phy_write(phy, 0x18, data | 0x0400);
0432         sungem_phy_write(phy, 0x18, 0x0007);
0433         data = sungem_phy_read(phy, 0x18);
0434         sungem_phy_write(phy, 0x18, data | 0x0800);
0435         sungem_phy_write(phy, 0x17, 0x000a);
0436         data = sungem_phy_read(phy, 0x15);
0437         sungem_phy_write(phy, 0x15, data | 0x0200);
0438     }
0439 
0440     /* Pick up some init code from OF for K2 version */
0441     if ((id & 0xfffffff0) == 0x002062e0) {
0442         sungem_phy_write(phy, 4, 0x01e1);
0443         sungem_phy_write(phy, 9, 0x0300);
0444     }
0445 
0446     /* Check if we can enable automatic low power */
0447 #ifdef CONFIG_PPC_PMAC
0448     if (phy->platform_data) {
0449         struct device_node *np = of_get_parent(phy->platform_data);
0450         int can_low_power = 1;
0451         if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
0452             can_low_power = 0;
0453         of_node_put(np);
0454         if (can_low_power) {
0455             /* Enable automatic low-power */
0456             sungem_phy_write(phy, 0x1c, 0x9002);
0457             sungem_phy_write(phy, 0x1c, 0xa821);
0458             sungem_phy_write(phy, 0x1c, 0x941d);
0459         }
0460     }
0461 #endif /* CONFIG_PPC_PMAC */
0462 
0463     return 0;
0464 }
0465 
0466 static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
0467 {
0468     u16 ctl, adv;
0469 
0470     phy->autoneg = 1;
0471     phy->speed = SPEED_10;
0472     phy->duplex = DUPLEX_HALF;
0473     phy->pause = 0;
0474     phy->advertising = advertise;
0475 
0476     /* Setup standard advertise */
0477     adv = sungem_phy_read(phy, MII_ADVERTISE);
0478     adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
0479     if (advertise & ADVERTISED_10baseT_Half)
0480         adv |= ADVERTISE_10HALF;
0481     if (advertise & ADVERTISED_10baseT_Full)
0482         adv |= ADVERTISE_10FULL;
0483     if (advertise & ADVERTISED_100baseT_Half)
0484         adv |= ADVERTISE_100HALF;
0485     if (advertise & ADVERTISED_100baseT_Full)
0486         adv |= ADVERTISE_100FULL;
0487     if (advertise & ADVERTISED_Pause)
0488         adv |= ADVERTISE_PAUSE_CAP;
0489     if (advertise & ADVERTISED_Asym_Pause)
0490         adv |= ADVERTISE_PAUSE_ASYM;
0491     sungem_phy_write(phy, MII_ADVERTISE, adv);
0492 
0493     /* Setup 1000BT advertise */
0494     adv = sungem_phy_read(phy, MII_1000BASETCONTROL);
0495     adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
0496     if (advertise & SUPPORTED_1000baseT_Half)
0497         adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
0498     if (advertise & SUPPORTED_1000baseT_Full)
0499         adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
0500     sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
0501 
0502     /* Start/Restart aneg */
0503     ctl = sungem_phy_read(phy, MII_BMCR);
0504     ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
0505     sungem_phy_write(phy, MII_BMCR, ctl);
0506 
0507     return 0;
0508 }
0509 
0510 static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
0511 {
0512     u16 ctl;
0513 
0514     phy->autoneg = 0;
0515     phy->speed = speed;
0516     phy->duplex = fd;
0517     phy->pause = 0;
0518 
0519     ctl = sungem_phy_read(phy, MII_BMCR);
0520     ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
0521 
0522     /* First reset the PHY */
0523     sungem_phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
0524 
0525     /* Select speed & duplex */
0526     switch(speed) {
0527     case SPEED_10:
0528         break;
0529     case SPEED_100:
0530         ctl |= BMCR_SPEED100;
0531         break;
0532     case SPEED_1000:
0533         ctl |= BMCR_SPD2;
0534     }
0535     if (fd == DUPLEX_FULL)
0536         ctl |= BMCR_FULLDPLX;
0537 
0538     // XXX Should we set the sungem to GII now on 1000BT ?
0539 
0540     sungem_phy_write(phy, MII_BMCR, ctl);
0541 
0542     return 0;
0543 }
0544 
0545 static int bcm54xx_read_link(struct mii_phy *phy)
0546 {
0547     int link_mode;
0548     u16 val;
0549 
0550     if (phy->autoneg) {
0551             val = sungem_phy_read(phy, MII_BCM5400_AUXSTATUS);
0552         link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
0553                  MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
0554         phy->duplex = phy_BCM5400_link_table[link_mode][0] ?
0555             DUPLEX_FULL : DUPLEX_HALF;
0556         phy->speed = phy_BCM5400_link_table[link_mode][2] ?
0557                 SPEED_1000 :
0558                 (phy_BCM5400_link_table[link_mode][1] ?
0559                  SPEED_100 : SPEED_10);
0560         val = sungem_phy_read(phy, MII_LPA);
0561         phy->pause = (phy->duplex == DUPLEX_FULL) &&
0562             ((val & LPA_PAUSE) != 0);
0563     }
0564     /* On non-aneg, we assume what we put in BMCR is the speed,
0565      * though magic-aneg shouldn't prevent this case from occurring
0566      */
0567 
0568     return 0;
0569 }
0570 
0571 static int marvell88e1111_init(struct mii_phy* phy)
0572 {
0573     u16 rev;
0574 
0575     /* magic init sequence for rev 0 */
0576     rev = sungem_phy_read(phy, MII_PHYSID2) & 0x000f;
0577     if (rev == 0) {
0578         sungem_phy_write(phy, 0x1d, 0x000a);
0579         sungem_phy_write(phy, 0x1e, 0x0821);
0580 
0581         sungem_phy_write(phy, 0x1d, 0x0006);
0582         sungem_phy_write(phy, 0x1e, 0x8600);
0583 
0584         sungem_phy_write(phy, 0x1d, 0x000b);
0585         sungem_phy_write(phy, 0x1e, 0x0100);
0586 
0587         sungem_phy_write(phy, 0x1d, 0x0004);
0588         sungem_phy_write(phy, 0x1e, 0x4850);
0589     }
0590     return 0;
0591 }
0592 
0593 #define BCM5421_MODE_MASK   (1 << 5)
0594 
0595 static int bcm5421_poll_link(struct mii_phy* phy)
0596 {
0597     u32 phy_reg;
0598     int mode;
0599 
0600     /* find out in what mode we are */
0601     sungem_phy_write(phy, MII_NCONFIG, 0x1000);
0602     phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0603 
0604     mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
0605 
0606     if ( mode == BCM54XX_COPPER)
0607         return genmii_poll_link(phy);
0608 
0609     /* try to find out whether we have a link */
0610     sungem_phy_write(phy, MII_NCONFIG, 0x2000);
0611     phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0612 
0613     if (phy_reg & 0x0020)
0614         return 0;
0615     else
0616         return 1;
0617 }
0618 
0619 static int bcm5421_read_link(struct mii_phy* phy)
0620 {
0621     u32 phy_reg;
0622     int mode;
0623 
0624     /* find out in what mode we are */
0625     sungem_phy_write(phy, MII_NCONFIG, 0x1000);
0626     phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0627 
0628     mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
0629 
0630     if ( mode == BCM54XX_COPPER)
0631         return bcm54xx_read_link(phy);
0632 
0633     phy->speed = SPEED_1000;
0634 
0635     /* find out whether we are running half- or full duplex */
0636     sungem_phy_write(phy, MII_NCONFIG, 0x2000);
0637     phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0638 
0639     if ( (phy_reg & 0x0080) >> 7)
0640         phy->duplex |=  DUPLEX_HALF;
0641     else
0642         phy->duplex |=  DUPLEX_FULL;
0643 
0644     return 0;
0645 }
0646 
0647 static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
0648 {
0649     /* enable fiber mode */
0650     sungem_phy_write(phy, MII_NCONFIG, 0x9020);
0651     /* LEDs active in both modes, autosense prio = fiber */
0652     sungem_phy_write(phy, MII_NCONFIG, 0x945f);
0653 
0654     if (!autoneg) {
0655         /* switch off fibre autoneg */
0656         sungem_phy_write(phy, MII_NCONFIG, 0xfc01);
0657         sungem_phy_write(phy, 0x0b, 0x0004);
0658     }
0659 
0660     phy->autoneg = autoneg;
0661 
0662     return 0;
0663 }
0664 
0665 #define BCM5461_FIBER_LINK  (1 << 2)
0666 #define BCM5461_MODE_MASK   (3 << 1)
0667 
0668 static int bcm5461_poll_link(struct mii_phy* phy)
0669 {
0670     u32 phy_reg;
0671     int mode;
0672 
0673     /* find out in what mode we are */
0674     sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
0675     phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0676 
0677     mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
0678 
0679     if ( mode == BCM54XX_COPPER)
0680         return genmii_poll_link(phy);
0681 
0682     /* find out whether we have a link */
0683     sungem_phy_write(phy, MII_NCONFIG, 0x7000);
0684     phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0685 
0686     if (phy_reg & BCM5461_FIBER_LINK)
0687         return 1;
0688     else
0689         return 0;
0690 }
0691 
0692 #define BCM5461_FIBER_DUPLEX    (1 << 3)
0693 
0694 static int bcm5461_read_link(struct mii_phy* phy)
0695 {
0696     u32 phy_reg;
0697     int mode;
0698 
0699     /* find out in what mode we are */
0700     sungem_phy_write(phy, MII_NCONFIG, 0x7c00);
0701     phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0702 
0703     mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
0704 
0705     if ( mode == BCM54XX_COPPER) {
0706         return bcm54xx_read_link(phy);
0707     }
0708 
0709     phy->speed = SPEED_1000;
0710 
0711     /* find out whether we are running half- or full duplex */
0712     sungem_phy_write(phy, MII_NCONFIG, 0x7000);
0713     phy_reg = sungem_phy_read(phy, MII_NCONFIG);
0714 
0715     if (phy_reg & BCM5461_FIBER_DUPLEX)
0716         phy->duplex |=  DUPLEX_FULL;
0717     else
0718         phy->duplex |=  DUPLEX_HALF;
0719 
0720     return 0;
0721 }
0722 
0723 static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
0724 {
0725     /* select fiber mode, enable 1000 base-X registers */
0726     sungem_phy_write(phy, MII_NCONFIG, 0xfc0b);
0727 
0728     if (autoneg) {
0729         /* enable fiber with no autonegotiation */
0730         sungem_phy_write(phy, MII_ADVERTISE, 0x01e0);
0731         sungem_phy_write(phy, MII_BMCR, 0x1140);
0732     } else {
0733         /* enable fiber with autonegotiation */
0734         sungem_phy_write(phy, MII_BMCR, 0x0140);
0735     }
0736 
0737     phy->autoneg = autoneg;
0738 
0739     return 0;
0740 }
0741 
0742 static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
0743 {
0744     u16 ctl, adv;
0745 
0746     phy->autoneg = 1;
0747     phy->speed = SPEED_10;
0748     phy->duplex = DUPLEX_HALF;
0749     phy->pause = 0;
0750     phy->advertising = advertise;
0751 
0752     /* Setup standard advertise */
0753     adv = sungem_phy_read(phy, MII_ADVERTISE);
0754     adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
0755     if (advertise & ADVERTISED_10baseT_Half)
0756         adv |= ADVERTISE_10HALF;
0757     if (advertise & ADVERTISED_10baseT_Full)
0758         adv |= ADVERTISE_10FULL;
0759     if (advertise & ADVERTISED_100baseT_Half)
0760         adv |= ADVERTISE_100HALF;
0761     if (advertise & ADVERTISED_100baseT_Full)
0762         adv |= ADVERTISE_100FULL;
0763     if (advertise & ADVERTISED_Pause)
0764         adv |= ADVERTISE_PAUSE_CAP;
0765     if (advertise & ADVERTISED_Asym_Pause)
0766         adv |= ADVERTISE_PAUSE_ASYM;
0767     sungem_phy_write(phy, MII_ADVERTISE, adv);
0768 
0769     /* Setup 1000BT advertise & enable crossover detect
0770      * XXX How do we advertise 1000BT ? Darwin source is
0771      * confusing here, they read from specific control and
0772      * write to control... Someone has specs for those
0773      * beasts ?
0774      */
0775     adv = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
0776     adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
0777     adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
0778             MII_1000BASETCONTROL_HALFDUPLEXCAP);
0779     if (advertise & SUPPORTED_1000baseT_Half)
0780         adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
0781     if (advertise & SUPPORTED_1000baseT_Full)
0782         adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
0783     sungem_phy_write(phy, MII_1000BASETCONTROL, adv);
0784 
0785     /* Start/Restart aneg */
0786     ctl = sungem_phy_read(phy, MII_BMCR);
0787     ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
0788     sungem_phy_write(phy, MII_BMCR, ctl);
0789 
0790     return 0;
0791 }
0792 
0793 static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
0794 {
0795     u16 ctl, ctl2;
0796 
0797     phy->autoneg = 0;
0798     phy->speed = speed;
0799     phy->duplex = fd;
0800     phy->pause = 0;
0801 
0802     ctl = sungem_phy_read(phy, MII_BMCR);
0803     ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
0804     ctl |= BMCR_RESET;
0805 
0806     /* Select speed & duplex */
0807     switch(speed) {
0808     case SPEED_10:
0809         break;
0810     case SPEED_100:
0811         ctl |= BMCR_SPEED100;
0812         break;
0813     /* I'm not sure about the one below, again, Darwin source is
0814      * quite confusing and I lack chip specs
0815      */
0816     case SPEED_1000:
0817         ctl |= BMCR_SPD2;
0818     }
0819     if (fd == DUPLEX_FULL)
0820         ctl |= BMCR_FULLDPLX;
0821 
0822     /* Disable crossover. Again, the way Apple does it is strange,
0823      * though I don't assume they are wrong ;)
0824      */
0825     ctl2 = sungem_phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
0826     ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
0827         MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
0828         MII_1000BASETCONTROL_FULLDUPLEXCAP |
0829         MII_1000BASETCONTROL_HALFDUPLEXCAP);
0830     if (speed == SPEED_1000)
0831         ctl2 |= (fd == DUPLEX_FULL) ?
0832             MII_1000BASETCONTROL_FULLDUPLEXCAP :
0833             MII_1000BASETCONTROL_HALFDUPLEXCAP;
0834     sungem_phy_write(phy, MII_1000BASETCONTROL, ctl2);
0835 
0836     // XXX Should we set the sungem to GII now on 1000BT ?
0837 
0838     sungem_phy_write(phy, MII_BMCR, ctl);
0839 
0840     return 0;
0841 }
0842 
0843 static int marvell_read_link(struct mii_phy *phy)
0844 {
0845     u16 status, pmask;
0846 
0847     if (phy->autoneg) {
0848         status = sungem_phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
0849         if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
0850             return -EAGAIN;
0851         if (status & MII_M1011_PHY_SPEC_STATUS_1000)
0852             phy->speed = SPEED_1000;
0853         else if (status & MII_M1011_PHY_SPEC_STATUS_100)
0854             phy->speed = SPEED_100;
0855         else
0856             phy->speed = SPEED_10;
0857         if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
0858             phy->duplex = DUPLEX_FULL;
0859         else
0860             phy->duplex = DUPLEX_HALF;
0861         pmask = MII_M1011_PHY_SPEC_STATUS_TX_PAUSE |
0862             MII_M1011_PHY_SPEC_STATUS_RX_PAUSE;
0863         phy->pause = (status & pmask) == pmask;
0864     }
0865     /* On non-aneg, we assume what we put in BMCR is the speed,
0866      * though magic-aneg shouldn't prevent this case from occurring
0867      */
0868 
0869     return 0;
0870 }
0871 
0872 #define MII_BASIC_FEATURES \
0873     (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |  \
0874      SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |    \
0875      SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | \
0876      SUPPORTED_Pause)
0877 
0878 /* On gigabit capable PHYs, we advertise Pause support but not asym pause
0879  * support for now as I'm not sure it's supported and Darwin doesn't do
0880  * it neither. --BenH.
0881  */
0882 #define MII_GBIT_FEATURES \
0883     (MII_BASIC_FEATURES |   \
0884      SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
0885 
0886 /* Broadcom BCM 5201 */
0887 static const struct mii_phy_ops bcm5201_phy_ops = {
0888     .init       = bcm5201_init,
0889     .suspend    = bcm5201_suspend,
0890     .setup_aneg = genmii_setup_aneg,
0891     .setup_forced   = genmii_setup_forced,
0892     .poll_link  = genmii_poll_link,
0893     .read_link  = genmii_read_link,
0894 };
0895 
0896 static struct mii_phy_def bcm5201_phy_def = {
0897     .phy_id     = 0x00406210,
0898     .phy_id_mask    = 0xfffffff0,
0899     .name       = "BCM5201",
0900     .features   = MII_BASIC_FEATURES,
0901     .magic_aneg = 1,
0902     .ops        = &bcm5201_phy_ops
0903 };
0904 
0905 /* Broadcom BCM 5221 */
0906 static const struct mii_phy_ops bcm5221_phy_ops = {
0907     .suspend    = bcm5221_suspend,
0908     .init       = bcm5221_init,
0909     .setup_aneg = genmii_setup_aneg,
0910     .setup_forced   = genmii_setup_forced,
0911     .poll_link  = genmii_poll_link,
0912     .read_link  = genmii_read_link,
0913 };
0914 
0915 static struct mii_phy_def bcm5221_phy_def = {
0916     .phy_id     = 0x004061e0,
0917     .phy_id_mask    = 0xfffffff0,
0918     .name       = "BCM5221",
0919     .features   = MII_BASIC_FEATURES,
0920     .magic_aneg = 1,
0921     .ops        = &bcm5221_phy_ops
0922 };
0923 
0924 /* Broadcom BCM 5241 */
0925 static const struct mii_phy_ops bcm5241_phy_ops = {
0926     .suspend    = bcm5241_suspend,
0927     .init       = bcm5241_init,
0928     .setup_aneg = genmii_setup_aneg,
0929     .setup_forced   = genmii_setup_forced,
0930     .poll_link  = genmii_poll_link,
0931     .read_link  = genmii_read_link,
0932 };
0933 static struct mii_phy_def bcm5241_phy_def = {
0934     .phy_id     = 0x0143bc30,
0935     .phy_id_mask    = 0xfffffff0,
0936     .name       = "BCM5241",
0937     .features   = MII_BASIC_FEATURES,
0938     .magic_aneg = 1,
0939     .ops        = &bcm5241_phy_ops
0940 };
0941 
0942 /* Broadcom BCM 5400 */
0943 static const struct mii_phy_ops bcm5400_phy_ops = {
0944     .init       = bcm5400_init,
0945     .suspend    = bcm5400_suspend,
0946     .setup_aneg = bcm54xx_setup_aneg,
0947     .setup_forced   = bcm54xx_setup_forced,
0948     .poll_link  = genmii_poll_link,
0949     .read_link  = bcm54xx_read_link,
0950 };
0951 
0952 static struct mii_phy_def bcm5400_phy_def = {
0953     .phy_id     = 0x00206040,
0954     .phy_id_mask    = 0xfffffff0,
0955     .name       = "BCM5400",
0956     .features   = MII_GBIT_FEATURES,
0957     .magic_aneg = 1,
0958     .ops        = &bcm5400_phy_ops
0959 };
0960 
0961 /* Broadcom BCM 5401 */
0962 static const struct mii_phy_ops bcm5401_phy_ops = {
0963     .init       = bcm5401_init,
0964     .suspend    = bcm5401_suspend,
0965     .setup_aneg = bcm54xx_setup_aneg,
0966     .setup_forced   = bcm54xx_setup_forced,
0967     .poll_link  = genmii_poll_link,
0968     .read_link  = bcm54xx_read_link,
0969 };
0970 
0971 static struct mii_phy_def bcm5401_phy_def = {
0972     .phy_id     = 0x00206050,
0973     .phy_id_mask    = 0xfffffff0,
0974     .name       = "BCM5401",
0975     .features   = MII_GBIT_FEATURES,
0976     .magic_aneg = 1,
0977     .ops        = &bcm5401_phy_ops
0978 };
0979 
0980 /* Broadcom BCM 5411 */
0981 static const struct mii_phy_ops bcm5411_phy_ops = {
0982     .init       = bcm5411_init,
0983     .suspend    = generic_suspend,
0984     .setup_aneg = bcm54xx_setup_aneg,
0985     .setup_forced   = bcm54xx_setup_forced,
0986     .poll_link  = genmii_poll_link,
0987     .read_link  = bcm54xx_read_link,
0988 };
0989 
0990 static struct mii_phy_def bcm5411_phy_def = {
0991     .phy_id     = 0x00206070,
0992     .phy_id_mask    = 0xfffffff0,
0993     .name       = "BCM5411",
0994     .features   = MII_GBIT_FEATURES,
0995     .magic_aneg = 1,
0996     .ops        = &bcm5411_phy_ops
0997 };
0998 
0999 /* Broadcom BCM 5421 */
1000 static const struct mii_phy_ops bcm5421_phy_ops = {
1001     .init       = bcm5421_init,
1002     .suspend    = generic_suspend,
1003     .setup_aneg = bcm54xx_setup_aneg,
1004     .setup_forced   = bcm54xx_setup_forced,
1005     .poll_link  = bcm5421_poll_link,
1006     .read_link  = bcm5421_read_link,
1007     .enable_fiber   = bcm5421_enable_fiber,
1008 };
1009 
1010 static struct mii_phy_def bcm5421_phy_def = {
1011     .phy_id     = 0x002060e0,
1012     .phy_id_mask    = 0xfffffff0,
1013     .name       = "BCM5421",
1014     .features   = MII_GBIT_FEATURES,
1015     .magic_aneg = 1,
1016     .ops        = &bcm5421_phy_ops
1017 };
1018 
1019 /* Broadcom BCM 5421 built-in K2 */
1020 static const struct mii_phy_ops bcm5421k2_phy_ops = {
1021     .init       = bcm5421_init,
1022     .suspend    = generic_suspend,
1023     .setup_aneg = bcm54xx_setup_aneg,
1024     .setup_forced   = bcm54xx_setup_forced,
1025     .poll_link  = genmii_poll_link,
1026     .read_link  = bcm54xx_read_link,
1027 };
1028 
1029 static struct mii_phy_def bcm5421k2_phy_def = {
1030     .phy_id     = 0x002062e0,
1031     .phy_id_mask    = 0xfffffff0,
1032     .name       = "BCM5421-K2",
1033     .features   = MII_GBIT_FEATURES,
1034     .magic_aneg = 1,
1035     .ops        = &bcm5421k2_phy_ops
1036 };
1037 
1038 static const struct mii_phy_ops bcm5461_phy_ops = {
1039     .init       = bcm5421_init,
1040     .suspend    = generic_suspend,
1041     .setup_aneg = bcm54xx_setup_aneg,
1042     .setup_forced   = bcm54xx_setup_forced,
1043     .poll_link  = bcm5461_poll_link,
1044     .read_link  = bcm5461_read_link,
1045     .enable_fiber   = bcm5461_enable_fiber,
1046 };
1047 
1048 static struct mii_phy_def bcm5461_phy_def = {
1049     .phy_id     = 0x002060c0,
1050     .phy_id_mask    = 0xfffffff0,
1051     .name       = "BCM5461",
1052     .features   = MII_GBIT_FEATURES,
1053     .magic_aneg = 1,
1054     .ops        = &bcm5461_phy_ops
1055 };
1056 
1057 /* Broadcom BCM 5462 built-in Vesta */
1058 static const struct mii_phy_ops bcm5462V_phy_ops = {
1059     .init       = bcm5421_init,
1060     .suspend    = generic_suspend,
1061     .setup_aneg = bcm54xx_setup_aneg,
1062     .setup_forced   = bcm54xx_setup_forced,
1063     .poll_link  = genmii_poll_link,
1064     .read_link  = bcm54xx_read_link,
1065 };
1066 
1067 static struct mii_phy_def bcm5462V_phy_def = {
1068     .phy_id     = 0x002060d0,
1069     .phy_id_mask    = 0xfffffff0,
1070     .name       = "BCM5462-Vesta",
1071     .features   = MII_GBIT_FEATURES,
1072     .magic_aneg = 1,
1073     .ops        = &bcm5462V_phy_ops
1074 };
1075 
1076 /* Marvell 88E1101 amd 88E1111 */
1077 static const struct mii_phy_ops marvell88e1101_phy_ops = {
1078     .suspend    = generic_suspend,
1079     .setup_aneg = marvell_setup_aneg,
1080     .setup_forced   = marvell_setup_forced,
1081     .poll_link  = genmii_poll_link,
1082     .read_link  = marvell_read_link
1083 };
1084 
1085 static const struct mii_phy_ops marvell88e1111_phy_ops = {
1086     .init       = marvell88e1111_init,
1087     .suspend    = generic_suspend,
1088     .setup_aneg = marvell_setup_aneg,
1089     .setup_forced   = marvell_setup_forced,
1090     .poll_link  = genmii_poll_link,
1091     .read_link  = marvell_read_link
1092 };
1093 
1094 /* two revs in darwin for the 88e1101 ... I could use a datasheet
1095  * to get the proper names...
1096  */
1097 static struct mii_phy_def marvell88e1101v1_phy_def = {
1098     .phy_id     = 0x01410c20,
1099     .phy_id_mask    = 0xfffffff0,
1100     .name       = "Marvell 88E1101v1",
1101     .features   = MII_GBIT_FEATURES,
1102     .magic_aneg = 1,
1103     .ops        = &marvell88e1101_phy_ops
1104 };
1105 static struct mii_phy_def marvell88e1101v2_phy_def = {
1106     .phy_id     = 0x01410c60,
1107     .phy_id_mask    = 0xfffffff0,
1108     .name       = "Marvell 88E1101v2",
1109     .features   = MII_GBIT_FEATURES,
1110     .magic_aneg = 1,
1111     .ops        = &marvell88e1101_phy_ops
1112 };
1113 static struct mii_phy_def marvell88e1111_phy_def = {
1114     .phy_id     = 0x01410cc0,
1115     .phy_id_mask    = 0xfffffff0,
1116     .name       = "Marvell 88E1111",
1117     .features   = MII_GBIT_FEATURES,
1118     .magic_aneg = 1,
1119     .ops        = &marvell88e1111_phy_ops
1120 };
1121 
1122 /* Generic implementation for most 10/100 PHYs */
1123 static const struct mii_phy_ops generic_phy_ops = {
1124     .setup_aneg = genmii_setup_aneg,
1125     .setup_forced   = genmii_setup_forced,
1126     .poll_link  = genmii_poll_link,
1127     .read_link  = genmii_read_link
1128 };
1129 
1130 static struct mii_phy_def genmii_phy_def = {
1131     .phy_id     = 0x00000000,
1132     .phy_id_mask    = 0x00000000,
1133     .name       = "Generic MII",
1134     .features   = MII_BASIC_FEATURES,
1135     .magic_aneg = 0,
1136     .ops        = &generic_phy_ops
1137 };
1138 
1139 static struct mii_phy_def* mii_phy_table[] = {
1140     &bcm5201_phy_def,
1141     &bcm5221_phy_def,
1142     &bcm5241_phy_def,
1143     &bcm5400_phy_def,
1144     &bcm5401_phy_def,
1145     &bcm5411_phy_def,
1146     &bcm5421_phy_def,
1147     &bcm5421k2_phy_def,
1148     &bcm5461_phy_def,
1149     &bcm5462V_phy_def,
1150     &marvell88e1101v1_phy_def,
1151     &marvell88e1101v2_phy_def,
1152     &marvell88e1111_phy_def,
1153     &genmii_phy_def,
1154     NULL
1155 };
1156 
1157 int sungem_phy_probe(struct mii_phy *phy, int mii_id)
1158 {
1159     int rc;
1160     u32 id;
1161     struct mii_phy_def* def;
1162     int i;
1163 
1164     /* We do not reset the mii_phy structure as the driver
1165      * may re-probe the PHY regulary
1166      */
1167     phy->mii_id = mii_id;
1168 
1169     /* Take PHY out of isloate mode and reset it. */
1170     rc = reset_one_mii_phy(phy, mii_id);
1171     if (rc)
1172         goto fail;
1173 
1174     /* Read ID and find matching entry */
1175     id = (sungem_phy_read(phy, MII_PHYSID1) << 16 | sungem_phy_read(phy, MII_PHYSID2));
1176     printk(KERN_DEBUG KBUILD_MODNAME ": " "PHY ID: %x, addr: %x\n",
1177            id, mii_id);
1178     for (i=0; (def = mii_phy_table[i]) != NULL; i++)
1179         if ((id & def->phy_id_mask) == def->phy_id)
1180             break;
1181     /* Should never be NULL (we have a generic entry), but... */
1182     if (def == NULL)
1183         goto fail;
1184 
1185     phy->def = def;
1186 
1187     return 0;
1188 fail:
1189     phy->speed = 0;
1190     phy->duplex = 0;
1191     phy->pause = 0;
1192     phy->advertising = 0;
1193     return -ENODEV;
1194 }
1195 
1196 EXPORT_SYMBOL(sungem_phy_probe);
1197 MODULE_LICENSE("GPL");