/* Setup standard advertisement */
oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
-
if (adv < 0)
return adv;
if (phydev->supported & (SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full)) {
oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
-
if (adv < 0)
return adv;
*/
static int genphy_setup_forced(struct phy_device *phydev)
{
- int err;
int ctl = 0;
phydev->pause = phydev->asym_pause = 0;
if (DUPLEX_FULL == phydev->duplex)
ctl |= BMCR_FULLDPLX;
- err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
-
- return err;
+ return phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
}
int ctl;
ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
-
if (ctl < 0)
return ctl;
/* Don't isolate the PHY if we're negotiating */
ctl &= ~(BMCR_ISOLATE);
- ctl = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
-
- return ctl;
+ return phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl);
}
*/
int genphy_update_link(struct phy_device *phydev)
{
- unsigned int mii_reg;
+ int mii_reg;
+ int bmcr;
/*
* Wait if the link is up, and autonegotiation is in progress
* (ie - we're capable and it's not done)
*/
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+ if (mii_reg < 0)
+ return mii_reg;
/*
* If we already saw the link up, and it hasn't gone down, then
if (phydev->link && mii_reg & BMSR_LSTATUS)
return 0;
+ bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+ if (bmcr < 0)
+ return bmcr;
+
+ if (!(bmcr & BMCR_ANENABLE))
+ return 0;
+
if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
int i = 0;
udelay(1000); /* 1 ms */
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+ if (mii_reg < 0)
+ return mii_reg;
}
printf(" done\n");
phydev->link = 1;
} else {
/* Read the link a second time to clear the latched state */
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+ if (mii_reg < 0)
+ return mii_reg;
if (mii_reg & BMSR_LSTATUS)
phydev->link = 1;
{
int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
+ if (mii_reg < 0)
+ return mii_reg;
+
/* We're using autonegotiation */
if (phydev->supported & SUPPORTED_Autoneg) {
+ int ret;
u32 lpa = 0;
- int gblpa = 0;
+ u32 gblpa = 0;
u32 estatus = 0;
/* Check for gigabit capability */
/* We want a list of states supported by
* both PHYs in the link
*/
- gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000);
- if (gblpa < 0) {
+ ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000);
+ if (ret < 0) {
debug("Could not read MII_STAT1000. Ignoring gigabit capability\n");
- gblpa = 0;
+ ret = 0;
}
- gblpa &= phy_read(phydev,
- MDIO_DEVAD_NONE, MII_CTRL1000) << 2;
+ gblpa = ret;
+
+ ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
+ if (ret < 0)
+ return ret;
+ gblpa &= ret << 2;
}
/* Set the baseline so we only have to set them
return 0;
}
- lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
- lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
+ ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
+ if (ret < 0)
+ return ret;
+ lpa = ret;
+
+ ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
+ if (ret < 0)
+ return ret;
+ lpa &= ret;
if (lpa & (LPA_100FULL | LPA_100HALF)) {
phydev->speed = SPEED_100;
if ((mii_reg & BMSR_ESTATEN) && !(mii_reg & BMSR_ERCAP))
estatus = phy_read(phydev, MDIO_DEVAD_NONE,
MII_ESTATUS);
+ if (estatus < 0)
+ return estatus;
if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_XHALF |
ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
}
} else {
- u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+ int bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
+
+ if (bmcr < 0)
+ return bmcr;
phydev->speed = SPEED_10;
phydev->duplex = DUPLEX_HALF;
/* Do we support autonegotiation? */
val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
-
if (val < 0)
return val;
return generic_for_interface(interface);
}
+static int aneg_enabled(struct phy_device *phydev)
+{
+ static const char *aneg = "_aneg";
+ char varname[strlen(phydev->bus->name) + strlen(aneg) + 1];
+
+ snprintf(varname, sizeof(varname), "%s%s", phydev->bus->name, aneg);
+ return getenv_yesno(varname);
+}
+
+static int phy_get_speed(struct phy_device *phydev)
+{
+ int ret;
+ static const char *aneg = "_speed";
+ char varname[strlen(phydev->bus->name) + strlen(aneg) + 1];
+ ulong val;
+
+ snprintf(varname, sizeof(varname), "%s%s", phydev->bus->name, aneg);
+
+ val = getenv_ulong(varname, 10, 100);
+ switch (val) {
+ case 1000:
+ ret = SPEED_1000;
+ break;
+ case 100:
+ ret = SPEED_100;
+ break;
+ case 10:
+ ret = SPEED_10;
+ break;
+ default:
+ printf("Improper setting '%s' for %s; assuming 100\n",
+ getenv(varname), varname);
+ ret = SPEED_100;
+ }
+ return ret;
+}
+
+static int phy_get_duplex(struct phy_device *phydev)
+{
+ int ret = DUPLEX_FULL;
+ static const char *aneg = "_duplex";
+ char varname[strlen(phydev->bus->name) + strlen(aneg) + 4];
+ const char *val;
+
+ snprintf(varname, sizeof(varname), "%s%d%s",
+ phydev->bus->name, phydev->addr, aneg);
+
+ val = getenv(varname);
+ if (val != NULL) {
+ if (strcasecmp(val, "full") != 0) {
+ if (strcasecmp(val, "half") == 0) {
+ ret = DUPLEX_HALF;
+ } else {
+ printf("Improper setting '%s' for %s; assuming 'full'\n",
+ val, varname);
+ printf("Expected one of: 'full', 'half'\n");
+ }
+ }
+ }
+
+ return ret;
+}
+
static struct phy_device *phy_device_create(struct mii_dev *bus, int addr,
int phy_id,
phy_interface_t interface)
dev->link = 1;
dev->interface = interface;
- dev->autoneg = AUTONEG_ENABLE;
-
dev->addr = addr;
dev->phy_id = phy_id;
dev->bus = bus;
dev->drv = get_phy_driver(dev, interface);
+ if (aneg_enabled(dev)) {
+ dev->autoneg = AUTONEG_ENABLE;
+ } else {
+ dev->autoneg = AUTONEG_DISABLE;
+ dev->speed = phy_get_speed(dev);
+ dev->duplex = phy_get_duplex(dev);
+
+ switch (dev->speed) {
+ case SPEED_1000:
+ if (dev->duplex == DUPLEX_FULL)
+ dev->supported &= SUPPORTED_1000baseT_Full;
+ else
+ dev->supported &= SUPPORTED_1000baseT_Half;
+ break;
+ case SPEED_100:
+ if (dev->duplex == DUPLEX_FULL)
+ dev->supported &= SUPPORTED_100baseT_Full;
+ else
+ dev->supported &= SUPPORTED_100baseT_Half;
+ break;
+ case SPEED_10:
+ if (dev->duplex == DUPLEX_FULL)
+ dev->supported &= SUPPORTED_10baseT_Full;
+ else
+ dev->supported &= SUPPORTED_10baseT_Half;
+ break;
+ default:
+ printf("Unsupported speed: %d\n", dev->speed);
+ }
+ }
+
phy_probe(dev);
bus->phymap[addr] = dev;
int phy_reset(struct phy_device *phydev)
{
+ int err;
int reg;
int timeout = 500;
int devad = MDIO_DEVAD_NONE;
reg |= BMCR_RESET;
- if (phy_write(phydev, devad, MII_BMCR, reg) < 0) {
+ err = phy_write(phydev, devad, MII_BMCR, reg);
+ if (err < 0) {
debug("PHY reset failed\n");
- return -1;
+ return err;
}
#ifdef CONFIG_PHY_RESET_DELAY
* auto-clearing). This should happen within 0.5 seconds per the
* IEEE spec.
*/
- while ((reg & BMCR_RESET) && timeout--) {
+ while ((reg & BMCR_RESET) && timeout-- >= 0) {
reg = phy_read(phydev, devad, MII_BMCR);
if (reg < 0) {
debug("PHY status read failed\n");
- return -1;
+ return reg;
}
udelay(1000);
}
if (reg & BMCR_RESET) {
puts("PHY reset timed out\n");
- return -1;
+ return -ETIMEDOUT;
}
return 0;