[PATCH v6 06/14] net: phy: add qca8081 read_status
From: Luo Jie
Date: Sat Oct 23 2021 - 05:56:05 EST
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@xxxxxxxxxxxxxx>
---
drivers/net/phy/at803x.c | 95 ++++++++++++++++++++++++++++++----------
1 file changed, 73 insertions(+), 22 deletions(-)
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index aae27fe3e1e1..cecf78e6c643 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -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);
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project