Commit 79c7bc05 authored by Luo Jie's avatar Luo Jie Committed by David S. Miller

net: phy: add qca8081 read_status

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: default avatarLuo Jie <luoj@codeaurora.org>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent daf61732
...@@ -41,6 +41,9 @@ ...@@ -41,6 +41,9 @@
#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) #define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11)
#define AT803X_SS_MDIX BIT(6) #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 0x12
#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) #define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) #define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14)
...@@ -959,27 +962,9 @@ static void at803x_link_change_notify(struct phy_device *phydev) ...@@ -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; int ss;
/* 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;
/* Read the AT8035 PHY-Specific Status register, which indicates the /* Read the AT8035 PHY-Specific Status register, which indicates the
* speed and duplex that the PHY is actually using, irrespective of * speed and duplex that the PHY is actually using, irrespective of
...@@ -990,13 +975,19 @@ static int at803x_read_status(struct phy_device *phydev) ...@@ -990,13 +975,19 @@ static int at803x_read_status(struct phy_device *phydev)
return ss; return ss;
if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
int sfc; int sfc, speed;
sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
if (sfc < 0) if (sfc < 0)
return sfc; 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: case AT803X_SS_SPEED_10:
phydev->speed = SPEED_10; phydev->speed = SPEED_10;
break; break;
...@@ -1006,6 +997,9 @@ static int at803x_read_status(struct phy_device *phydev) ...@@ -1006,6 +997,9 @@ static int at803x_read_status(struct phy_device *phydev)
case AT803X_SS_SPEED_1000: case AT803X_SS_SPEED_1000:
phydev->speed = SPEED_1000; phydev->speed = SPEED_1000;
break; break;
case QCA808X_SS_SPEED_2500:
phydev->speed = SPEED_2500;
break;
} }
if (ss & AT803X_SS_DUPLEX) if (ss & AT803X_SS_DUPLEX)
phydev->duplex = DUPLEX_FULL; phydev->duplex = DUPLEX_FULL;
...@@ -1030,6 +1024,35 @@ static int at803x_read_status(struct phy_device *phydev) ...@@ -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) if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
phy_resolve_aneg_pause(phydev); phy_resolve_aneg_pause(phydev);
...@@ -1434,6 +1457,33 @@ static int qca83xx_suspend(struct phy_device *phydev) ...@@ -1434,6 +1457,33 @@ static int qca83xx_suspend(struct phy_device *phydev)
return 0; 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[] = { static struct phy_driver at803x_driver[] = {
{ {
/* Qualcomm Atheros AR8035 */ /* Qualcomm Atheros AR8035 */
...@@ -1605,6 +1655,7 @@ static struct phy_driver at803x_driver[] = { ...@@ -1605,6 +1655,7 @@ static struct phy_driver at803x_driver[] = {
.get_wol = at803x_get_wol, .get_wol = at803x_get_wol,
.suspend = genphy_suspend, .suspend = genphy_suspend,
.resume = genphy_resume, .resume = genphy_resume,
.read_status = qca808x_read_status,
}, }; }, };
module_phy_driver(at803x_driver); module_phy_driver(at803x_driver);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment