From: Lothar Waßmann Date: Fri, 9 Jan 2015 11:22:56 +0000 (+0100) Subject: net: phy: make autonegotiation configurable X-Git-Tag: KARO-TX6-2015-02-05~9 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;ds=sidebyside;h=250c4d38baf13e723ea8d83f25f07a54dcb3ce48;p=karo-tx-uboot.git net: phy: make autonegotiation configurable Introduce environment variables to configure the use of ethernet autonegotiation. The variable names are derived from the ethernet device name ('FEC' for TX51,TX53,TX6; 'FEC0','FEC1' for TX28; 'cpsw' for TX48) with the suffix '_aneg' appended. If the '*_aneg' variable is unset or set to a string starting in 'y','t' or '1' autonegotiation will be enabled and the '*_speed' and '*_duplex' variables have no meaning. Otherwise autonegotiation is disabled and the link speed and duplex settings can be configured with the variables: '*_speed' and '*_duplex' (with '*' replaced with the prefix described above). --- diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 7ad1343ab1..58ba5c2c2c 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -558,6 +558,69 @@ static struct phy_driver *get_phy_driver(struct phy_device *phydev, 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) @@ -579,14 +642,43 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr, 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;