diff options
Diffstat (limited to 'drivers/net/phy/broadcom.c')
-rw-r--r-- | drivers/net/phy/broadcom.c | 47 |
1 files changed, 38 insertions, 9 deletions
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 22edb7e4c1a1..a60e58ef90c4 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -16,7 +16,7 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/phy.h> -#include <linux/pm_wakeup.h> +#include <linux/device.h> #include <linux/brcmphy.h> #include <linux/of.h> #include <linux/interrupt.h> @@ -407,7 +407,7 @@ static int bcm5481x_set_brrmode(struct phy_device *phydev, bool on) static int bcm54811_config_init(struct phy_device *phydev) { struct bcm54xx_phy_priv *priv = phydev->priv; - int err, reg; + int err, reg, exp_sync_ethernet; /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { @@ -424,6 +424,18 @@ static int bcm54811_config_init(struct phy_device *phydev) if (priv->brr_mode) phydev->autoneg = 0; + /* Enable MII Lite (No TXER, RXER, CRS, COL) if configured */ + if (phydev->interface == PHY_INTERFACE_MODE_MIILITE) + exp_sync_ethernet = BCM_EXP_SYNC_ETHERNET_MII_LITE; + else + exp_sync_ethernet = 0; + + err = bcm_phy_modify_exp(phydev, BCM_EXP_SYNC_ETHERNET, + BCM_EXP_SYNC_ETHERNET_MII_LITE, + exp_sync_ethernet); + if (err < 0) + return err; + return bcm5481x_set_brrmode(phydev, priv->brr_mode); } @@ -655,7 +667,7 @@ static int bcm5481x_read_abilities(struct phy_device *phydev) { struct device_node *np = phydev->mdio.dev.of_node; struct bcm54xx_phy_priv *priv = phydev->priv; - int i, val, err; + int i, val, err, aneg; for (i = 0; i < ARRAY_SIZE(bcm54811_linkmodes); i++) linkmode_clear_bit(bcm54811_linkmodes[i], phydev->supported); @@ -676,9 +688,19 @@ static int bcm5481x_read_abilities(struct phy_device *phydev) if (val < 0) return val; + /* BCM54811 is not capable of LDS but the corresponding bit + * in LRESR is set to 1 and marked "Ignore" in the datasheet. + * So we must read the bcm54811 as unable to auto-negotiate + * in BroadR-Reach mode. + */ + if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811) + aneg = 0; + else + aneg = val & LRESR_LDSABILITY; + linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported, - val & LRESR_LDSABILITY); + aneg); linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT, phydev->supported, val & LRESR_100_1PAIR); @@ -735,8 +757,15 @@ static int bcm54811_config_aneg(struct phy_device *phydev) /* Aneg firstly. */ if (priv->brr_mode) { - /* BCM54811 is only capable of autonegotiation in IEEE mode */ - phydev->autoneg = 0; + /* BCM54811 is only capable of autonegotiation in IEEE mode. + * In BroadR-Reach mode, disable the Long Distance Signaling, + * the BRR mode autoneg as supported in other Broadcom PHYs. + * This bit is marked as "Reserved" and "Default 1, must be + * written to 0 after every device reset" in the datasheet. + */ + ret = phy_modify(phydev, MII_BCM54XX_LRECR, LRECR_LDSEN, 0); + if (ret < 0) + return ret; ret = bcm_config_lre_aneg(phydev, false); } else { ret = genphy_config_aneg(phydev); @@ -859,7 +888,7 @@ static int brcm_fet_config_init(struct phy_device *phydev) return reg; /* Unmask events we are interested in and mask interrupts globally. */ - if (phydev->phy_id == PHY_ID_BCM5221) + if (phydev->drv->phy_id == PHY_ID_BCM5221) reg = MII_BRCM_FET_IR_ENABLE | MII_BRCM_FET_IR_MASK; else @@ -888,7 +917,7 @@ static int brcm_fet_config_init(struct phy_device *phydev) return err; } - if (phydev->phy_id != PHY_ID_BCM5221) { + if (phydev->drv->phy_id != PHY_ID_BCM5221) { /* Set the LED mode */ reg = __phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4); if (reg < 0) { @@ -1009,7 +1038,7 @@ static int brcm_fet_suspend(struct phy_device *phydev) return err; } - if (phydev->phy_id == PHY_ID_BCM5221) + if (phydev->drv->phy_id == PHY_ID_BCM5221) /* Force Low Power Mode with clock enabled */ reg = BCM5221_SHDW_AM4_EN_CLK_LPM | BCM5221_SHDW_AM4_FORCE_LPM; else |