OSDN Git Service

net: phy: add qca8081 read_status
authorLuo Jie <luoj@codeaurora.org>
Sun, 24 Oct 2021 08:27:30 +0000 (16:27 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 25 Oct 2021 13:04:18 +0000 (14:04 +0100)
1. Separate the function at803x_read_specific_status from
the at803x_read_status, since it can be reused by the
read_status of qca8081 phy driver excepting adding the
2500M speed.

2. Add the qca8081 read_status function qca808x_read_status.

Signed-off-by: Luo Jie <luoj@codeaurora.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/at803x.c

index aae27fe..cecf78e 100644 (file)
@@ -41,6 +41,9 @@
 #define AT803X_SS_SPEED_DUPLEX_RESOLVED                BIT(11)
 #define AT803X_SS_MDIX                         BIT(6)
 
+#define QCA808X_SS_SPEED_MASK                  GENMASK(9, 7)
+#define QCA808X_SS_SPEED_2500                  4
+
 #define AT803X_INTR_ENABLE                     0x12
 #define AT803X_INTR_ENABLE_AUTONEG_ERR         BIT(15)
 #define AT803X_INTR_ENABLE_SPEED_CHANGED       BIT(14)
@@ -959,27 +962,9 @@ static void at803x_link_change_notify(struct phy_device *phydev)
        }
 }
 
-static int at803x_read_status(struct phy_device *phydev)
+static int at803x_read_specific_status(struct phy_device *phydev)
 {
-       int ss, err, old_link = phydev->link;
-
-       /* Update the link, but return if there was an error */
-       err = genphy_update_link(phydev);
-       if (err)
-               return err;
-
-       /* why bother the PHY if nothing can have changed */
-       if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
-               return 0;
-
-       phydev->speed = SPEED_UNKNOWN;
-       phydev->duplex = DUPLEX_UNKNOWN;
-       phydev->pause = 0;
-       phydev->asym_pause = 0;
-
-       err = genphy_read_lpa(phydev);
-       if (err < 0)
-               return err;
+       int ss;
 
        /* Read the AT8035 PHY-Specific Status register, which indicates the
         * speed and duplex that the PHY is actually using, irrespective of
@@ -990,13 +975,19 @@ static int at803x_read_status(struct phy_device *phydev)
                return ss;
 
        if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
-               int sfc;
+               int sfc, speed;
 
                sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
                if (sfc < 0)
                        return sfc;
 
-               switch (FIELD_GET(AT803X_SS_SPEED_MASK, ss)) {
+               /* qca8081 takes the different bits for speed value from at803x */
+               if (phydev->drv->phy_id == QCA8081_PHY_ID)
+                       speed = FIELD_GET(QCA808X_SS_SPEED_MASK, ss);
+               else
+                       speed = FIELD_GET(AT803X_SS_SPEED_MASK, ss);
+
+               switch (speed) {
                case AT803X_SS_SPEED_10:
                        phydev->speed = SPEED_10;
                        break;
@@ -1006,6 +997,9 @@ static int at803x_read_status(struct phy_device *phydev)
                case AT803X_SS_SPEED_1000:
                        phydev->speed = SPEED_1000;
                        break;
+               case QCA808X_SS_SPEED_2500:
+                       phydev->speed = SPEED_2500;
+                       break;
                }
                if (ss & AT803X_SS_DUPLEX)
                        phydev->duplex = DUPLEX_FULL;
@@ -1030,6 +1024,35 @@ static int at803x_read_status(struct phy_device *phydev)
                }
        }
 
+       return 0;
+}
+
+static int at803x_read_status(struct phy_device *phydev)
+{
+       int err, old_link = phydev->link;
+
+       /* Update the link, but return if there was an error */
+       err = genphy_update_link(phydev);
+       if (err)
+               return err;
+
+       /* why bother the PHY if nothing can have changed */
+       if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
+               return 0;
+
+       phydev->speed = SPEED_UNKNOWN;
+       phydev->duplex = DUPLEX_UNKNOWN;
+       phydev->pause = 0;
+       phydev->asym_pause = 0;
+
+       err = genphy_read_lpa(phydev);
+       if (err < 0)
+               return err;
+
+       err = at803x_read_specific_status(phydev);
+       if (err < 0)
+               return err;
+
        if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
                phy_resolve_aneg_pause(phydev);
 
@@ -1434,6 +1457,33 @@ static int qca83xx_suspend(struct phy_device *phydev)
        return 0;
 }
 
+static int qca808x_read_status(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
+       if (ret < 0)
+               return ret;
+
+       linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising,
+                       ret & MDIO_AN_10GBT_STAT_LP2_5G);
+
+       ret = genphy_read_status(phydev);
+       if (ret)
+               return ret;
+
+       ret = at803x_read_specific_status(phydev);
+       if (ret < 0)
+               return ret;
+
+       if (phydev->link && phydev->speed == SPEED_2500)
+               phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+       else
+               phydev->interface = PHY_INTERFACE_MODE_SMII;
+
+       return 0;
+}
+
 static struct phy_driver at803x_driver[] = {
 {
        /* Qualcomm Atheros AR8035 */
@@ -1605,6 +1655,7 @@ static struct phy_driver at803x_driver[] = {
        .get_wol                = at803x_get_wol,
        .suspend                = genphy_suspend,
        .resume                 = genphy_resume,
+       .read_status            = qca808x_read_status,
 }, };
 
 module_phy_driver(at803x_driver);