@@ -313,6 +313,7 @@ struct at803x_priv {
u8 smarteee_lpi_tw_100m;
bool is_fiber;
bool is_1000basex;
+ bool tx_lpi_on;
struct regulator_dev *vddio_rdev;
struct regulator_dev *vddh_rdev;
struct regulator *vddio;
@@ -970,6 +971,8 @@ static int at803x_smarteee_config(struct phy_device *phydev, bool enable,
u16 mask = 0, val = 0;
int ret;
+ priv->tx_lpi_on = enable;
+
if (priv->flags & AT803X_DISABLE_SMARTEEE || !enable)
return phy_modify_mmd(phydev, MDIO_MMD_PCS,
AT803X_MMD3_SMARTEEE_CTL3,
@@ -1010,10 +1013,15 @@ static int at803x_smarteee_config(struct phy_device *phydev, bool enable,
if (ret)
return ret;
- val = AT803X_MMD3_SMARTEEE_CTL3_LPI_EN |
- FIELD_PREP(AT803X_MMD3_SMARTEEE_LPI_TIME_HIGH,
- FIELD_GET(AT803X_MMD3_SMARTEEE_LPI_TIME_23_16,
- tx_lpi_timer_raw));
+ val = FIELD_PREP(AT803X_MMD3_SMARTEEE_LPI_TIME_HIGH,
+ FIELD_GET(AT803X_MMD3_SMARTEEE_LPI_TIME_23_16,
+ tx_lpi_timer_raw));
+
+ if (phydev->state == PHY_RUNNING &&
+ phy_check_valid(phydev->speed, phydev->duplex,
+ phydev->supported_eee)) {
+ val |= AT803X_MMD3_SMARTEEE_CTL3_LPI_EN;
+ }
return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3,
AT803X_MMD3_SMARTEEE_CTL3_LPI_EN |
@@ -1682,7 +1690,7 @@ static int at803x_get_eee(struct phy_device *phydev, struct ethtool_eee *data)
tx_timer_ns = tx_timer_raw * AT803X_MMD3_SMARTEEE_LPI_TIME_RESOL_NS;
data->tx_lpi_timer = DIV_ROUND_CLOSEST_ULL(tx_timer_ns, NSEC_PER_USEC);
- data->tx_lpi_enabled = !!(ret & AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
+ data->tx_lpi_enabled = priv->tx_lpi_on;
return genphy_c45_ethtool_get_eee(phydev, data);
}
@@ -1709,6 +1717,28 @@ static int at803x_set_eee(struct phy_device *phydev, struct ethtool_eee *data)
return genphy_c45_ethtool_set_eee(phydev, data);
}
+static void at8035_link_change_notify(struct phy_device *phydev)
+{
+ struct at803x_priv *priv = phydev->priv;
+
+ if (priv->flags & AT803X_DISABLE_SMARTEEE)
+ return;
+
+ if (phydev->state == PHY_RUNNING) {
+ if (priv->tx_lpi_on && phy_check_valid(phydev->speed,
+ phydev->duplex,
+ phydev->supported_eee))
+ phy_set_bits_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_MMD3_SMARTEEE_CTL3,
+ AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
+ } else {
+ if (priv->tx_lpi_on)
+ phy_clear_bits_mmd(phydev, MDIO_MMD_PCS,
+ AT803X_MMD3_SMARTEEE_CTL3,
+ AT803X_MMD3_SMARTEEE_CTL3_LPI_EN);
+ }
+}
+
static int qca83xx_config_init(struct phy_device *phydev)
{
u8 switch_revision;
@@ -2137,6 +2167,7 @@ static struct phy_driver at803x_driver[] = {
.cable_test_get_status = at803x_cable_test_get_status,
.get_eee = at803x_get_eee,
.set_eee = at803x_set_eee,
+ .link_change_notify = at8035_link_change_notify,
}, {
/* Qualcomm Atheros AR8030 */
.phy_id = ATH8030_PHY_ID,
If AR8035 is running with enabled EEE and LPI, it will not be able to establish an 100BaseTX/Half or 1000BaseT/Half link. Similar issue we will have with 100BaseTX/Full and LPI TX timer configured to less then 80msec. To avoid this issue, we need to keep LPI disabled before link is establish and enable it only we detected supported link configuration. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- drivers/net/phy/at803x.c | 41 +++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-)