diff options
| author | Vladimir Oltean <vladimir.oltean@nxp.com> | 2025-11-22 13:04:27 +0200 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2025-11-26 18:04:17 -0800 |
| commit | 002373a8b01df23be072bb91741c2e8b2b70ccc1 (patch) | |
| tree | 5d4b8f8f3169d72ded84d0b20e2d461df32a3748 | |
| parent | 308b7dee3e5c767e88bbecceff3883c8b17c55b6 (diff) | |
net: phy: dp83867: implement configurability for SGMII in-band auto-negotiation
Implement the inband_caps() and config_inband() PHY driver methods, to
allow working with PCS devices that do not support or want in-band to be
used.
There is a complication due to existing logic from commit c76acfb7e19d
("net: phy: dp83867: retrigger SGMII AN when link change") which might
re-enable what dp83867_config_inband() has disabled. So we need to
modify dp83867_link_change_notify() to use phy_modify_changed() when
temporarily disabling in-band autoneg. If the return code is 0, it means
the original in-band was disabled and we need to keep it disabled.
If the return code is 1, the original was enabled and we need to
re-enable it. If negative, there was an error, which was silent before,
and remains silent now.
dp83867_config_inband() and dp83867_link_change_notify() are serialized
by the phydev->lock.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20251122110427.133035-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/phy/dp83867.c | 36 |
1 files changed, 29 insertions, 7 deletions
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 36a0c1b7f59c..5f5de01c41e1 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -937,15 +937,15 @@ static void dp83867_link_change_notify(struct phy_device *phydev) * whenever there is a link change. */ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { - int val = 0; + int val; - val = phy_clear_bits(phydev, DP83867_CFG2, - DP83867_SGMII_AUTONEG_EN); - if (val < 0) - return; + val = phy_modify_changed(phydev, DP83867_CFG2, + DP83867_SGMII_AUTONEG_EN, 0); - phy_set_bits(phydev, DP83867_CFG2, - DP83867_SGMII_AUTONEG_EN); + /* Keep the in-band setting made by dp83867_config_inband() */ + if (val != 0) + phy_set_bits(phydev, DP83867_CFG2, + DP83867_SGMII_AUTONEG_EN); } } @@ -1116,6 +1116,25 @@ static int dp83867_led_polarity_set(struct phy_device *phydev, int index, DP83867_LED_POLARITY(index), polarity); } +static unsigned int dp83867_inband_caps(struct phy_device *phydev, + phy_interface_t interface) +{ + if (interface == PHY_INTERFACE_MODE_SGMII) + return LINK_INBAND_ENABLE | LINK_INBAND_DISABLE; + + return 0; +} + +static int dp83867_config_inband(struct phy_device *phydev, unsigned int modes) +{ + int val = 0; + + if (modes == LINK_INBAND_ENABLE) + val = DP83867_SGMII_AUTONEG_EN; + + return phy_modify(phydev, DP83867_CFG2, DP83867_SGMII_AUTONEG_EN, val); +} + static struct phy_driver dp83867_driver[] = { { .phy_id = DP83867_PHY_ID, @@ -1149,6 +1168,9 @@ static struct phy_driver dp83867_driver[] = { .led_hw_control_set = dp83867_led_hw_control_set, .led_hw_control_get = dp83867_led_hw_control_get, .led_polarity_set = dp83867_led_polarity_set, + + .inband_caps = dp83867_inband_caps, + .config_inband = dp83867_config_inband, }, }; module_phy_driver(dp83867_driver); |
