From a058052c358c3ecf5f394ff37def6a45eb26768c Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 9 Dec 2015 11:21:25 -0800 Subject: net: phy: do not read configuration register on reset When doing a software reset, the reset flag should be written without other bits set. Writing the current state will lead to restoring the state of the PHY (e.g. Powerdown), which is not what is expected from a software reset. Signed-off-by: Stefan Agner Acked-by: Michael Welling Reviewed-by: Bin Meng Acked-by: Joe Hershberger --- drivers/net/phy/phy.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 51b5746..ef9f13b 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -717,15 +717,7 @@ int phy_reset(struct phy_device *phydev) } #endif - reg = phy_read(phydev, devad, MII_BMCR); - if (reg < 0) { - debug("PHY status read failed\n"); - return -1; - } - - reg |= BMCR_RESET; - - if (phy_write(phydev, devad, MII_BMCR, reg) < 0) { + if (phy_write(phydev, devad, MII_BMCR, BMCR_RESET) < 0) { debug("PHY reset failed\n"); return -1; } @@ -738,6 +730,7 @@ int phy_reset(struct phy_device *phydev) * auto-clearing). This should happen within 0.5 seconds per the * IEEE spec. */ + reg = phy_read(phydev, devad, MII_BMCR); while ((reg & BMCR_RESET) && timeout--) { reg = phy_read(phydev, devad, MII_BMCR); -- cgit v1.1 From bbdcaff12ad8c32100b5e1fdf9b9ae6931c3ba0d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 13 Jan 2016 16:59:31 +0300 Subject: net: phy: ensure Gigabit features are masked off if requested When a Gigabit PHY device is connected to a 10/100Mbits capable Ethernet MAC, the driver will restrict the phydev->supported modes to mask off Gigabit. If the Gigabit PHY comes out of reset with the Gigabit features set by default in MII_CTRL1000, it will keep advertising these feature, so by the time we call genphy_config_advert(), the condition on phydev->supported having the Gigabit features on is false, and we do not update MII_CTRL1000 with updated values, and we keep advertising Gigabit features, eventually configuring the PHY for Gigabit whilst the Ethernet MAC does not support that. This patches fixes the problem by ensuring that the Gigabit feature bits are always cleared in MII_CTRL1000, if the PHY happens to be a Gigabit PHY, and then, if Gigabit features are supported, setting those and updating MII_CTRL1000 accordingly. This is a copy of patch from Linux kernel, see http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=5273e3a5ca94fbeb8e07d31203069220d5e682aa Signed-off-by: Florian Fainelli Signed-off-by: Alexey Brodkin Cc: Joe Hershberger Acked-by: Joe Hershberger --- drivers/net/phy/phy.c | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index ef9f13b..aac9aa3 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -38,16 +38,16 @@ DECLARE_GLOBAL_DATA_PTR; static int genphy_config_advert(struct phy_device *phydev) { u32 advertise; - int oldadv, adv; + int oldadv, adv, bmsr; int err, changed = 0; - /* Only allow advertising what - * this PHY supports */ + /* Only allow advertising what this PHY supports */ phydev->advertising &= phydev->supported; advertise = phydev->advertising; /* Setup standard advertisement */ - oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE); + adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE); + oldadv = adv; if (adv < 0) return adv; @@ -79,29 +79,40 @@ static int genphy_config_advert(struct phy_device *phydev) changed = 1; } + bmsr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + if (bmsr < 0) + return bmsr; + + /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all + * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a + * logical 1. + */ + if (!(bmsr & BMSR_ESTATEN)) + return changed; + /* Configure gigabit if it's supported */ - if (phydev->supported & (SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full)) { - oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000); + adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000); + oldadv = adv; + + if (adv < 0) + return adv; - if (adv < 0) - return adv; + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (phydev->supported & (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full)) { if (advertise & SUPPORTED_1000baseT_Half) adv |= ADVERTISE_1000HALF; if (advertise & SUPPORTED_1000baseT_Full) adv |= ADVERTISE_1000FULL; + } - if (adv != oldadv) { - err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, - adv); + if (adv != oldadv) + changed = 1; - if (err < 0) - return err; - changed = 1; - } - } + err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, adv); + if (err < 0) + return err; return changed; } -- cgit v1.1 From 44bc317487386117a9a08d50be4cb105d512224c Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 13 Jan 2016 16:59:32 +0300 Subject: net: phy: genphy: Allow overwriting features of_set_phy_supported allows overwiting hardware capabilities of a phy with values from the devicetree. This does not work with the genphy driver though because the genphys config_init function will overwrite all values adjusted by of_set_phy_supported. Fix this by initialising the genphy features in the phy_driver struct and in config_init just limit the features to the ones the hardware can actually support. The resulting features are a subset of the devicetree specified features and the hardware features. This is a copy of the patch from Linux kernel, see http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c242a47238fa2a6a54af8a16e62b54e6e031d4bc Signed-off-by: Sascha Hauer Signed-off-by: Alexey Brodkin Cc: Joe Hershberger Acked-by: Joe Hershberger --- drivers/net/phy/phy.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index aac9aa3..d25bec2 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -382,8 +382,6 @@ int genphy_config(struct phy_device *phydev) int val; u32 features; - /* For now, I'll claim that the generic driver supports - * all possible port types */ features = (SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_AUI | SUPPORTED_FIBRE | SUPPORTED_BNC); @@ -422,8 +420,8 @@ int genphy_config(struct phy_device *phydev) features |= SUPPORTED_1000baseX_Half; } - phydev->supported = features; - phydev->advertising = features; + phydev->supported &= features; + phydev->advertising &= features; genphy_config_aneg(phydev); @@ -447,7 +445,9 @@ static struct phy_driver genphy_driver = { .uid = 0xffffffff, .mask = 0xffffffff, .name = "Generic PHY", - .features = 0, + .features = PHY_GBIT_FEATURES | SUPPORTED_MII | + SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_BNC, .config = genphy_config, .startup = genphy_startup, .shutdown = genphy_shutdown, -- cgit v1.1 From b18acb0a115dfbbd31ee53081b514cab6fe2f262 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Wed, 13 Jan 2016 16:59:34 +0300 Subject: drivers/net/phy: introduce phy_set_supported() This new function will allow MAC drivers to override supported capabilities of the phy. It is required when MAC cannot handle all speeds supported by phy. For example phy supports up-to 1Gb connections while MAC may only work in modes up to 100 or even 10 Mbit/sec. Signed-off-by: Alexey Brodkin Cc: Joe Hershberger Acked-by: Joe Hershberger --- drivers/net/phy/phy.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d25bec2..e25d4e3 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -528,6 +528,30 @@ int phy_register(struct phy_driver *drv) return 0; } +int phy_set_supported(struct phy_device *phydev, u32 max_speed) +{ + /* The default values for phydev->supported are provided by the PHY + * driver "features" member, we want to reset to sane defaults first + * before supporting higher speeds. + */ + phydev->supported &= PHY_DEFAULT_FEATURES; + + switch (max_speed) { + default: + return -ENOTSUPP; + case SPEED_1000: + phydev->supported |= PHY_1000BT_FEATURES; + /* fall through */ + case SPEED_100: + phydev->supported |= PHY_100BT_FEATURES; + /* fall through */ + case SPEED_10: + phydev->supported |= PHY_10BT_FEATURES; + } + + return 0; +} + static int phy_probe(struct phy_device *phydev) { int err = 0; -- cgit v1.1 From 79e3efd5e54acba20a5af94f713d7aae5e540d09 Mon Sep 17 00:00:00 2001 From: Alexandre Messier Date: Fri, 22 Jan 2016 14:06:33 -0500 Subject: net: phy: micrel: Disable B_CAST on config Micrel PHYs KSZ8021/31 and KSZ8081 have a feature where MDIO address 0 is considered as a broadcast address; the PHY will respond even if it is not its configured (pinstrapped) address. This feature is enabled by default. The Linux kernel disables that feature at initialisation, but not before it probes the MDIO bus. This causes an issue, because a PHY at address 3 will be discovered at addresses 0 and 3, but will then only respond at address 3. Because Linux attaches the first PHY it discovers on 'eth0', it will attach the PHY from address 0, which will never answer again. Fix the issue by disabling the broadcast feature in U-Boot, before Linux is started. Signed-off-by: Alexandre Messier Acked-by: Joe Hershberger --- drivers/net/phy/micrel.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 19b6bc7..446d05a 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -27,12 +27,31 @@ static struct phy_driver KSZ804_driver = { .shutdown = &genphy_shutdown, }; +#define MII_KSZPHY_OMSO 0x16 +#define KSZPHY_OMSO_B_CAST_OFF (1 << 9) + +static int ksz_genconfig_bcastoff(struct phy_device *phydev) +{ + int ret; + + ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_KSZPHY_OMSO, + ret | KSZPHY_OMSO_B_CAST_OFF); + if (ret < 0) + return ret; + + return genphy_config(phydev); +} + static struct phy_driver KSZ8031_driver = { .name = "Micrel KSZ8021/KSZ8031", .uid = 0x221550, .mask = 0xfffff0, .features = PHY_BASIC_FEATURES, - .config = &genphy_config, + .config = &ksz_genconfig_bcastoff, .startup = &genphy_startup, .shutdown = &genphy_shutdown, }; @@ -70,7 +89,7 @@ static struct phy_driver KSZ8081_driver = { .uid = 0x221560, .mask = 0xfffff0, .features = PHY_BASIC_FEATURES, - .config = &genphy_config, + .config = &ksz_genconfig_bcastoff, .startup = &genphy_startup, .shutdown = &genphy_shutdown, }; -- cgit v1.1 From 53b0c38c7a691d13d53c08e4c4ebbfd2612f20a7 Mon Sep 17 00:00:00 2001 From: Alexandre Messier Date: Fri, 22 Jan 2016 14:16:15 -0500 Subject: net: phy: Set ANRESTART in setup_forced When configuring a PHY in fixed (forced) link mode, in order for the changes to be applied, either one of these conditions must be triggered: 1- PHY is reset 2- Autoneg is restarted 3- PHY transitions from power-down to power-up Neither of these is currently done, so effectively the fixed link configuration is not applied in the PHY. Fix this by setting the Autoneg restart bit. Signed-off-by: Alexandre Messier Acked-by: Joe Hershberger --- drivers/net/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e25d4e3..a06115d 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -128,7 +128,7 @@ static int genphy_config_advert(struct phy_device *phydev) static int genphy_setup_forced(struct phy_device *phydev) { int err; - int ctl = 0; + int ctl = BMCR_ANRESTART; phydev->pause = phydev->asym_pause = 0; -- cgit v1.1 From 1f9e672c792404744006658047c5866c74bc1ab1 Mon Sep 17 00:00:00 2001 From: Alexandre Messier Date: Fri, 22 Jan 2016 14:16:56 -0500 Subject: net: phy: Use 'autoneg' flag from phydev Use the 'autoneg' flag available in phydev when checking if autoneg is in use. The previous implementation was checking directly in the PHY if autoneg was supported. Some PHYs will report that autoneg is supported, even when it is disabled. Thus it is not possible to use that bit to determine if autoneg is currently in use or not. Signed-off-by: Alexandre Messier Acked-by: Joe Hershberger --- drivers/net/phy/phy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index a06115d..467efd8 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -235,7 +235,8 @@ int genphy_update_link(struct phy_device *phydev) if (phydev->link && mii_reg & BMSR_LSTATUS) return 0; - if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) { + if ((phydev->autoneg == AUTONEG_ENABLE) && + !(mii_reg & BMSR_ANEGCOMPLETE)) { int i = 0; printf("%s Waiting for PHY auto negotiation to complete", @@ -291,7 +292,7 @@ int genphy_parse_link(struct phy_device *phydev) int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); /* We're using autonegotiation */ - if (phydev->supported & SUPPORTED_Autoneg) { + if (phydev->autoneg == AUTONEG_ENABLE) { u32 lpa = 0; int gblpa = 0; u32 estatus = 0; -- cgit v1.1 From ff7bd212cb8a0a80a113e25af7616ef0a24abdfc Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Wed, 27 Jan 2016 15:46:00 -0600 Subject: net: phy: micrel: fix divisor value for KSZ9031 phy skew The picoseconds to register value divisor(ps_to_regval) should be 60 and not 200. Linux has KSZ9031_PS_TO_REG defined to be 60 as well. 60 is the correct divisor because the 4-bit skew values are defined from 0x0000(-420ps) to 0xffff(480ps), increments of 60. For example, a DTS skew value of 420, represents 0ps delay, which should be 0x7. With the previous divisor of 200, it would result in 0x2, which represents a -300ps delay. With this patch, ethernet on the SoCFPGA DE0 Atlas is now able to work with 1Gb ethernet. References: http://www.micrel.com/_PDF/Ethernet/datasheets/KSZ9031RNX.pdf -> page 26 Signed-off-by: Dinh Nguyen Acked-by: Marek Vasut Acked-by: Joe Hershberger --- drivers/net/phy/micrel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 446d05a..c3da160 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -230,7 +230,7 @@ static int ksz90x1_of_config_group(struct phy_device *phydev, { struct udevice *dev = phydev->dev; struct phy_driver *drv = phydev->drv; - const int ps_to_regval = 200; + const int ps_to_regval = 60; int val[4]; int i, changed = 0, offset, max; u16 regval = 0; -- cgit v1.1 From ddcd1f3084d88cc92403ed09f77f42fc6f2c4e0e Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Thu, 28 Jan 2016 15:55:46 +0800 Subject: net: phy: introduce a quirk PHY_FLAG_BROKEN_RESET Current driver always performs a phy soft reset when connecting the phy device, but soft reset is not always supported by a phy device, so introduce a quirk PHY_FLAG_BROKEN_RESET to let such a phy device to skip soft reset. This commit uses 'flags' of phy device structure to store the quirk. Signed-off-by: Shaohui Xie Acked-by: Joe Hershberger --- drivers/net/phy/phy.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 467efd8..17866a2 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -743,6 +743,9 @@ int phy_reset(struct phy_device *phydev) int timeout = 500; int devad = MDIO_DEVAD_NONE; + if (phydev->flags & PHY_FLAG_BROKEN_RESET) + return 0; + #ifdef CONFIG_PHYLIB_10G /* If it's 10G, we need to issue reset through one of the MMDs */ if (is_10g_interface(phydev->interface)) { -- cgit v1.1 From d8877e6f8ca4b6c08c0bc9c1fa8f855dc8776044 Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Thu, 28 Jan 2016 15:56:36 +0800 Subject: net: phy: implements probe for Cortina phy Cortina phy cannot support soft reset, this commit implements probe for Cortina PHY to tell phylib to skip phy soft reset by setting PHY_FLAG_BROKEN_RESET in flags. Signed-off-by: Shaohui Xie Acked-by: Joe Hershberger --- drivers/net/phy/cortina.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/net/phy') diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c index 3a2b3bb..ba1157f 100644 --- a/drivers/net/phy/cortina.c +++ b/drivers/net/phy/cortina.c @@ -256,6 +256,12 @@ int cs4340_config(struct phy_device *phydev) return 0; } +int cs4340_probe(struct phy_device *phydev) +{ + phydev->flags = PHY_FLAG_BROKEN_RESET; + return 0; +} + int cs4340_startup(struct phy_device *phydev) { phydev->link = 1; @@ -275,6 +281,7 @@ struct phy_driver cs4340_driver = { MDIO_DEVS_PHYXS | MDIO_DEVS_AN | MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2), .config = &cs4340_config, + .probe = &cs4340_probe, .startup = &cs4340_startup, .shutdown = &gen10g_shutdown, }; -- cgit v1.1