diff options
Diffstat (limited to 'drivers/net/phy/at803x.c')
-rw-r--r-- | drivers/net/phy/at803x.c | 237 |
1 files changed, 193 insertions, 44 deletions
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c index dae95d9a07e8..349b7b1dbbf2 100644 --- a/drivers/net/phy/at803x.c +++ b/drivers/net/phy/at803x.c @@ -19,6 +19,8 @@ #include <linux/regulator/of_regulator.h> #include <linux/regulator/driver.h> #include <linux/regulator/consumer.h> +#include <linux/phylink.h> +#include <linux/sfp.h> #include <dt-bindings/net/qca-ar803x.h> #define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 @@ -51,6 +53,8 @@ #define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) #define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) #define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) +#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) +#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) #define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) #define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) #define AT803X_INTR_ENABLE_WOL BIT(0) @@ -85,7 +89,17 @@ #define AT803X_DEBUG_DATA 0x1E #define AT803X_MODE_CFG_MASK 0x0F -#define AT803X_MODE_CFG_SGMII 0x01 +#define AT803X_MODE_CFG_BASET_RGMII 0x00 +#define AT803X_MODE_CFG_BASET_SGMII 0x01 +#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02 +#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03 +#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04 +#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05 +#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06 +#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07 +#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B +#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E +#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ #define AT803X_PSSR_MR_AN_COMPLETE 0x0200 @@ -101,6 +115,7 @@ #define AT803X_DEBUG_REG_HIB_CTRL 0x0b #define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10) #define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) +#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) #define AT803X_DEBUG_REG_3C 0x3C @@ -178,6 +193,9 @@ #define AT803X_KEEP_PLL_ENABLED BIT(0) #define AT803X_DISABLE_SMARTEEE BIT(1) +/* disable hibernation mode */ +#define AT803X_DISABLE_HIBERNATION_MODE BIT(2) + /* ADC threshold */ #define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80 #define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0) @@ -283,6 +301,8 @@ struct at803x_priv { u16 clk_25m_mask; u8 smarteee_lpi_tw_1g; u8 smarteee_lpi_tw_100m; + bool is_fiber; + bool is_1000basex; struct regulator_dev *vddio_rdev; struct regulator_dev *vddh_rdev; struct regulator *vddio; @@ -417,20 +437,21 @@ static void at803x_context_restore(struct phy_device *phydev, static int at803x_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol) { - struct net_device *ndev = phydev->attached_dev; - const u8 *mac; int ret, irq_enabled; - unsigned int i; - const unsigned int offsets[] = { - AT803X_LOC_MAC_ADDR_32_47_OFFSET, - AT803X_LOC_MAC_ADDR_16_31_OFFSET, - AT803X_LOC_MAC_ADDR_0_15_OFFSET, - }; - - if (!ndev) - return -ENODEV; if (wol->wolopts & WAKE_MAGIC) { + struct net_device *ndev = phydev->attached_dev; + const u8 *mac; + unsigned int i; + static const unsigned int offsets[] = { + AT803X_LOC_MAC_ADDR_32_47_OFFSET, + AT803X_LOC_MAC_ADDR_16_31_OFFSET, + AT803X_LOC_MAC_ADDR_0_15_OFFSET, + }; + + if (!ndev) + return -ENODEV; + mac = (const u8 *) ndev->dev_addr; if (!is_valid_ether_addr(mac)) @@ -650,6 +671,56 @@ static int at8031_register_regulators(struct phy_device *phydev) return 0; } +static int at803x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) +{ + struct phy_device *phydev = upstream; + __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support); + __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); + DECLARE_PHY_INTERFACE_MASK(interfaces); + phy_interface_t iface; + + linkmode_zero(phy_support); + phylink_set(phy_support, 1000baseX_Full); + phylink_set(phy_support, 1000baseT_Full); + phylink_set(phy_support, Autoneg); + phylink_set(phy_support, Pause); + phylink_set(phy_support, Asym_Pause); + + linkmode_zero(sfp_support); + sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces); + /* Some modules support 10G modes as well as others we support. + * Mask out non-supported modes so the correct interface is picked. + */ + linkmode_and(sfp_support, phy_support, sfp_support); + + if (linkmode_empty(sfp_support)) { + dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); + return -EINVAL; + } + + iface = sfp_select_interface(phydev->sfp_bus, sfp_support); + + /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes + * interface for use with SFP modules. + * However, some copper modules detected as having a preferred SGMII + * interface do default to and function in 1000Base-X mode, so just + * print a warning and allow such modules, as they may have some chance + * of working. + */ + if (iface == PHY_INTERFACE_MODE_SGMII) + dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n"); + else if (iface != PHY_INTERFACE_MODE_1000BASEX) + return -EINVAL; + + return 0; +} + +static const struct sfp_upstream_ops at803x_sfp_ops = { + .attach = phy_sfp_attach, + .detach = phy_sfp_detach, + .module_insert = at803x_sfp_insert, +}; + static int at803x_parse_dt(struct phy_device *phydev) { struct device_node *node = phydev->mdio.dev.of_node; @@ -664,6 +735,9 @@ static int at803x_parse_dt(struct phy_device *phydev) if (of_property_read_bool(node, "qca,disable-smarteee")) priv->flags |= AT803X_DISABLE_SMARTEEE; + if (of_property_read_bool(node, "qca,disable-hibernation-mode")) + priv->flags |= AT803X_DISABLE_HIBERNATION_MODE; + if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) { if (!tw || tw > 255) { phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n"); @@ -757,6 +831,11 @@ static int at803x_parse_dt(struct phy_device *phydev) phydev_err(phydev, "failed to get VDDIO regulator\n"); return PTR_ERR(priv->vddio); } + + /* Only AR8031/8033 support 1000Base-X for SFP modules */ + ret = phy_sfp_probe(phydev, &at803x_sfp_ops); + if (ret < 0) + return ret; } return 0; @@ -784,16 +863,34 @@ static int at803x_probe(struct phy_device *phydev) return ret; } - /* Some bootloaders leave the fiber page selected. - * Switch to the copper page, as otherwise we read - * the PHY capabilities from the fiber side. - */ if (phydev->drv->phy_id == ATH8031_PHY_ID) { - phy_lock_mdio_bus(phydev); - ret = at803x_write_page(phydev, AT803X_PAGE_COPPER); - phy_unlock_mdio_bus(phydev); - if (ret) + int ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); + int mode_cfg; + struct ethtool_wolinfo wol = { + .wolopts = 0, + }; + + if (ccr < 0) + goto err; + mode_cfg = ccr & AT803X_MODE_CFG_MASK; + + switch (mode_cfg) { + case AT803X_MODE_CFG_BX1000_RGMII_50OHM: + case AT803X_MODE_CFG_BX1000_RGMII_75OHM: + priv->is_1000basex = true; + fallthrough; + case AT803X_MODE_CFG_FX100_RGMII_50OHM: + case AT803X_MODE_CFG_FX100_RGMII_75OHM: + priv->is_fiber = true; + break; + } + + /* Disable WOL by default */ + ret = at803x_set_wol(phydev, &wol); + if (ret < 0) { + phydev_err(phydev, "failed to disable WOL on probe: %d\n", ret); goto err; + } } return 0; @@ -815,6 +912,7 @@ static void at803x_remove(struct phy_device *phydev) static int at803x_get_features(struct phy_device *phydev) { + struct at803x_priv *priv = phydev->priv; int err; err = genphy_read_abilities(phydev); @@ -841,12 +939,13 @@ static int at803x_get_features(struct phy_device *phydev) * As a result of that, ESTATUS_1000_XFULL is set * to 1 even when operating in copper TP mode. * - * Remove this mode from the supported link modes, - * as this driver currently only supports copper - * operation. + * Remove this mode from the supported link modes + * when not operating in 1000BaseX mode. */ - linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, - phydev->supported); + if (!priv->is_1000basex) + linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->supported); + return 0; } @@ -908,10 +1007,43 @@ static int at8031_pll_config(struct phy_device *phydev) AT803X_DEBUG_PLL_ON, 0); } +static int at803x_hibernation_mode_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + /* The default after hardware reset is hibernation mode enabled. After + * software reset, the value is retained. + */ + if (!(priv->flags & AT803X_DISABLE_HIBERNATION_MODE)) + return 0; + + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, + AT803X_DEBUG_HIB_CTRL_PS_HIB_EN, 0); +} + static int at803x_config_init(struct phy_device *phydev) { + struct at803x_priv *priv = phydev->priv; int ret; + if (phydev->drv->phy_id == ATH8031_PHY_ID) { + /* Some bootloaders leave the fiber page selected. + * Switch to the appropriate page (fiber or copper), as otherwise we + * read the PHY capabilities from the wrong page. + */ + phy_lock_mdio_bus(phydev); + ret = at803x_write_page(phydev, + priv->is_fiber ? AT803X_PAGE_FIBER : + AT803X_PAGE_COPPER); + phy_unlock_mdio_bus(phydev); + if (ret) + return ret; + + ret = at8031_pll_config(phydev); + if (ret < 0) + return ret; + } + /* The RX and TX delay default is: * after HW reset: RX delay enabled and TX delay disabled * after SW reset: RX delay enabled, while TX delay retains the @@ -941,11 +1073,9 @@ static int at803x_config_init(struct phy_device *phydev) if (ret < 0) return ret; - if (phydev->drv->phy_id == ATH8031_PHY_ID) { - ret = at8031_pll_config(phydev); - if (ret < 0) - return ret; - } + ret = at803x_hibernation_mode_config(phydev); + if (ret < 0) + return ret; /* Ar803x extended next page bit is enabled by default. Cisco * multigig switches read this bit and attempt to negotiate 10Gbps @@ -967,6 +1097,7 @@ static int at803x_ack_interrupt(struct phy_device *phydev) static int at803x_config_intr(struct phy_device *phydev) { + struct at803x_priv *priv = phydev->priv; int err; int value; @@ -983,6 +1114,10 @@ static int at803x_config_intr(struct phy_device *phydev) value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; value |= AT803X_INTR_ENABLE_LINK_FAIL; value |= AT803X_INTR_ENABLE_LINK_SUCCESS; + if (priv->is_fiber) { + value |= AT803X_INTR_ENABLE_LINK_FAIL_BX; + value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX; + } err = phy_write(phydev, AT803X_INTR_ENABLE, value); } else { @@ -1115,8 +1250,12 @@ static int at803x_read_specific_status(struct phy_device *phydev) static int at803x_read_status(struct phy_device *phydev) { + struct at803x_priv *priv = phydev->priv; int err, old_link = phydev->link; + if (priv->is_1000basex) + return genphy_c37_read_status(phydev); + /* Update the link, but return if there was an error */ err = genphy_update_link(phydev); if (err) @@ -1170,6 +1309,7 @@ static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl) static int at803x_config_aneg(struct phy_device *phydev) { + struct at803x_priv *priv = phydev->priv; int ret; ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); @@ -1186,6 +1326,9 @@ static int at803x_config_aneg(struct phy_device *phydev) return ret; } + if (priv->is_1000basex) + return genphy_c37_config_aneg(phydev); + /* Do not restart auto-negotiation by setting ret to 0 defautly, * when calling __genphy_config_aneg later. */ @@ -1615,7 +1758,7 @@ static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) static int qca808x_phy_ms_random_seed_set(struct phy_device *phydev) { - u16 seed_value = (prandom_u32() % QCA808X_MASTER_SLAVE_SEED_RANGE); + u16 seed_value = prandom_u32_max(QCA808X_MASTER_SLAVE_SEED_RANGE); return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, QCA808X_MASTER_SLAVE_SEED_CFG, @@ -1688,19 +1831,19 @@ static int qca808x_read_status(struct phy_device *phydev) if (ret < 0) return ret; - if (phydev->link && phydev->speed == SPEED_2500) - phydev->interface = PHY_INTERFACE_MODE_2500BASEX; - else - phydev->interface = PHY_INTERFACE_MODE_SMII; - - /* generate seed as a lower random value to make PHY linked as SLAVE easily, - * except for master/slave configuration fault detected. - * the reason for not putting this code into the function link_change_notify is - * the corner case where the link partner is also the qca8081 PHY and the seed - * value is configured as the same value, the link can't be up and no link change - * occurs. - */ - if (!phydev->link) { + if (phydev->link) { + if (phydev->speed == SPEED_2500) + phydev->interface = PHY_INTERFACE_MODE_2500BASEX; + else + phydev->interface = PHY_INTERFACE_MODE_SGMII; + } else { + /* generate seed as a lower random value to make PHY linked as SLAVE easily, + * except for master/slave configuration fault detected. + * the reason for not putting this code into the function link_change_notify is + * the corner case where the link partner is also the qca8081 PHY and the seed + * value is configured as the same value, the link can't be up and no link change + * occurs. + */ if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR) { qca808x_phy_ms_seed_enable(phydev, false); } else { @@ -1955,6 +2098,8 @@ static struct phy_driver at803x_driver[] = { /* ATHEROS AR9331 */ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), .name = "Qualcomm Atheros AR9331 built-in PHY", + .probe = at803x_probe, + .remove = at803x_remove, .suspend = at803x_suspend, .resume = at803x_resume, .flags = PHY_POLL_CABLE_TEST, @@ -1970,6 +2115,8 @@ static struct phy_driver at803x_driver[] = { /* Qualcomm Atheros QCA9561 */ PHY_ID_MATCH_EXACT(QCA9561_PHY_ID), .name = "Qualcomm Atheros QCA9561 built-in PHY", + .probe = at803x_probe, + .remove = at803x_remove, .suspend = at803x_suspend, .resume = at803x_resume, .flags = PHY_POLL_CABLE_TEST, @@ -2034,6 +2181,8 @@ static struct phy_driver at803x_driver[] = { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID), .name = "Qualcomm QCA8081", .flags = PHY_POLL_CABLE_TEST, + .probe = at803x_probe, + .remove = at803x_remove, .config_intr = at803x_config_intr, .handle_interrupt = at803x_handle_interrupt, .get_tunable = at803x_get_tunable, |