1*5f184715SAndy Fleming /* 2*5f184715SAndy Fleming * Generic PHY Management code 3*5f184715SAndy Fleming * 4*5f184715SAndy Fleming * This program is free software; you can redistribute it and/or 5*5f184715SAndy Fleming * modify it under the terms of the GNU General Public License as 6*5f184715SAndy Fleming * published by the Free Software Foundation; either version 2 of 7*5f184715SAndy Fleming * the License, or (at your option) any later version. 8*5f184715SAndy Fleming * 9*5f184715SAndy Fleming * This program is distributed in the hope that it will be useful, 10*5f184715SAndy Fleming * but WITHOUT ANY WARRANTY; without even the implied warranty of 11*5f184715SAndy Fleming * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12*5f184715SAndy Fleming * GNU General Public License for more details. 13*5f184715SAndy Fleming * 14*5f184715SAndy Fleming * You should have received a copy of the GNU General Public License 15*5f184715SAndy Fleming * along with this program; if not, write to the Free Software 16*5f184715SAndy Fleming * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 17*5f184715SAndy Fleming * MA 02111-1307 USA 18*5f184715SAndy Fleming * 19*5f184715SAndy Fleming * 20*5f184715SAndy Fleming * Copyright 2011 Freescale Semiconductor, Inc. 21*5f184715SAndy Fleming * author Andy Fleming 22*5f184715SAndy Fleming * 23*5f184715SAndy Fleming * Based loosely off of Linux's PHY Lib 24*5f184715SAndy Fleming */ 25*5f184715SAndy Fleming 26*5f184715SAndy Fleming #include <config.h> 27*5f184715SAndy Fleming #include <common.h> 28*5f184715SAndy Fleming #include <malloc.h> 29*5f184715SAndy Fleming #include <net.h> 30*5f184715SAndy Fleming #include <command.h> 31*5f184715SAndy Fleming #include <miiphy.h> 32*5f184715SAndy Fleming #include <phy.h> 33*5f184715SAndy Fleming #include <errno.h> 34*5f184715SAndy Fleming 35*5f184715SAndy Fleming /* Generic PHY support and helper functions */ 36*5f184715SAndy Fleming 37*5f184715SAndy Fleming /** 38*5f184715SAndy Fleming * genphy_config_advert - sanitize and advertise auto-negotation parameters 39*5f184715SAndy Fleming * @phydev: target phy_device struct 40*5f184715SAndy Fleming * 41*5f184715SAndy Fleming * Description: Writes MII_ADVERTISE with the appropriate values, 42*5f184715SAndy Fleming * after sanitizing the values to make sure we only advertise 43*5f184715SAndy Fleming * what is supported. Returns < 0 on error, 0 if the PHY's advertisement 44*5f184715SAndy Fleming * hasn't changed, and > 0 if it has changed. 45*5f184715SAndy Fleming */ 46*5f184715SAndy Fleming int genphy_config_advert(struct phy_device *phydev) 47*5f184715SAndy Fleming { 48*5f184715SAndy Fleming u32 advertise; 49*5f184715SAndy Fleming int oldadv, adv; 50*5f184715SAndy Fleming int err, changed = 0; 51*5f184715SAndy Fleming 52*5f184715SAndy Fleming /* Only allow advertising what 53*5f184715SAndy Fleming * this PHY supports */ 54*5f184715SAndy Fleming phydev->advertising &= phydev->supported; 55*5f184715SAndy Fleming advertise = phydev->advertising; 56*5f184715SAndy Fleming 57*5f184715SAndy Fleming /* Setup standard advertisement */ 58*5f184715SAndy Fleming oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE); 59*5f184715SAndy Fleming 60*5f184715SAndy Fleming if (adv < 0) 61*5f184715SAndy Fleming return adv; 62*5f184715SAndy Fleming 63*5f184715SAndy Fleming adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | 64*5f184715SAndy Fleming ADVERTISE_PAUSE_ASYM); 65*5f184715SAndy Fleming if (advertise & ADVERTISED_10baseT_Half) 66*5f184715SAndy Fleming adv |= ADVERTISE_10HALF; 67*5f184715SAndy Fleming if (advertise & ADVERTISED_10baseT_Full) 68*5f184715SAndy Fleming adv |= ADVERTISE_10FULL; 69*5f184715SAndy Fleming if (advertise & ADVERTISED_100baseT_Half) 70*5f184715SAndy Fleming adv |= ADVERTISE_100HALF; 71*5f184715SAndy Fleming if (advertise & ADVERTISED_100baseT_Full) 72*5f184715SAndy Fleming adv |= ADVERTISE_100FULL; 73*5f184715SAndy Fleming if (advertise & ADVERTISED_Pause) 74*5f184715SAndy Fleming adv |= ADVERTISE_PAUSE_CAP; 75*5f184715SAndy Fleming if (advertise & ADVERTISED_Asym_Pause) 76*5f184715SAndy Fleming adv |= ADVERTISE_PAUSE_ASYM; 77*5f184715SAndy Fleming 78*5f184715SAndy Fleming if (adv != oldadv) { 79*5f184715SAndy Fleming err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv); 80*5f184715SAndy Fleming 81*5f184715SAndy Fleming if (err < 0) 82*5f184715SAndy Fleming return err; 83*5f184715SAndy Fleming changed = 1; 84*5f184715SAndy Fleming } 85*5f184715SAndy Fleming 86*5f184715SAndy Fleming /* Configure gigabit if it's supported */ 87*5f184715SAndy Fleming if (phydev->supported & (SUPPORTED_1000baseT_Half | 88*5f184715SAndy Fleming SUPPORTED_1000baseT_Full)) { 89*5f184715SAndy Fleming oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000); 90*5f184715SAndy Fleming 91*5f184715SAndy Fleming if (adv < 0) 92*5f184715SAndy Fleming return adv; 93*5f184715SAndy Fleming 94*5f184715SAndy Fleming adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); 95*5f184715SAndy Fleming if (advertise & SUPPORTED_1000baseT_Half) 96*5f184715SAndy Fleming adv |= ADVERTISE_1000HALF; 97*5f184715SAndy Fleming if (advertise & SUPPORTED_1000baseT_Full) 98*5f184715SAndy Fleming adv |= ADVERTISE_1000FULL; 99*5f184715SAndy Fleming 100*5f184715SAndy Fleming if (adv != oldadv) { 101*5f184715SAndy Fleming err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, 102*5f184715SAndy Fleming adv); 103*5f184715SAndy Fleming 104*5f184715SAndy Fleming if (err < 0) 105*5f184715SAndy Fleming return err; 106*5f184715SAndy Fleming changed = 1; 107*5f184715SAndy Fleming } 108*5f184715SAndy Fleming } 109*5f184715SAndy Fleming 110*5f184715SAndy Fleming return changed; 111*5f184715SAndy Fleming } 112*5f184715SAndy Fleming 113*5f184715SAndy Fleming 114*5f184715SAndy Fleming /** 115*5f184715SAndy Fleming * genphy_setup_forced - configures/forces speed/duplex from @phydev 116*5f184715SAndy Fleming * @phydev: target phy_device struct 117*5f184715SAndy Fleming * 118*5f184715SAndy Fleming * Description: Configures MII_BMCR to force speed/duplex 119*5f184715SAndy Fleming * to the values in phydev. Assumes that the values are valid. 120*5f184715SAndy Fleming */ 121*5f184715SAndy Fleming int genphy_setup_forced(struct phy_device *phydev) 122*5f184715SAndy Fleming { 123*5f184715SAndy Fleming int err; 124*5f184715SAndy Fleming int ctl = 0; 125*5f184715SAndy Fleming 126*5f184715SAndy Fleming phydev->pause = phydev->asym_pause = 0; 127*5f184715SAndy Fleming 128*5f184715SAndy Fleming if (SPEED_1000 == phydev->speed) 129*5f184715SAndy Fleming ctl |= BMCR_SPEED1000; 130*5f184715SAndy Fleming else if (SPEED_100 == phydev->speed) 131*5f184715SAndy Fleming ctl |= BMCR_SPEED100; 132*5f184715SAndy Fleming 133*5f184715SAndy Fleming if (DUPLEX_FULL == phydev->duplex) 134*5f184715SAndy Fleming ctl |= BMCR_FULLDPLX; 135*5f184715SAndy Fleming 136*5f184715SAndy Fleming err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl); 137*5f184715SAndy Fleming 138*5f184715SAndy Fleming return err; 139*5f184715SAndy Fleming } 140*5f184715SAndy Fleming 141*5f184715SAndy Fleming 142*5f184715SAndy Fleming /** 143*5f184715SAndy Fleming * genphy_restart_aneg - Enable and Restart Autonegotiation 144*5f184715SAndy Fleming * @phydev: target phy_device struct 145*5f184715SAndy Fleming */ 146*5f184715SAndy Fleming int genphy_restart_aneg(struct phy_device *phydev) 147*5f184715SAndy Fleming { 148*5f184715SAndy Fleming int ctl; 149*5f184715SAndy Fleming 150*5f184715SAndy Fleming ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 151*5f184715SAndy Fleming 152*5f184715SAndy Fleming if (ctl < 0) 153*5f184715SAndy Fleming return ctl; 154*5f184715SAndy Fleming 155*5f184715SAndy Fleming ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); 156*5f184715SAndy Fleming 157*5f184715SAndy Fleming /* Don't isolate the PHY if we're negotiating */ 158*5f184715SAndy Fleming ctl &= ~(BMCR_ISOLATE); 159*5f184715SAndy Fleming 160*5f184715SAndy Fleming ctl = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl); 161*5f184715SAndy Fleming 162*5f184715SAndy Fleming return ctl; 163*5f184715SAndy Fleming } 164*5f184715SAndy Fleming 165*5f184715SAndy Fleming 166*5f184715SAndy Fleming /** 167*5f184715SAndy Fleming * genphy_config_aneg - restart auto-negotiation or write BMCR 168*5f184715SAndy Fleming * @phydev: target phy_device struct 169*5f184715SAndy Fleming * 170*5f184715SAndy Fleming * Description: If auto-negotiation is enabled, we configure the 171*5f184715SAndy Fleming * advertising, and then restart auto-negotiation. If it is not 172*5f184715SAndy Fleming * enabled, then we write the BMCR. 173*5f184715SAndy Fleming */ 174*5f184715SAndy Fleming int genphy_config_aneg(struct phy_device *phydev) 175*5f184715SAndy Fleming { 176*5f184715SAndy Fleming int result; 177*5f184715SAndy Fleming 178*5f184715SAndy Fleming if (AUTONEG_ENABLE != phydev->autoneg) 179*5f184715SAndy Fleming return genphy_setup_forced(phydev); 180*5f184715SAndy Fleming 181*5f184715SAndy Fleming result = genphy_config_advert(phydev); 182*5f184715SAndy Fleming 183*5f184715SAndy Fleming if (result < 0) /* error */ 184*5f184715SAndy Fleming return result; 185*5f184715SAndy Fleming 186*5f184715SAndy Fleming if (result == 0) { 187*5f184715SAndy Fleming /* Advertisment hasn't changed, but maybe aneg was never on to 188*5f184715SAndy Fleming * begin with? Or maybe phy was isolated? */ 189*5f184715SAndy Fleming int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 190*5f184715SAndy Fleming 191*5f184715SAndy Fleming if (ctl < 0) 192*5f184715SAndy Fleming return ctl; 193*5f184715SAndy Fleming 194*5f184715SAndy Fleming if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) 195*5f184715SAndy Fleming result = 1; /* do restart aneg */ 196*5f184715SAndy Fleming } 197*5f184715SAndy Fleming 198*5f184715SAndy Fleming /* Only restart aneg if we are advertising something different 199*5f184715SAndy Fleming * than we were before. */ 200*5f184715SAndy Fleming if (result > 0) 201*5f184715SAndy Fleming result = genphy_restart_aneg(phydev); 202*5f184715SAndy Fleming 203*5f184715SAndy Fleming return result; 204*5f184715SAndy Fleming } 205*5f184715SAndy Fleming 206*5f184715SAndy Fleming /** 207*5f184715SAndy Fleming * genphy_update_link - update link status in @phydev 208*5f184715SAndy Fleming * @phydev: target phy_device struct 209*5f184715SAndy Fleming * 210*5f184715SAndy Fleming * Description: Update the value in phydev->link to reflect the 211*5f184715SAndy Fleming * current link value. In order to do this, we need to read 212*5f184715SAndy Fleming * the status register twice, keeping the second value. 213*5f184715SAndy Fleming */ 214*5f184715SAndy Fleming int genphy_update_link(struct phy_device *phydev) 215*5f184715SAndy Fleming { 216*5f184715SAndy Fleming unsigned int mii_reg; 217*5f184715SAndy Fleming 218*5f184715SAndy Fleming /* 219*5f184715SAndy Fleming * Wait if the link is up, and autonegotiation is in progress 220*5f184715SAndy Fleming * (ie - we're capable and it's not done) 221*5f184715SAndy Fleming */ 222*5f184715SAndy Fleming mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); 223*5f184715SAndy Fleming 224*5f184715SAndy Fleming /* 225*5f184715SAndy Fleming * If we already saw the link up, and it hasn't gone down, then 226*5f184715SAndy Fleming * we don't need to wait for autoneg again 227*5f184715SAndy Fleming */ 228*5f184715SAndy Fleming if (phydev->link && mii_reg & BMSR_LSTATUS) 229*5f184715SAndy Fleming return 0; 230*5f184715SAndy Fleming 231*5f184715SAndy Fleming if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) { 232*5f184715SAndy Fleming int i = 0; 233*5f184715SAndy Fleming 234*5f184715SAndy Fleming printf("%s Waiting for PHY auto negotiation to complete", 235*5f184715SAndy Fleming phydev->dev->name); 236*5f184715SAndy Fleming while (!(mii_reg & BMSR_ANEGCOMPLETE)) { 237*5f184715SAndy Fleming /* 238*5f184715SAndy Fleming * Timeout reached ? 239*5f184715SAndy Fleming */ 240*5f184715SAndy Fleming if (i > PHY_ANEG_TIMEOUT) { 241*5f184715SAndy Fleming printf(" TIMEOUT !\n"); 242*5f184715SAndy Fleming phydev->link = 0; 243*5f184715SAndy Fleming return 0; 244*5f184715SAndy Fleming } 245*5f184715SAndy Fleming 246*5f184715SAndy Fleming if (ctrlc()) { 247*5f184715SAndy Fleming puts("user interrupt!\n"); 248*5f184715SAndy Fleming phydev->link = 0; 249*5f184715SAndy Fleming return -EINTR; 250*5f184715SAndy Fleming } 251*5f184715SAndy Fleming 252*5f184715SAndy Fleming if ((i++ % 500) == 0) 253*5f184715SAndy Fleming printf("."); 254*5f184715SAndy Fleming 255*5f184715SAndy Fleming udelay(1000); /* 1 ms */ 256*5f184715SAndy Fleming mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); 257*5f184715SAndy Fleming } 258*5f184715SAndy Fleming printf(" done\n"); 259*5f184715SAndy Fleming phydev->link = 1; 260*5f184715SAndy Fleming } else { 261*5f184715SAndy Fleming /* Read the link a second time to clear the latched state */ 262*5f184715SAndy Fleming mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); 263*5f184715SAndy Fleming 264*5f184715SAndy Fleming if (mii_reg & BMSR_LSTATUS) 265*5f184715SAndy Fleming phydev->link = 1; 266*5f184715SAndy Fleming else 267*5f184715SAndy Fleming phydev->link = 0; 268*5f184715SAndy Fleming } 269*5f184715SAndy Fleming 270*5f184715SAndy Fleming return 0; 271*5f184715SAndy Fleming } 272*5f184715SAndy Fleming 273*5f184715SAndy Fleming /* 274*5f184715SAndy Fleming * Generic function which updates the speed and duplex. If 275*5f184715SAndy Fleming * autonegotiation is enabled, it uses the AND of the link 276*5f184715SAndy Fleming * partner's advertised capabilities and our advertised 277*5f184715SAndy Fleming * capabilities. If autonegotiation is disabled, we use the 278*5f184715SAndy Fleming * appropriate bits in the control register. 279*5f184715SAndy Fleming * 280*5f184715SAndy Fleming * Stolen from Linux's mii.c and phy_device.c 281*5f184715SAndy Fleming */ 282*5f184715SAndy Fleming static int genphy_parse_link(struct phy_device *phydev) 283*5f184715SAndy Fleming { 284*5f184715SAndy Fleming int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); 285*5f184715SAndy Fleming 286*5f184715SAndy Fleming /* We're using autonegotiation */ 287*5f184715SAndy Fleming if (mii_reg & BMSR_ANEGCAPABLE) { 288*5f184715SAndy Fleming u32 lpa = 0; 289*5f184715SAndy Fleming u32 gblpa = 0; 290*5f184715SAndy Fleming 291*5f184715SAndy Fleming /* Check for gigabit capability */ 292*5f184715SAndy Fleming if (mii_reg & BMSR_ERCAP) { 293*5f184715SAndy Fleming /* We want a list of states supported by 294*5f184715SAndy Fleming * both PHYs in the link 295*5f184715SAndy Fleming */ 296*5f184715SAndy Fleming gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000); 297*5f184715SAndy Fleming gblpa &= phy_read(phydev, 298*5f184715SAndy Fleming MDIO_DEVAD_NONE, MII_CTRL1000) << 2; 299*5f184715SAndy Fleming } 300*5f184715SAndy Fleming 301*5f184715SAndy Fleming /* Set the baseline so we only have to set them 302*5f184715SAndy Fleming * if they're different 303*5f184715SAndy Fleming */ 304*5f184715SAndy Fleming phydev->speed = SPEED_10; 305*5f184715SAndy Fleming phydev->duplex = DUPLEX_HALF; 306*5f184715SAndy Fleming 307*5f184715SAndy Fleming /* Check the gigabit fields */ 308*5f184715SAndy Fleming if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) { 309*5f184715SAndy Fleming phydev->speed = SPEED_1000; 310*5f184715SAndy Fleming 311*5f184715SAndy Fleming if (gblpa & PHY_1000BTSR_1000FD) 312*5f184715SAndy Fleming phydev->duplex = DUPLEX_FULL; 313*5f184715SAndy Fleming 314*5f184715SAndy Fleming /* We're done! */ 315*5f184715SAndy Fleming return 0; 316*5f184715SAndy Fleming } 317*5f184715SAndy Fleming 318*5f184715SAndy Fleming lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE); 319*5f184715SAndy Fleming lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA); 320*5f184715SAndy Fleming 321*5f184715SAndy Fleming if (lpa & (LPA_100FULL | LPA_100HALF)) { 322*5f184715SAndy Fleming phydev->speed = SPEED_100; 323*5f184715SAndy Fleming 324*5f184715SAndy Fleming if (lpa & LPA_100FULL) 325*5f184715SAndy Fleming phydev->duplex = DUPLEX_FULL; 326*5f184715SAndy Fleming 327*5f184715SAndy Fleming } else if (lpa & LPA_10FULL) 328*5f184715SAndy Fleming phydev->duplex = DUPLEX_FULL; 329*5f184715SAndy Fleming } else { 330*5f184715SAndy Fleming u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); 331*5f184715SAndy Fleming 332*5f184715SAndy Fleming phydev->speed = SPEED_10; 333*5f184715SAndy Fleming phydev->duplex = DUPLEX_HALF; 334*5f184715SAndy Fleming 335*5f184715SAndy Fleming if (bmcr & BMCR_FULLDPLX) 336*5f184715SAndy Fleming phydev->duplex = DUPLEX_FULL; 337*5f184715SAndy Fleming 338*5f184715SAndy Fleming if (bmcr & BMCR_SPEED1000) 339*5f184715SAndy Fleming phydev->speed = SPEED_1000; 340*5f184715SAndy Fleming else if (bmcr & BMCR_SPEED100) 341*5f184715SAndy Fleming phydev->speed = SPEED_100; 342*5f184715SAndy Fleming } 343*5f184715SAndy Fleming 344*5f184715SAndy Fleming return 0; 345*5f184715SAndy Fleming } 346*5f184715SAndy Fleming 347*5f184715SAndy Fleming int genphy_config(struct phy_device *phydev) 348*5f184715SAndy Fleming { 349*5f184715SAndy Fleming int val; 350*5f184715SAndy Fleming u32 features; 351*5f184715SAndy Fleming 352*5f184715SAndy Fleming /* For now, I'll claim that the generic driver supports 353*5f184715SAndy Fleming * all possible port types */ 354*5f184715SAndy Fleming features = (SUPPORTED_TP | SUPPORTED_MII 355*5f184715SAndy Fleming | SUPPORTED_AUI | SUPPORTED_FIBRE | 356*5f184715SAndy Fleming SUPPORTED_BNC); 357*5f184715SAndy Fleming 358*5f184715SAndy Fleming /* Do we support autonegotiation? */ 359*5f184715SAndy Fleming val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); 360*5f184715SAndy Fleming 361*5f184715SAndy Fleming if (val < 0) 362*5f184715SAndy Fleming return val; 363*5f184715SAndy Fleming 364*5f184715SAndy Fleming if (val & BMSR_ANEGCAPABLE) 365*5f184715SAndy Fleming features |= SUPPORTED_Autoneg; 366*5f184715SAndy Fleming 367*5f184715SAndy Fleming if (val & BMSR_100FULL) 368*5f184715SAndy Fleming features |= SUPPORTED_100baseT_Full; 369*5f184715SAndy Fleming if (val & BMSR_100HALF) 370*5f184715SAndy Fleming features |= SUPPORTED_100baseT_Half; 371*5f184715SAndy Fleming if (val & BMSR_10FULL) 372*5f184715SAndy Fleming features |= SUPPORTED_10baseT_Full; 373*5f184715SAndy Fleming if (val & BMSR_10HALF) 374*5f184715SAndy Fleming features |= SUPPORTED_10baseT_Half; 375*5f184715SAndy Fleming 376*5f184715SAndy Fleming if (val & BMSR_ESTATEN) { 377*5f184715SAndy Fleming val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS); 378*5f184715SAndy Fleming 379*5f184715SAndy Fleming if (val < 0) 380*5f184715SAndy Fleming return val; 381*5f184715SAndy Fleming 382*5f184715SAndy Fleming if (val & ESTATUS_1000_TFULL) 383*5f184715SAndy Fleming features |= SUPPORTED_1000baseT_Full; 384*5f184715SAndy Fleming if (val & ESTATUS_1000_THALF) 385*5f184715SAndy Fleming features |= SUPPORTED_1000baseT_Half; 386*5f184715SAndy Fleming } 387*5f184715SAndy Fleming 388*5f184715SAndy Fleming phydev->supported = features; 389*5f184715SAndy Fleming phydev->advertising = features; 390*5f184715SAndy Fleming 391*5f184715SAndy Fleming genphy_config_aneg(phydev); 392*5f184715SAndy Fleming 393*5f184715SAndy Fleming return 0; 394*5f184715SAndy Fleming } 395*5f184715SAndy Fleming 396*5f184715SAndy Fleming int genphy_startup(struct phy_device *phydev) 397*5f184715SAndy Fleming { 398*5f184715SAndy Fleming genphy_update_link(phydev); 399*5f184715SAndy Fleming genphy_parse_link(phydev); 400*5f184715SAndy Fleming 401*5f184715SAndy Fleming return 0; 402*5f184715SAndy Fleming } 403*5f184715SAndy Fleming 404*5f184715SAndy Fleming int genphy_shutdown(struct phy_device *phydev) 405*5f184715SAndy Fleming { 406*5f184715SAndy Fleming return 0; 407*5f184715SAndy Fleming } 408*5f184715SAndy Fleming 409*5f184715SAndy Fleming static struct phy_driver genphy_driver = { 410*5f184715SAndy Fleming .uid = 0xffffffff, 411*5f184715SAndy Fleming .mask = 0xffffffff, 412*5f184715SAndy Fleming .name = "Generic PHY", 413*5f184715SAndy Fleming .features = 0, 414*5f184715SAndy Fleming .config = genphy_config, 415*5f184715SAndy Fleming .startup = genphy_startup, 416*5f184715SAndy Fleming .shutdown = genphy_shutdown, 417*5f184715SAndy Fleming }; 418*5f184715SAndy Fleming 419*5f184715SAndy Fleming static LIST_HEAD(phy_drivers); 420*5f184715SAndy Fleming 421*5f184715SAndy Fleming int phy_init(void) 422*5f184715SAndy Fleming { 423*5f184715SAndy Fleming return 0; 424*5f184715SAndy Fleming } 425*5f184715SAndy Fleming 426*5f184715SAndy Fleming int phy_register(struct phy_driver *drv) 427*5f184715SAndy Fleming { 428*5f184715SAndy Fleming INIT_LIST_HEAD(&drv->list); 429*5f184715SAndy Fleming list_add_tail(&drv->list, &phy_drivers); 430*5f184715SAndy Fleming 431*5f184715SAndy Fleming return 0; 432*5f184715SAndy Fleming } 433*5f184715SAndy Fleming 434*5f184715SAndy Fleming int phy_probe(struct phy_device *phydev) 435*5f184715SAndy Fleming { 436*5f184715SAndy Fleming int err = 0; 437*5f184715SAndy Fleming 438*5f184715SAndy Fleming phydev->advertising = phydev->supported = phydev->drv->features; 439*5f184715SAndy Fleming phydev->mmds = phydev->drv->mmds; 440*5f184715SAndy Fleming 441*5f184715SAndy Fleming if (phydev->drv->probe) 442*5f184715SAndy Fleming err = phydev->drv->probe(phydev); 443*5f184715SAndy Fleming 444*5f184715SAndy Fleming return err; 445*5f184715SAndy Fleming } 446*5f184715SAndy Fleming 447*5f184715SAndy Fleming static struct phy_driver *generic_for_interface(phy_interface_t interface) 448*5f184715SAndy Fleming { 449*5f184715SAndy Fleming #ifdef CONFIG_PHYLIB_10G 450*5f184715SAndy Fleming if (is_10g_interface(interface)) 451*5f184715SAndy Fleming return &gen10g_driver; 452*5f184715SAndy Fleming #endif 453*5f184715SAndy Fleming 454*5f184715SAndy Fleming return &genphy_driver; 455*5f184715SAndy Fleming } 456*5f184715SAndy Fleming 457*5f184715SAndy Fleming struct phy_driver *get_phy_driver(struct phy_device *phydev, 458*5f184715SAndy Fleming phy_interface_t interface) 459*5f184715SAndy Fleming { 460*5f184715SAndy Fleming struct list_head *entry; 461*5f184715SAndy Fleming int phy_id = phydev->phy_id; 462*5f184715SAndy Fleming struct phy_driver *drv = NULL; 463*5f184715SAndy Fleming 464*5f184715SAndy Fleming list_for_each(entry, &phy_drivers) { 465*5f184715SAndy Fleming drv = list_entry(entry, struct phy_driver, list); 466*5f184715SAndy Fleming if ((drv->uid & drv->mask) == (phy_id & drv->mask)) 467*5f184715SAndy Fleming return drv; 468*5f184715SAndy Fleming } 469*5f184715SAndy Fleming 470*5f184715SAndy Fleming /* If we made it here, there's no driver for this PHY */ 471*5f184715SAndy Fleming return generic_for_interface(interface); 472*5f184715SAndy Fleming } 473*5f184715SAndy Fleming 474*5f184715SAndy Fleming struct phy_device *phy_device_create(struct mii_dev *bus, int addr, int phy_id, 475*5f184715SAndy Fleming phy_interface_t interface) 476*5f184715SAndy Fleming { 477*5f184715SAndy Fleming struct phy_device *dev; 478*5f184715SAndy Fleming 479*5f184715SAndy Fleming /* We allocate the device, and initialize the 480*5f184715SAndy Fleming * default values */ 481*5f184715SAndy Fleming dev = malloc(sizeof(*dev)); 482*5f184715SAndy Fleming if (!dev) { 483*5f184715SAndy Fleming printf("Failed to allocate PHY device for %s:%d\n", 484*5f184715SAndy Fleming bus->name, addr); 485*5f184715SAndy Fleming return NULL; 486*5f184715SAndy Fleming } 487*5f184715SAndy Fleming 488*5f184715SAndy Fleming memset(dev, 0, sizeof(*dev)); 489*5f184715SAndy Fleming 490*5f184715SAndy Fleming dev->duplex = -1; 491*5f184715SAndy Fleming dev->link = 1; 492*5f184715SAndy Fleming dev->interface = interface; 493*5f184715SAndy Fleming 494*5f184715SAndy Fleming dev->autoneg = AUTONEG_ENABLE; 495*5f184715SAndy Fleming 496*5f184715SAndy Fleming dev->addr = addr; 497*5f184715SAndy Fleming dev->phy_id = phy_id; 498*5f184715SAndy Fleming dev->bus = bus; 499*5f184715SAndy Fleming 500*5f184715SAndy Fleming dev->drv = get_phy_driver(dev, interface); 501*5f184715SAndy Fleming 502*5f184715SAndy Fleming phy_probe(dev); 503*5f184715SAndy Fleming 504*5f184715SAndy Fleming bus->phymap[addr] = dev; 505*5f184715SAndy Fleming 506*5f184715SAndy Fleming return dev; 507*5f184715SAndy Fleming } 508*5f184715SAndy Fleming 509*5f184715SAndy Fleming /** 510*5f184715SAndy Fleming * get_phy_id - reads the specified addr for its ID. 511*5f184715SAndy Fleming * @bus: the target MII bus 512*5f184715SAndy Fleming * @addr: PHY address on the MII bus 513*5f184715SAndy Fleming * @phy_id: where to store the ID retrieved. 514*5f184715SAndy Fleming * 515*5f184715SAndy Fleming * Description: Reads the ID registers of the PHY at @addr on the 516*5f184715SAndy Fleming * @bus, stores it in @phy_id and returns zero on success. 517*5f184715SAndy Fleming */ 518*5f184715SAndy Fleming int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id) 519*5f184715SAndy Fleming { 520*5f184715SAndy Fleming int phy_reg; 521*5f184715SAndy Fleming 522*5f184715SAndy Fleming /* Grab the bits from PHYIR1, and put them 523*5f184715SAndy Fleming * in the upper half */ 524*5f184715SAndy Fleming phy_reg = bus->read(bus, addr, devad, MII_PHYSID1); 525*5f184715SAndy Fleming 526*5f184715SAndy Fleming if (phy_reg < 0) 527*5f184715SAndy Fleming return -EIO; 528*5f184715SAndy Fleming 529*5f184715SAndy Fleming *phy_id = (phy_reg & 0xffff) << 16; 530*5f184715SAndy Fleming 531*5f184715SAndy Fleming /* Grab the bits from PHYIR2, and put them in the lower half */ 532*5f184715SAndy Fleming phy_reg = bus->read(bus, addr, devad, MII_PHYSID2); 533*5f184715SAndy Fleming 534*5f184715SAndy Fleming if (phy_reg < 0) 535*5f184715SAndy Fleming return -EIO; 536*5f184715SAndy Fleming 537*5f184715SAndy Fleming *phy_id |= (phy_reg & 0xffff); 538*5f184715SAndy Fleming 539*5f184715SAndy Fleming return 0; 540*5f184715SAndy Fleming } 541*5f184715SAndy Fleming 542*5f184715SAndy Fleming /** 543*5f184715SAndy Fleming * get_phy_device - reads the specified PHY device and returns its @phy_device struct 544*5f184715SAndy Fleming * @bus: the target MII bus 545*5f184715SAndy Fleming * @addr: PHY address on the MII bus 546*5f184715SAndy Fleming * 547*5f184715SAndy Fleming * Description: Reads the ID registers of the PHY at @addr on the 548*5f184715SAndy Fleming * @bus, then allocates and returns the phy_device to represent it. 549*5f184715SAndy Fleming */ 550*5f184715SAndy Fleming struct phy_device *get_phy_device(struct mii_dev *bus, int addr, 551*5f184715SAndy Fleming phy_interface_t interface) 552*5f184715SAndy Fleming { 553*5f184715SAndy Fleming u32 phy_id = 0x1fffffff; 554*5f184715SAndy Fleming int i; 555*5f184715SAndy Fleming int r; 556*5f184715SAndy Fleming 557*5f184715SAndy Fleming /* If we have one, return the existing device, with new interface */ 558*5f184715SAndy Fleming if (bus->phymap[addr]) { 559*5f184715SAndy Fleming bus->phymap[addr]->interface = interface; 560*5f184715SAndy Fleming 561*5f184715SAndy Fleming return bus->phymap[addr]; 562*5f184715SAndy Fleming } 563*5f184715SAndy Fleming 564*5f184715SAndy Fleming /* Try Standard (ie Clause 22) access */ 565*5f184715SAndy Fleming r = get_phy_id(bus, addr, MDIO_DEVAD_NONE, &phy_id); 566*5f184715SAndy Fleming if (r) 567*5f184715SAndy Fleming return NULL; 568*5f184715SAndy Fleming 569*5f184715SAndy Fleming /* If the PHY ID is mostly f's, we didn't find anything */ 570*5f184715SAndy Fleming if ((phy_id & 0x1fffffff) != 0x1fffffff) 571*5f184715SAndy Fleming return phy_device_create(bus, addr, phy_id, interface); 572*5f184715SAndy Fleming 573*5f184715SAndy Fleming /* Otherwise we have to try Clause 45 */ 574*5f184715SAndy Fleming for (i = 1; i < 5; i++) { 575*5f184715SAndy Fleming r = get_phy_id(bus, addr, i, &phy_id); 576*5f184715SAndy Fleming if (r) 577*5f184715SAndy Fleming return NULL; 578*5f184715SAndy Fleming 579*5f184715SAndy Fleming /* If the phy_id is mostly Fs, there is no device there */ 580*5f184715SAndy Fleming if ((phy_id & 0x1fffffff) != 0x1fffffff) 581*5f184715SAndy Fleming break; 582*5f184715SAndy Fleming } 583*5f184715SAndy Fleming 584*5f184715SAndy Fleming return phy_device_create(bus, addr, phy_id, interface); 585*5f184715SAndy Fleming } 586*5f184715SAndy Fleming 587*5f184715SAndy Fleming int phy_reset(struct phy_device *phydev) 588*5f184715SAndy Fleming { 589*5f184715SAndy Fleming int reg; 590*5f184715SAndy Fleming int timeout = 500; 591*5f184715SAndy Fleming int devad = MDIO_DEVAD_NONE; 592*5f184715SAndy Fleming 593*5f184715SAndy Fleming #ifdef CONFIG_PHYLIB_10G 594*5f184715SAndy Fleming /* If it's 10G, we need to issue reset through one of the MMDs */ 595*5f184715SAndy Fleming if (is_10g_interface(phydev->interface)) { 596*5f184715SAndy Fleming if (!phydev->mmds) 597*5f184715SAndy Fleming gen10g_discover_mmds(phydev); 598*5f184715SAndy Fleming 599*5f184715SAndy Fleming devad = ffs(phydev->mmds) - 1; 600*5f184715SAndy Fleming } 601*5f184715SAndy Fleming #endif 602*5f184715SAndy Fleming 603*5f184715SAndy Fleming reg = phy_read(phydev, devad, MII_BMCR); 604*5f184715SAndy Fleming if (reg < 0) { 605*5f184715SAndy Fleming debug("PHY status read failed\n"); 606*5f184715SAndy Fleming return -1; 607*5f184715SAndy Fleming } 608*5f184715SAndy Fleming 609*5f184715SAndy Fleming reg |= BMCR_RESET; 610*5f184715SAndy Fleming 611*5f184715SAndy Fleming if (phy_write(phydev, devad, MII_BMCR, reg) < 0) { 612*5f184715SAndy Fleming debug("PHY reset failed\n"); 613*5f184715SAndy Fleming return -1; 614*5f184715SAndy Fleming } 615*5f184715SAndy Fleming 616*5f184715SAndy Fleming #ifdef CONFIG_PHY_RESET_DELAY 617*5f184715SAndy Fleming udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ 618*5f184715SAndy Fleming #endif 619*5f184715SAndy Fleming /* 620*5f184715SAndy Fleming * Poll the control register for the reset bit to go to 0 (it is 621*5f184715SAndy Fleming * auto-clearing). This should happen within 0.5 seconds per the 622*5f184715SAndy Fleming * IEEE spec. 623*5f184715SAndy Fleming */ 624*5f184715SAndy Fleming while ((reg & BMCR_RESET) && timeout--) { 625*5f184715SAndy Fleming reg = phy_read(phydev, devad, MII_BMCR); 626*5f184715SAndy Fleming 627*5f184715SAndy Fleming if (reg < 0) { 628*5f184715SAndy Fleming debug("PHY status read failed\n"); 629*5f184715SAndy Fleming return -1; 630*5f184715SAndy Fleming } 631*5f184715SAndy Fleming udelay(1000); 632*5f184715SAndy Fleming } 633*5f184715SAndy Fleming 634*5f184715SAndy Fleming if (reg & BMCR_RESET) { 635*5f184715SAndy Fleming puts("PHY reset timed out\n"); 636*5f184715SAndy Fleming return -1; 637*5f184715SAndy Fleming } 638*5f184715SAndy Fleming 639*5f184715SAndy Fleming return 0; 640*5f184715SAndy Fleming } 641*5f184715SAndy Fleming 642*5f184715SAndy Fleming int miiphy_reset(const char *devname, unsigned char addr) 643*5f184715SAndy Fleming { 644*5f184715SAndy Fleming struct mii_dev *bus = miiphy_get_dev_by_name(devname); 645*5f184715SAndy Fleming struct phy_device *phydev; 646*5f184715SAndy Fleming 647*5f184715SAndy Fleming /* 648*5f184715SAndy Fleming * miiphy_reset was only used on standard PHYs, so we'll fake it here. 649*5f184715SAndy Fleming * If later code tries to connect with the right interface, this will 650*5f184715SAndy Fleming * be corrected by get_phy_device in phy_connect() 651*5f184715SAndy Fleming */ 652*5f184715SAndy Fleming phydev = get_phy_device(bus, addr, PHY_INTERFACE_MODE_MII); 653*5f184715SAndy Fleming 654*5f184715SAndy Fleming return phy_reset(phydev); 655*5f184715SAndy Fleming } 656*5f184715SAndy Fleming 657*5f184715SAndy Fleming struct phy_device *phy_connect(struct mii_dev *bus, int addr, 658*5f184715SAndy Fleming struct eth_device *dev, 659*5f184715SAndy Fleming phy_interface_t interface) 660*5f184715SAndy Fleming { 661*5f184715SAndy Fleming struct phy_device *phydev; 662*5f184715SAndy Fleming 663*5f184715SAndy Fleming /* Reset the bus */ 664*5f184715SAndy Fleming bus->reset(bus); 665*5f184715SAndy Fleming 666*5f184715SAndy Fleming /* Wait 15ms to make sure the PHY has come out of hard reset */ 667*5f184715SAndy Fleming udelay(15000); 668*5f184715SAndy Fleming 669*5f184715SAndy Fleming phydev = get_phy_device(bus, addr, interface); 670*5f184715SAndy Fleming 671*5f184715SAndy Fleming if (!phydev) { 672*5f184715SAndy Fleming printf("Could not get PHY for %s:%d\n", bus->name, addr); 673*5f184715SAndy Fleming 674*5f184715SAndy Fleming return NULL; 675*5f184715SAndy Fleming } 676*5f184715SAndy Fleming 677*5f184715SAndy Fleming /* Soft Reset the PHY */ 678*5f184715SAndy Fleming phy_reset(phydev); 679*5f184715SAndy Fleming 680*5f184715SAndy Fleming if (phydev->dev) 681*5f184715SAndy Fleming printf("%s:%d is connected to %s. Reconnecting to %s\n", 682*5f184715SAndy Fleming bus->name, addr, phydev->dev->name, dev->name); 683*5f184715SAndy Fleming 684*5f184715SAndy Fleming phydev->dev = dev; 685*5f184715SAndy Fleming 686*5f184715SAndy Fleming printf("%s connected to %s\n", dev->name, phydev->drv->name); 687*5f184715SAndy Fleming 688*5f184715SAndy Fleming return phydev; 689*5f184715SAndy Fleming } 690*5f184715SAndy Fleming 691*5f184715SAndy Fleming int phy_startup(struct phy_device *phydev) 692*5f184715SAndy Fleming { 693*5f184715SAndy Fleming if (phydev->drv->startup) 694*5f184715SAndy Fleming phydev->drv->startup(phydev); 695*5f184715SAndy Fleming 696*5f184715SAndy Fleming return 0; 697*5f184715SAndy Fleming } 698*5f184715SAndy Fleming 699*5f184715SAndy Fleming static int __board_phy_config(struct phy_device *phydev) 700*5f184715SAndy Fleming { 701*5f184715SAndy Fleming return 0; 702*5f184715SAndy Fleming } 703*5f184715SAndy Fleming 704*5f184715SAndy Fleming int board_phy_config(struct phy_device *phydev) 705*5f184715SAndy Fleming __attribute__((weak, alias("__board_phy_config"))); 706*5f184715SAndy Fleming 707*5f184715SAndy Fleming int phy_config(struct phy_device *phydev) 708*5f184715SAndy Fleming { 709*5f184715SAndy Fleming if (phydev->drv->config) 710*5f184715SAndy Fleming phydev->drv->config(phydev); 711*5f184715SAndy Fleming 712*5f184715SAndy Fleming /* Invoke an optional board-specific helper */ 713*5f184715SAndy Fleming board_phy_config(phydev); 714*5f184715SAndy Fleming 715*5f184715SAndy Fleming return 0; 716*5f184715SAndy Fleming } 717*5f184715SAndy Fleming 718*5f184715SAndy Fleming int phy_shutdown(struct phy_device *phydev) 719*5f184715SAndy Fleming { 720*5f184715SAndy Fleming if (phydev->drv->shutdown) 721*5f184715SAndy Fleming phydev->drv->shutdown(phydev); 722*5f184715SAndy Fleming 723*5f184715SAndy Fleming return 0; 724*5f184715SAndy Fleming } 725