OSDN Git Service

net: phy: mxl-gpy: Add PHY Auto/MDI/MDI-X set driver for GPY211 chips
authorRaju Lakkaraju <Raju.Lakkaraju@microchip.com>
Wed, 26 Oct 2022 05:59:18 +0000 (11:29 +0530)
committerDavid S. Miller <davem@davemloft.net>
Fri, 28 Oct 2022 09:35:51 +0000 (10:35 +0100)
Add support for MDI-X status and configuration for GPY211 chips

Signed-off-by: Raju Lakkaraju <Raju.Lakkaraju@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/mxl-gpy.c

index 1383af3..27c0f16 100644 (file)
 #define PHY_ID_GPY241BM                0x67C9DE80
 #define PHY_ID_GPY245B         0x67C9DEC0
 
+#define PHY_CTL1               0x13
+#define PHY_CTL1_MDICD         BIT(3)
+#define PHY_CTL1_MDIAB         BIT(2)
+#define PHY_CTL1_AMDIX         BIT(0)
 #define PHY_MIISTAT            0x18    /* MII state */
 #define PHY_IMASK              0x19    /* interrupt mask */
 #define PHY_ISTAT              0x1A    /* interrupt status */
 #define PHY_FWV_MAJOR_MASK     GENMASK(11, 8)
 #define PHY_FWV_MINOR_MASK     GENMASK(7, 0)
 
+#define PHY_PMA_MGBT_POLARITY  0x82
+#define PHY_MDI_MDI_X_MASK     GENMASK(1, 0)
+#define PHY_MDI_MDI_X_NORMAL   0x3
+#define PHY_MDI_MDI_X_AB       0x2
+#define PHY_MDI_MDI_X_CD       0x1
+#define PHY_MDI_MDI_X_CROSS    0x0
+
 /* SGMII */
 #define VSPEC1_SGMII_CTRL      0x08
 #define VSPEC1_SGMII_CTRL_ANEN BIT(12)         /* Aneg enable */
@@ -289,6 +300,33 @@ static bool gpy_sgmii_aneg_en(struct phy_device *phydev)
        return (ret & VSPEC1_SGMII_CTRL_ANEN) ? true : false;
 }
 
+static int gpy_config_mdix(struct phy_device *phydev, u8 ctrl)
+{
+       int ret;
+       u16 val;
+
+       switch (ctrl) {
+       case ETH_TP_MDI_AUTO:
+               val = PHY_CTL1_AMDIX;
+               break;
+       case ETH_TP_MDI_X:
+               val = (PHY_CTL1_MDIAB | PHY_CTL1_MDICD);
+               break;
+       case ETH_TP_MDI:
+               val = 0;
+               break;
+       default:
+               return 0;
+       }
+
+       ret =  phy_modify(phydev, PHY_CTL1, PHY_CTL1_AMDIX | PHY_CTL1_MDIAB |
+                         PHY_CTL1_MDICD, val);
+       if (ret < 0)
+               return ret;
+
+       return genphy_c45_restart_aneg(phydev);
+}
+
 static int gpy_config_aneg(struct phy_device *phydev)
 {
        bool changed = false;
@@ -304,6 +342,10 @@ static int gpy_config_aneg(struct phy_device *phydev)
                        : genphy_c45_pma_setup_forced(phydev);
        }
 
+       ret = gpy_config_mdix(phydev,  phydev->mdix_ctrl);
+       if (ret < 0)
+               return ret;
+
        ret = genphy_c45_an_config_aneg(phydev);
        if (ret < 0)
                return ret;
@@ -370,6 +412,34 @@ static int gpy_config_aneg(struct phy_device *phydev)
                              VSPEC1_SGMII_CTRL_ANRS, VSPEC1_SGMII_CTRL_ANRS);
 }
 
+static int gpy_update_mdix(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = phy_read(phydev, PHY_CTL1);
+       if (ret < 0)
+               return ret;
+
+       if (ret & PHY_CTL1_AMDIX)
+               phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
+       else
+               if (ret & PHY_CTL1_MDICD || ret & PHY_CTL1_MDIAB)
+                       phydev->mdix_ctrl = ETH_TP_MDI_X;
+               else
+                       phydev->mdix_ctrl = ETH_TP_MDI;
+
+       ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, PHY_PMA_MGBT_POLARITY);
+       if (ret < 0)
+               return ret;
+
+       if ((ret & PHY_MDI_MDI_X_MASK) < PHY_MDI_MDI_X_NORMAL)
+               phydev->mdix = ETH_TP_MDI_X;
+       else
+               phydev->mdix = ETH_TP_MDI;
+
+       return 0;
+}
+
 static int gpy_update_interface(struct phy_device *phydev)
 {
        int ret;
@@ -421,7 +491,7 @@ static int gpy_update_interface(struct phy_device *phydev)
                        return ret;
        }
 
-       return 0;
+       return gpy_update_mdix(phydev);
 }
 
 static int gpy_read_status(struct phy_device *phydev)