net: phy: at803x: add mdix configuration support for AR9331 and AR8035
This patch add MDIX configuration ability for AR9331 and AR8035. Theoretically it should work on other Atheros PHYs, but I was able to test only this two. Since I have no certified reference HW able to detect or configure MDIX, this functionality was confirmed by oscilloscope. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ff9a8c48eb
commit
7dce80c2a5
|
@ -21,6 +21,17 @@
|
|||
#include <linux/regulator/consumer.h>
|
||||
#include <dt-bindings/net/qca-ar803x.h>
|
||||
|
||||
#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
|
||||
#define AT803X_SFC_ASSERT_CRS BIT(11)
|
||||
#define AT803X_SFC_FORCE_LINK BIT(10)
|
||||
#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5)
|
||||
#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3
|
||||
#define AT803X_SFC_MANUAL_MDIX 0x1
|
||||
#define AT803X_SFC_MANUAL_MDI 0x0
|
||||
#define AT803X_SFC_SQE_TEST BIT(2)
|
||||
#define AT803X_SFC_POLARITY_REVERSAL BIT(1)
|
||||
#define AT803X_SFC_DISABLE_JABBER BIT(0)
|
||||
|
||||
#define AT803X_SPECIFIC_STATUS 0x11
|
||||
#define AT803X_SS_SPEED_MASK (3 << 14)
|
||||
#define AT803X_SS_SPEED_1000 (2 << 14)
|
||||
|
@ -703,6 +714,12 @@ static int at803x_read_status(struct phy_device *phydev)
|
|||
return ss;
|
||||
|
||||
if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
|
||||
int sfc;
|
||||
|
||||
sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL);
|
||||
if (sfc < 0)
|
||||
return sfc;
|
||||
|
||||
switch (ss & AT803X_SS_SPEED_MASK) {
|
||||
case AT803X_SS_SPEED_10:
|
||||
phydev->speed = SPEED_10;
|
||||
|
@ -718,10 +735,23 @@ static int at803x_read_status(struct phy_device *phydev)
|
|||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = DUPLEX_HALF;
|
||||
|
||||
if (ss & AT803X_SS_MDIX)
|
||||
phydev->mdix = ETH_TP_MDI_X;
|
||||
else
|
||||
phydev->mdix = ETH_TP_MDI;
|
||||
|
||||
switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) {
|
||||
case AT803X_SFC_MANUAL_MDI:
|
||||
phydev->mdix_ctrl = ETH_TP_MDI;
|
||||
break;
|
||||
case AT803X_SFC_MANUAL_MDIX:
|
||||
phydev->mdix_ctrl = ETH_TP_MDI_X;
|
||||
break;
|
||||
case AT803X_SFC_AUTOMATIC_CROSSOVER:
|
||||
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
|
||||
|
@ -730,6 +760,50 @@ static int at803x_read_status(struct phy_device *phydev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
switch (ctrl) {
|
||||
case ETH_TP_MDI:
|
||||
val = AT803X_SFC_MANUAL_MDI;
|
||||
break;
|
||||
case ETH_TP_MDI_X:
|
||||
val = AT803X_SFC_MANUAL_MDIX;
|
||||
break;
|
||||
case ETH_TP_MDI_AUTO:
|
||||
val = AT803X_SFC_AUTOMATIC_CROSSOVER;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL,
|
||||
AT803X_SFC_MDI_CROSSOVER_MODE_M,
|
||||
FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val));
|
||||
}
|
||||
|
||||
static int at803x_config_aneg(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = at803x_config_mdix(phydev, phydev->mdix_ctrl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Changes of the midx bits are disruptive to the normal operation;
|
||||
* therefore any changes to these registers must be followed by a
|
||||
* software reset to take effect.
|
||||
*/
|
||||
if (ret == 1) {
|
||||
ret = genphy_soft_reset(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return genphy_config_aneg(phydev);
|
||||
}
|
||||
|
||||
static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
|
||||
{
|
||||
int val;
|
||||
|
@ -979,6 +1053,7 @@ static struct phy_driver at803x_driver[] = {
|
|||
.flags = PHY_POLL_CABLE_TEST,
|
||||
.probe = at803x_probe,
|
||||
.remove = at803x_remove,
|
||||
.config_aneg = at803x_config_aneg,
|
||||
.config_init = at803x_config_init,
|
||||
.soft_reset = genphy_soft_reset,
|
||||
.set_wol = at803x_set_wol,
|
||||
|
@ -1061,6 +1136,9 @@ static struct phy_driver at803x_driver[] = {
|
|||
.config_intr = &at803x_config_intr,
|
||||
.cable_test_start = at803x_cable_test_start,
|
||||
.cable_test_get_status = at803x_cable_test_get_status,
|
||||
.read_status = at803x_read_status,
|
||||
.soft_reset = genphy_soft_reset,
|
||||
.config_aneg = at803x_config_aneg,
|
||||
} };
|
||||
|
||||
module_phy_driver(at803x_driver);
|
||||
|
|
Loading…
Reference in New Issue