Commit 3c42563b authored by Sean Anderson's avatar Sean Anderson Committed by David S. Miller

net: phy: aquantia: Add support for rate matching

This adds support for rate matching for phys similar to the AQR107. We
assume that all phys using aqr107_read_status support rate matching.
However, it could be possible to determine support based on the firmware
revision if there are phys discovered which do not support rate
matching.  However, as rate matching is advertised in the datasheets for
these phys, I suspect it is supported most boards.

Despite the name, the "config" registers are updated with the current
rate matching method (if any). Because they appear to be updated
automatically, I don't know if these registers can be used to disable
rate matching.
Signed-off-by: default avatarSean Anderson <sean.anderson@seco.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7de26bf1
...@@ -97,6 +97,19 @@ ...@@ -97,6 +97,19 @@
#define VEND1_GLOBAL_GEN_STAT2 0xc831 #define VEND1_GLOBAL_GEN_STAT2 0xc831
#define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15) #define VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG BIT(15)
/* The following registers all have similar layouts; first the registers... */
#define VEND1_GLOBAL_CFG_10M 0x0310
#define VEND1_GLOBAL_CFG_100M 0x031b
#define VEND1_GLOBAL_CFG_1G 0x031c
#define VEND1_GLOBAL_CFG_2_5G 0x031d
#define VEND1_GLOBAL_CFG_5G 0x031e
#define VEND1_GLOBAL_CFG_10G 0x031f
/* ...and now the fields */
#define VEND1_GLOBAL_CFG_RATE_ADAPT GENMASK(8, 7)
#define VEND1_GLOBAL_CFG_RATE_ADAPT_NONE 0
#define VEND1_GLOBAL_CFG_RATE_ADAPT_USX 1
#define VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE 2
#define VEND1_GLOBAL_RSVD_STAT1 0xc885 #define VEND1_GLOBAL_RSVD_STAT1 0xc885
#define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4) #define VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID GENMASK(7, 4)
#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0) #define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0)
...@@ -347,40 +360,57 @@ static int aqr_read_status(struct phy_device *phydev) ...@@ -347,40 +360,57 @@ static int aqr_read_status(struct phy_device *phydev)
static int aqr107_read_rate(struct phy_device *phydev) static int aqr107_read_rate(struct phy_device *phydev)
{ {
u32 config_reg;
int val; int val;
val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1); val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1);
if (val < 0) if (val < 0)
return val; return val;
if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
switch (FIELD_GET(MDIO_AN_TX_VEND_STATUS1_RATE_MASK, val)) { switch (FIELD_GET(MDIO_AN_TX_VEND_STATUS1_RATE_MASK, val)) {
case MDIO_AN_TX_VEND_STATUS1_10BASET: case MDIO_AN_TX_VEND_STATUS1_10BASET:
phydev->speed = SPEED_10; phydev->speed = SPEED_10;
config_reg = VEND1_GLOBAL_CFG_10M;
break; break;
case MDIO_AN_TX_VEND_STATUS1_100BASETX: case MDIO_AN_TX_VEND_STATUS1_100BASETX:
phydev->speed = SPEED_100; phydev->speed = SPEED_100;
config_reg = VEND1_GLOBAL_CFG_100M;
break; break;
case MDIO_AN_TX_VEND_STATUS1_1000BASET: case MDIO_AN_TX_VEND_STATUS1_1000BASET:
phydev->speed = SPEED_1000; phydev->speed = SPEED_1000;
config_reg = VEND1_GLOBAL_CFG_1G;
break; break;
case MDIO_AN_TX_VEND_STATUS1_2500BASET: case MDIO_AN_TX_VEND_STATUS1_2500BASET:
phydev->speed = SPEED_2500; phydev->speed = SPEED_2500;
config_reg = VEND1_GLOBAL_CFG_2_5G;
break; break;
case MDIO_AN_TX_VEND_STATUS1_5000BASET: case MDIO_AN_TX_VEND_STATUS1_5000BASET:
phydev->speed = SPEED_5000; phydev->speed = SPEED_5000;
config_reg = VEND1_GLOBAL_CFG_5G;
break; break;
case MDIO_AN_TX_VEND_STATUS1_10GBASET: case MDIO_AN_TX_VEND_STATUS1_10GBASET:
phydev->speed = SPEED_10000; phydev->speed = SPEED_10000;
config_reg = VEND1_GLOBAL_CFG_10G;
break; break;
default: default:
phydev->speed = SPEED_UNKNOWN; phydev->speed = SPEED_UNKNOWN;
break; return 0;
} }
if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX) val = phy_read_mmd(phydev, MDIO_MMD_VEND1, config_reg);
phydev->duplex = DUPLEX_FULL; if (val < 0)
return val;
if (FIELD_GET(VEND1_GLOBAL_CFG_RATE_ADAPT, val) ==
VEND1_GLOBAL_CFG_RATE_ADAPT_PAUSE)
phydev->rate_matching = RATE_MATCH_PAUSE;
else else
phydev->duplex = DUPLEX_HALF; phydev->rate_matching = RATE_MATCH_NONE;
return 0; return 0;
} }
...@@ -645,6 +675,16 @@ static int aqr107_wait_processor_intensive_op(struct phy_device *phydev) ...@@ -645,6 +675,16 @@ static int aqr107_wait_processor_intensive_op(struct phy_device *phydev)
return 0; return 0;
} }
static int aqr107_get_rate_matching(struct phy_device *phydev,
phy_interface_t iface)
{
if (iface == PHY_INTERFACE_MODE_10GBASER ||
iface == PHY_INTERFACE_MODE_2500BASEX ||
iface == PHY_INTERFACE_MODE_NA)
return RATE_MATCH_PAUSE;
return RATE_MATCH_NONE;
}
static int aqr107_suspend(struct phy_device *phydev) static int aqr107_suspend(struct phy_device *phydev)
{ {
int err; int err;
...@@ -718,6 +758,7 @@ static struct phy_driver aqr_driver[] = { ...@@ -718,6 +758,7 @@ static struct phy_driver aqr_driver[] = {
PHY_ID_MATCH_MODEL(PHY_ID_AQR107), PHY_ID_MATCH_MODEL(PHY_ID_AQR107),
.name = "Aquantia AQR107", .name = "Aquantia AQR107",
.probe = aqr107_probe, .probe = aqr107_probe,
.get_rate_matching = aqr107_get_rate_matching,
.config_init = aqr107_config_init, .config_init = aqr107_config_init,
.config_aneg = aqr_config_aneg, .config_aneg = aqr_config_aneg,
.config_intr = aqr_config_intr, .config_intr = aqr_config_intr,
...@@ -736,6 +777,7 @@ static struct phy_driver aqr_driver[] = { ...@@ -736,6 +777,7 @@ static struct phy_driver aqr_driver[] = {
PHY_ID_MATCH_MODEL(PHY_ID_AQCS109), PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
.name = "Aquantia AQCS109", .name = "Aquantia AQCS109",
.probe = aqr107_probe, .probe = aqr107_probe,
.get_rate_matching = aqr107_get_rate_matching,
.config_init = aqcs109_config_init, .config_init = aqcs109_config_init,
.config_aneg = aqr_config_aneg, .config_aneg = aqr_config_aneg,
.config_intr = aqr_config_intr, .config_intr = aqr_config_intr,
...@@ -762,6 +804,7 @@ static struct phy_driver aqr_driver[] = { ...@@ -762,6 +804,7 @@ static struct phy_driver aqr_driver[] = {
PHY_ID_MATCH_MODEL(PHY_ID_AQR113C), PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
.name = "Aquantia AQR113C", .name = "Aquantia AQR113C",
.probe = aqr107_probe, .probe = aqr107_probe,
.get_rate_matching = aqr107_get_rate_matching,
.config_init = aqr107_config_init, .config_init = aqr107_config_init,
.config_aneg = aqr_config_aneg, .config_aneg = aqr_config_aneg,
.config_intr = aqr_config_intr, .config_intr = aqr_config_intr,
......
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