diff options
Diffstat (limited to 'drivers/net/phy/broadcom.c')
-rw-r--r-- | drivers/net/phy/broadcom.c | 196 |
1 files changed, 60 insertions, 136 deletions
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 8a4ec3222168..91fbd26c809e 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -26,44 +26,6 @@ MODULE_DESCRIPTION("Broadcom PHY driver"); MODULE_AUTHOR("Maciej W. Rozycki"); MODULE_LICENSE("GPL"); -static int bcm54xx_config_clock_delay(struct phy_device *phydev); - -static int bcm54210e_config_init(struct phy_device *phydev) -{ - int val; - - bcm54xx_config_clock_delay(phydev); - - if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { - val = phy_read(phydev, MII_CTRL1000); - val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; - phy_write(phydev, MII_CTRL1000, val); - } - - return 0; -} - -static int bcm54612e_config_init(struct phy_device *phydev) -{ - int reg; - - bcm54xx_config_clock_delay(phydev); - - /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ - if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { - int err; - - reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); - err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, - BCM54612E_LED4_CLK125OUT_EN | reg); - - if (err < 0) - return err; - } - - return 0; -} - static int bcm54xx_config_clock_delay(struct phy_device *phydev) { int rc, val; @@ -105,6 +67,42 @@ static int bcm54xx_config_clock_delay(struct phy_device *phydev) return 0; } +static int bcm54210e_config_init(struct phy_device *phydev) +{ + int val; + + bcm54xx_config_clock_delay(phydev); + + if (phydev->dev_flags & PHY_BRCM_EN_MASTER_MODE) { + val = phy_read(phydev, MII_CTRL1000); + val |= CTL1000_AS_MASTER | CTL1000_ENABLE_MASTER; + phy_write(phydev, MII_CTRL1000, val); + } + + return 0; +} + +static int bcm54612e_config_init(struct phy_device *phydev) +{ + int reg; + + bcm54xx_config_clock_delay(phydev); + + /* Enable CLK125 MUX on LED4 if ref clock is enabled. */ + if (!(phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED)) { + int err; + + reg = bcm_phy_read_exp(phydev, BCM54612E_EXP_SPARE0); + err = bcm_phy_write_exp(phydev, BCM54612E_EXP_SPARE0, + BCM54612E_LED4_CLK125OUT_EN | reg); + + if (err < 0) + return err; + } + + return 0; +} + /* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */ static int bcm50610_a0_workaround(struct phy_device *phydev) { @@ -195,6 +193,7 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 && BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 && BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M && + BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54210E && BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54810 && BRCM_PHY_MODEL(phydev) != PHY_ID_BCM54811) return; @@ -229,9 +228,10 @@ static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev) val |= BCM54XX_SHD_SCR3_DLLAPD_DIS; if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) { - if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 || - BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54811) - val |= BCM54810_SHD_SCR3_TRDDAPD; + if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E || + BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810 || + BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) + val |= BCM54XX_SHD_SCR3_RXCTXC_DIS; else val |= BCM54XX_SHD_SCR3_TRDDAPD; } @@ -361,96 +361,6 @@ static int bcm54811_config_init(struct phy_device *phydev) return err; } -static int bcm5482_config_init(struct phy_device *phydev) -{ - int err, reg; - - err = bcm54xx_config_init(phydev); - - if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { - /* - * Enable secondary SerDes and its use as an LED source - */ - reg = bcm_phy_read_shadow(phydev, BCM5482_SHD_SSD); - bcm_phy_write_shadow(phydev, BCM5482_SHD_SSD, - reg | - BCM5482_SHD_SSD_LEDM | - BCM5482_SHD_SSD_EN); - - /* - * Enable SGMII slave mode and auto-detection - */ - reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD; - err = bcm_phy_read_exp(phydev, reg); - if (err < 0) - return err; - err = bcm_phy_write_exp(phydev, reg, err | - BCM5482_SSD_SGMII_SLAVE_EN | - BCM5482_SSD_SGMII_SLAVE_AD); - if (err < 0) - return err; - - /* - * Disable secondary SerDes powerdown - */ - reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD; - err = bcm_phy_read_exp(phydev, reg); - if (err < 0) - return err; - err = bcm_phy_write_exp(phydev, reg, - err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); - if (err < 0) - return err; - - /* - * Select 1000BASE-X register set (primary SerDes) - */ - reg = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); - bcm_phy_write_shadow(phydev, BCM54XX_SHD_MODE, - reg | BCM54XX_SHD_MODE_1000BX); - - /* - * LED1=ACTIVITYLED, LED3=LINKSPD[2] - * (Use LED1 as secondary SerDes ACTIVITY LED) - */ - bcm_phy_write_shadow(phydev, BCM5482_SHD_LEDS1, - BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) | - BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2)); - - /* - * Auto-negotiation doesn't seem to work quite right - * in this mode, so we disable it and force it to the - * right speed/duplex setting. Only 'link status' - * is important. - */ - phydev->autoneg = AUTONEG_DISABLE; - phydev->speed = SPEED_1000; - phydev->duplex = DUPLEX_FULL; - } - - return err; -} - -static int bcm5482_read_status(struct phy_device *phydev) -{ - int err; - - err = genphy_read_status(phydev); - - if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) { - /* - * Only link status matters for 1000Base-X mode, so force - * 1000 Mbit/s full-duplex status - */ - if (phydev->link) { - phydev->speed = SPEED_1000; - phydev->duplex = DUPLEX_FULL; - } - } - - return err; -} - static int bcm5481_config_aneg(struct phy_device *phydev) { struct device_node *np = phydev->mdio.dev.of_node; @@ -473,10 +383,21 @@ static int bcm5481_config_aneg(struct phy_device *phydev) return ret; } +struct bcm54616s_phy_priv { + bool mode_1000bx_en; +}; + static int bcm54616s_probe(struct phy_device *phydev) { + struct bcm54616s_phy_priv *priv; int val, intf_sel; + priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_MODE); if (val < 0) return val; @@ -499,7 +420,9 @@ static int bcm54616s_probe(struct phy_device *phydev) * 1000BASE-X configuration. */ if (!(val & BCM54616S_100FX_MODE)) - phydev->dev_flags |= PHY_BCM_FLAGS_MODE_1000BX; + priv->mode_1000bx_en = true; + + phydev->port = PORT_FIBRE; } return 0; @@ -507,10 +430,11 @@ static int bcm54616s_probe(struct phy_device *phydev) static int bcm54616s_config_aneg(struct phy_device *phydev) { + struct bcm54616s_phy_priv *priv = phydev->priv; int ret; /* Aneg firstly. */ - if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) + if (priv->mode_1000bx_en) ret = genphy_c37_config_aneg(phydev); else ret = genphy_config_aneg(phydev); @@ -523,9 +447,10 @@ static int bcm54616s_config_aneg(struct phy_device *phydev) static int bcm54616s_read_status(struct phy_device *phydev) { + struct bcm54616s_phy_priv *priv = phydev->priv; int err; - if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) + if (priv->mode_1000bx_en) err = genphy_c37_read_status(phydev); else err = genphy_read_status(phydev); @@ -800,8 +725,7 @@ static struct phy_driver broadcom_drivers[] = { .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5482", /* PHY_GBIT_FEATURES */ - .config_init = bcm5482_config_init, - .read_status = bcm5482_read_status, + .config_init = bcm54xx_config_init, .config_intr = bcm_phy_config_intr, .handle_interrupt = bcm_phy_handle_interrupt, }, { |