]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: phy: vitesse: implement MDI-X configuration in vsc73xx
authorPawel Dembicki <paweldembicki@gmail.com>
Mon, 26 Aug 2024 09:37:10 +0000 (11:37 +0200)
committerJakub Kicinski <kuba@kernel.org>
Tue, 27 Aug 2024 21:26:49 +0000 (14:26 -0700)
This commit introduces MDI-X configuration support in vsc73xx phys.

Vsc73xx supports only auto mode or forced MDI.

Vsc73xx have auto MDI-X disabled by default in forced speed mode.
This commit enables it.

Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20240826093710.511837-1-paweldembicki@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/vitesse.c

index 54eb4e8377c447b90c2c9a1e0790119cbbc53268..2377179de017b54d4af07a9c19e4154876e49603 100644 (file)
 #define MII_VSC73XX_DOWNSHIFT_MAX              5
 #define MII_VSC73XX_DOWNSHIFT_INVAL            1
 
+/* VSC73XX PHY_BYPASS_CTRL register*/
+#define MII_VSC73XX_PHY_BYPASS_CTRL            MII_DCOUNTER
+#define MII_VSC73XX_PBC_TX_DIS                 BIT(15)
+#define MII_VSC73XX_PBC_FOR_SPD_AUTO_MDIX_DIS  BIT(7)
+#define MII_VSC73XX_PBC_PAIR_SWAP_DIS          BIT(5)
+#define MII_VSC73XX_PBC_POL_INV_DIS            BIT(4)
+#define MII_VSC73XX_PBC_PARALLEL_DET_DIS       BIT(3)
+#define MII_VSC73XX_PBC_AUTO_NP_EXCHANGE_DIS   BIT(1)
+
+/* VSC73XX PHY_AUX_CTRL_STAT register */
+#define MII_VSC73XX_PHY_AUX_CTRL_STAT  MII_NCONFIG
+#define MII_VSC73XX_PACS_NO_MDI_X_IND  BIT(13)
+
 /* Vitesse VSC8601 Extended PHY Control Register 1 */
 #define MII_VSC8601_EPHY_CTL           0x17
 #define MII_VSC8601_EPHY_CTL_RGMII_SKEW        (1 << 8)
@@ -219,6 +232,9 @@ static void vsc73xx_config_init(struct phy_device *phydev)
 
        /* Enable downshift by default */
        vsc73xx_set_downshift(phydev, MII_VSC73XX_DOWNSHIFT_MAX);
+
+       /* Set Auto MDI-X by default */
+       phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
 }
 
 static int vsc738x_config_init(struct phy_device *phydev)
@@ -319,6 +335,75 @@ static int vsc739x_config_init(struct phy_device *phydev)
        return 0;
 }
 
+static int vsc73xx_mdix_set(struct phy_device *phydev, u8 mdix)
+{
+       int ret;
+       u16 val;
+
+       val = phy_read(phydev, MII_VSC73XX_PHY_BYPASS_CTRL);
+
+       switch (mdix) {
+       case ETH_TP_MDI:
+               val |= MII_VSC73XX_PBC_FOR_SPD_AUTO_MDIX_DIS |
+                      MII_VSC73XX_PBC_PAIR_SWAP_DIS |
+                      MII_VSC73XX_PBC_POL_INV_DIS;
+               break;
+       case ETH_TP_MDI_X:
+               /* When MDI-X auto configuration is disabled, is possible
+                * to force only MDI mode. Let's use autoconfig for forced
+                * MDIX mode.
+                */
+       case ETH_TP_MDI_AUTO:
+               val &= ~(MII_VSC73XX_PBC_FOR_SPD_AUTO_MDIX_DIS |
+                        MII_VSC73XX_PBC_PAIR_SWAP_DIS |
+                        MII_VSC73XX_PBC_POL_INV_DIS);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = phy_write(phydev, MII_VSC73XX_PHY_BYPASS_CTRL, val);
+       if (ret)
+               return ret;
+
+       return genphy_restart_aneg(phydev);
+}
+
+static int vsc73xx_config_aneg(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = vsc73xx_mdix_set(phydev, phydev->mdix_ctrl);
+       if (ret)
+               return ret;
+
+       return genphy_config_aneg(phydev);
+}
+
+static int vsc73xx_mdix_get(struct phy_device *phydev, u8 *mdix)
+{
+       u16 reg_val;
+
+       reg_val = phy_read(phydev, MII_VSC73XX_PHY_AUX_CTRL_STAT);
+       if (reg_val & MII_VSC73XX_PACS_NO_MDI_X_IND)
+               *mdix = ETH_TP_MDI;
+       else
+               *mdix = ETH_TP_MDI_X;
+
+       return 0;
+}
+
+static int vsc73xx_read_status(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = vsc73xx_mdix_get(phydev, &phydev->mdix);
+       if (ret < 0)
+               return ret;
+
+       return genphy_read_status(phydev);
+}
+
 /* This adds a skew for both TX and RX clocks, so the skew should only be
  * applied to "rgmii-id" interfaces. It may not work as expected
  * on "rgmii-txid", "rgmii-rxid" or "rgmii" interfaces.
@@ -516,6 +601,8 @@ static struct phy_driver vsc82xx_driver[] = {
        .phy_id_mask    = 0x000ffff0,
        /* PHY_GBIT_FEATURES */
        .config_init    = vsc738x_config_init,
+       .config_aneg    = vsc73xx_config_aneg,
+       .read_status    = vsc73xx_read_status,
        .read_page      = vsc73xx_read_page,
        .write_page     = vsc73xx_write_page,
        .get_tunable    = vsc73xx_get_tunable,
@@ -526,6 +613,8 @@ static struct phy_driver vsc82xx_driver[] = {
        .phy_id_mask    = 0x000ffff0,
        /* PHY_GBIT_FEATURES */
        .config_init    = vsc738x_config_init,
+       .config_aneg    = vsc73xx_config_aneg,
+       .read_status    = vsc73xx_read_status,
        .read_page      = vsc73xx_read_page,
        .write_page     = vsc73xx_write_page,
        .get_tunable    = vsc73xx_get_tunable,
@@ -536,6 +625,8 @@ static struct phy_driver vsc82xx_driver[] = {
        .phy_id_mask    = 0x000ffff0,
        /* PHY_GBIT_FEATURES */
        .config_init    = vsc739x_config_init,
+       .config_aneg    = vsc73xx_config_aneg,
+       .read_status    = vsc73xx_read_status,
        .read_page      = vsc73xx_read_page,
        .write_page     = vsc73xx_write_page,
        .get_tunable    = vsc73xx_get_tunable,
@@ -546,6 +637,8 @@ static struct phy_driver vsc82xx_driver[] = {
        .phy_id_mask    = 0x000ffff0,
        /* PHY_GBIT_FEATURES */
        .config_init    = vsc739x_config_init,
+       .config_aneg    = vsc73xx_config_aneg,
+       .read_status    = vsc73xx_read_status,
        .read_page      = vsc73xx_read_page,
        .write_page     = vsc73xx_write_page,
        .get_tunable    = vsc73xx_get_tunable,