Skip to content

Commit

Permalink
net: phy: at803x: add downshift support
Browse files Browse the repository at this point in the history
The AR8031 and AR8035 support the link speed downshift. Add driver
support for it. One peculiarity of these PHYs is that it needs a
software reset after changing the setting, thus add the .soft_reset()
op and do a phy_init_hw() if necessary.

This was tested on a custom board with the AR8031.

Signed-off-by: Michael Walle <michael@walle.cc>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Michael Walle authored and David S. Miller committed May 1, 2020
1 parent 838974e commit cde0f4f
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions drivers/net/phy/at803x.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
#define AT803X_INTR_STATUS 0x13

#define AT803X_SMART_SPEED 0x14
#define AT803X_SMART_SPEED_ENABLE BIT(5)
#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1)
#define AT803X_LED_CONTROL 0x18

#define AT803X_DEVICE_ADDR 0x03
Expand Down Expand Up @@ -103,6 +106,10 @@
#define AT803X_CLK_OUT_STRENGTH_HALF 1
#define AT803X_CLK_OUT_STRENGTH_QUARTER 2

#define AT803X_DEFAULT_DOWNSHIFT 5
#define AT803X_MIN_DOWNSHIFT 2
#define AT803X_MAX_DOWNSHIFT 9

#define ATH9331_PHY_ID 0x004dd041
#define ATH8030_PHY_ID 0x004dd076
#define ATH8031_PHY_ID 0x004dd074
Expand Down Expand Up @@ -713,6 +720,80 @@ static int at803x_read_status(struct phy_device *phydev)
return 0;
}

static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
{
int val;

val = phy_read(phydev, AT803X_SMART_SPEED);
if (val < 0)
return val;

if (val & AT803X_SMART_SPEED_ENABLE)
*d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2;
else
*d = DOWNSHIFT_DEV_DISABLE;

return 0;
}

static int at803x_set_downshift(struct phy_device *phydev, u8 cnt)
{
u16 mask, set;
int ret;

switch (cnt) {
case DOWNSHIFT_DEV_DEFAULT_COUNT:
cnt = AT803X_DEFAULT_DOWNSHIFT;
fallthrough;
case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT:
set = AT803X_SMART_SPEED_ENABLE |
AT803X_SMART_SPEED_BYPASS_TIMER |
FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2);
mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK;
break;
case DOWNSHIFT_DEV_DISABLE:
set = 0;
mask = AT803X_SMART_SPEED_ENABLE |
AT803X_SMART_SPEED_BYPASS_TIMER;
break;
default:
return -EINVAL;
}

ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set);

/* After changing the smart speed settings, we need to perform a
* software reset, use phy_init_hw() to make sure we set the
* reapply any values which might got lost during software reset.
*/
if (ret == 1)
ret = phy_init_hw(phydev);

return ret;
}

static int at803x_get_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna, void *data)
{
switch (tuna->id) {
case ETHTOOL_PHY_DOWNSHIFT:
return at803x_get_downshift(phydev, data);
default:
return -EOPNOTSUPP;
}
}

static int at803x_set_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna, const void *data)
{
switch (tuna->id) {
case ETHTOOL_PHY_DOWNSHIFT:
return at803x_set_downshift(phydev, *(const u8 *)data);
default:
return -EOPNOTSUPP;
}
}

static struct phy_driver at803x_driver[] = {
{
/* Qualcomm Atheros AR8035 */
Expand All @@ -722,6 +803,7 @@ static struct phy_driver at803x_driver[] = {
.probe = at803x_probe,
.remove = at803x_remove,
.config_init = at803x_config_init,
.soft_reset = genphy_soft_reset,
.set_wol = at803x_set_wol,
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
Expand All @@ -730,6 +812,8 @@ static struct phy_driver at803x_driver[] = {
.read_status = at803x_read_status,
.ack_interrupt = at803x_ack_interrupt,
.config_intr = at803x_config_intr,
.get_tunable = at803x_get_tunable,
.set_tunable = at803x_set_tunable,
}, {
/* Qualcomm Atheros AR8030 */
.phy_id = ATH8030_PHY_ID,
Expand All @@ -754,6 +838,7 @@ static struct phy_driver at803x_driver[] = {
.probe = at803x_probe,
.remove = at803x_remove,
.config_init = at803x_config_init,
.soft_reset = genphy_soft_reset,
.set_wol = at803x_set_wol,
.get_wol = at803x_get_wol,
.suspend = at803x_suspend,
Expand All @@ -763,6 +848,8 @@ static struct phy_driver at803x_driver[] = {
.aneg_done = at803x_aneg_done,
.ack_interrupt = &at803x_ack_interrupt,
.config_intr = &at803x_config_intr,
.get_tunable = at803x_get_tunable,
.set_tunable = at803x_set_tunable,
}, {
/* Qualcomm Atheros AR8032 */
PHY_ID_MATCH_EXACT(ATH8032_PHY_ID),
Expand Down

0 comments on commit cde0f4f

Please sign in to comment.