]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: phy: mscc: report and configure in-band auto-negotiation for SGMII/QSGMII
authorVladimir Oltean <vladimir.oltean@nxp.com>
Wed, 13 Aug 2025 07:44:54 +0000 (10:44 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 13 Nov 2025 20:37:01 +0000 (15:37 -0500)
[ Upstream commit df979273bd716a93ca9ffa8f84aeb205c9bf2ab6 ]

The following Vitesse/Microsemi/Microchip PHYs, among those supported by
this driver, have the host interface configurable as SGMII or QSGMII:
- VSC8504
- VSC8514
- VSC8552
- VSC8562
- VSC8572
- VSC8574
- VSC8575
- VSC8582
- VSC8584

All these PHYs are documented to have bit 7 of "MAC SerDes PCS Control"
as "MAC SerDes ANEG enable".

Out of these, I could test the VSC8514 quad PHY in QSGMII. This works
both with the in-band autoneg on and off, on the NXP LS1028A-RDB and
T1040-RDB boards.

Notably, the bit is sticky (survives soft resets), so giving Linux the
tools to read and modify this settings makes it robust to changes made
to it by previous boot layers (U-Boot).

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Link: https://patch.msgid.link/20250813074454.63224-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/net/phy/mscc/mscc.h
drivers/net/phy/mscc/mscc_main.c

index 2bfe314ef881c30510110cb2a1fb9846e46ae7b1..2d8eca54c40a290e9ff1de3a5b8f787a0282563c 100644 (file)
@@ -196,6 +196,9 @@ enum rgmii_clock_delay {
 #define MSCC_PHY_EXTENDED_INT_MS_EGR     BIT(9)
 
 /* Extended Page 3 Registers */
+#define MSCC_PHY_SERDES_PCS_CTRL         16
+#define MSCC_PHY_SERDES_ANEG             BIT(7)
+
 #define MSCC_PHY_SERDES_TX_VALID_CNT     21
 #define MSCC_PHY_SERDES_TX_CRC_ERR_CNT   22
 #define MSCC_PHY_SERDES_RX_VALID_CNT     28
index 24c75903f535437fbce0a73ba91282f20fa73f5c..ef0ef1570d39234d8aeea829dc0a97150236bf51 100644 (file)
@@ -2202,6 +2202,28 @@ static int vsc85xx_read_status(struct phy_device *phydev)
        return genphy_read_status(phydev);
 }
 
+static unsigned int vsc85xx_inband_caps(struct phy_device *phydev,
+                                       phy_interface_t interface)
+{
+       if (interface != PHY_INTERFACE_MODE_SGMII &&
+           interface != PHY_INTERFACE_MODE_QSGMII)
+               return 0;
+
+       return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
+}
+
+static int vsc85xx_config_inband(struct phy_device *phydev, unsigned int modes)
+{
+       u16 reg_val = 0;
+
+       if (modes == LINK_INBAND_ENABLE)
+               reg_val = MSCC_PHY_SERDES_ANEG;
+
+       return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_3,
+                               MSCC_PHY_SERDES_PCS_CTRL, MSCC_PHY_SERDES_ANEG,
+                               reg_val);
+}
+
 static int vsc8514_probe(struct phy_device *phydev)
 {
        struct vsc8531_private *vsc8531;
@@ -2414,6 +2436,8 @@ static struct phy_driver vsc85xx_driver[] = {
        .get_sset_count = &vsc85xx_get_sset_count,
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
+       .inband_caps    = vsc85xx_inband_caps,
+       .config_inband  = vsc85xx_config_inband,
 },
 {
        .phy_id         = PHY_ID_VSC8514,
@@ -2437,6 +2461,8 @@ static struct phy_driver vsc85xx_driver[] = {
        .get_sset_count = &vsc85xx_get_sset_count,
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
+       .inband_caps    = vsc85xx_inband_caps,
+       .config_inband  = vsc85xx_config_inband,
 },
 {
        .phy_id         = PHY_ID_VSC8530,
@@ -2557,6 +2583,8 @@ static struct phy_driver vsc85xx_driver[] = {
        .get_sset_count = &vsc85xx_get_sset_count,
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
+       .inband_caps    = vsc85xx_inband_caps,
+       .config_inband  = vsc85xx_config_inband,
 },
 {
        .phy_id         = PHY_ID_VSC856X,
@@ -2579,6 +2607,8 @@ static struct phy_driver vsc85xx_driver[] = {
        .get_sset_count = &vsc85xx_get_sset_count,
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
+       .inband_caps    = vsc85xx_inband_caps,
+       .config_inband  = vsc85xx_config_inband,
 },
 {
        .phy_id         = PHY_ID_VSC8572,
@@ -2605,6 +2635,8 @@ static struct phy_driver vsc85xx_driver[] = {
        .get_sset_count = &vsc85xx_get_sset_count,
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
+       .inband_caps    = vsc85xx_inband_caps,
+       .config_inband  = vsc85xx_config_inband,
 },
 {
        .phy_id         = PHY_ID_VSC8574,
@@ -2631,6 +2663,8 @@ static struct phy_driver vsc85xx_driver[] = {
        .get_sset_count = &vsc85xx_get_sset_count,
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
+       .inband_caps    = vsc85xx_inband_caps,
+       .config_inband  = vsc85xx_config_inband,
 },
 {
        .phy_id         = PHY_ID_VSC8575,
@@ -2655,6 +2689,8 @@ static struct phy_driver vsc85xx_driver[] = {
        .get_sset_count = &vsc85xx_get_sset_count,
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
+       .inband_caps    = vsc85xx_inband_caps,
+       .config_inband  = vsc85xx_config_inband,
 },
 {
        .phy_id         = PHY_ID_VSC8582,
@@ -2679,6 +2715,8 @@ static struct phy_driver vsc85xx_driver[] = {
        .get_sset_count = &vsc85xx_get_sset_count,
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
+       .inband_caps    = vsc85xx_inband_caps,
+       .config_inband  = vsc85xx_config_inband,
 },
 {
        .phy_id         = PHY_ID_VSC8584,
@@ -2704,6 +2742,8 @@ static struct phy_driver vsc85xx_driver[] = {
        .get_strings    = &vsc85xx_get_strings,
        .get_stats      = &vsc85xx_get_stats,
        .link_change_notify = &vsc85xx_link_change_notify,
+       .inband_caps    = vsc85xx_inband_caps,
+       .config_inband  = vsc85xx_config_inband,
 }
 
 };