mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 01:11:14 +00:00
149 lines
4.9 KiB
Diff
149 lines
4.9 KiB
Diff
|
From 3c42563b30417afc8855a3b4c1b38c2f36f78657 Mon Sep 17 00:00:00 2001
|
||
|
From: Sean Anderson <sean.anderson@seco.com>
|
||
|
Date: Tue, 20 Sep 2022 18:12:35 -0400
|
||
|
Subject: [PATCH] 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: Sean Anderson <sean.anderson@seco.com>
|
||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||
|
---
|
||
|
drivers/net/phy/aquantia_main.c | 51 ++++++++++++++++++++++++++++++---
|
||
|
1 file changed, 47 insertions(+), 4 deletions(-)
|
||
|
|
||
|
--- a/drivers/net/phy/aquantia_main.c
|
||
|
+++ b/drivers/net/phy/aquantia_main.c
|
||
|
@@ -97,6 +97,19 @@
|
||
|
#define VEND1_GLOBAL_GEN_STAT2 0xc831
|
||
|
#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_FW_BUILD_ID GENMASK(7, 4)
|
||
|
#define VEND1_GLOBAL_RSVD_STAT1_PROV_ID GENMASK(3, 0)
|
||
|
@@ -347,40 +360,57 @@ static int aqr_read_status(struct phy_de
|
||
|
|
||
|
static int aqr107_read_rate(struct phy_device *phydev)
|
||
|
{
|
||
|
+ u32 config_reg;
|
||
|
int val;
|
||
|
|
||
|
val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_TX_VEND_STATUS1);
|
||
|
if (val < 0)
|
||
|
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)) {
|
||
|
case MDIO_AN_TX_VEND_STATUS1_10BASET:
|
||
|
phydev->speed = SPEED_10;
|
||
|
+ config_reg = VEND1_GLOBAL_CFG_10M;
|
||
|
break;
|
||
|
case MDIO_AN_TX_VEND_STATUS1_100BASETX:
|
||
|
phydev->speed = SPEED_100;
|
||
|
+ config_reg = VEND1_GLOBAL_CFG_100M;
|
||
|
break;
|
||
|
case MDIO_AN_TX_VEND_STATUS1_1000BASET:
|
||
|
phydev->speed = SPEED_1000;
|
||
|
+ config_reg = VEND1_GLOBAL_CFG_1G;
|
||
|
break;
|
||
|
case MDIO_AN_TX_VEND_STATUS1_2500BASET:
|
||
|
phydev->speed = SPEED_2500;
|
||
|
+ config_reg = VEND1_GLOBAL_CFG_2_5G;
|
||
|
break;
|
||
|
case MDIO_AN_TX_VEND_STATUS1_5000BASET:
|
||
|
phydev->speed = SPEED_5000;
|
||
|
+ config_reg = VEND1_GLOBAL_CFG_5G;
|
||
|
break;
|
||
|
case MDIO_AN_TX_VEND_STATUS1_10GBASET:
|
||
|
phydev->speed = SPEED_10000;
|
||
|
+ config_reg = VEND1_GLOBAL_CFG_10G;
|
||
|
break;
|
||
|
default:
|
||
|
phydev->speed = SPEED_UNKNOWN;
|
||
|
- break;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
- if (val & MDIO_AN_TX_VEND_STATUS1_FULL_DUPLEX)
|
||
|
- phydev->duplex = DUPLEX_FULL;
|
||
|
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, config_reg);
|
||
|
+ 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
|
||
|
- phydev->duplex = DUPLEX_HALF;
|
||
|
+ phydev->rate_matching = RATE_MATCH_NONE;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -647,6 +677,16 @@ static int aqr107_wait_processor_intensi
|
||
|
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)
|
||
|
{
|
||
|
int err;
|
||
|
@@ -720,6 +760,7 @@ static struct phy_driver aqr_driver[] =
|
||
|
PHY_ID_MATCH_MODEL(PHY_ID_AQR107),
|
||
|
.name = "Aquantia AQR107",
|
||
|
.probe = aqr107_probe,
|
||
|
+ .get_rate_matching = aqr107_get_rate_matching,
|
||
|
.config_init = aqr107_config_init,
|
||
|
.config_aneg = aqr_config_aneg,
|
||
|
.config_intr = aqr_config_intr,
|
||
|
@@ -738,6 +779,7 @@ static struct phy_driver aqr_driver[] =
|
||
|
PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
|
||
|
.name = "Aquantia AQCS109",
|
||
|
.probe = aqr107_probe,
|
||
|
+ .get_rate_matching = aqr107_get_rate_matching,
|
||
|
.config_init = aqcs109_config_init,
|
||
|
.config_aneg = aqr_config_aneg,
|
||
|
.config_intr = aqr_config_intr,
|
||
|
@@ -764,6 +806,7 @@ static struct phy_driver aqr_driver[] =
|
||
|
PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
|
||
|
.name = "Aquantia AQR113C",
|
||
|
.probe = aqr107_probe,
|
||
|
+ .get_rate_matching = aqr107_get_rate_matching,
|
||
|
.config_init = aqr107_config_init,
|
||
|
.config_aneg = aqr_config_aneg,
|
||
|
.config_intr = aqr_config_intr,
|