generic: add fix for AQR113 PMD Global Transmit Disable bit
PMD Global Transmit Disable bit should be cleared for normal operation. This should be HW default, however I found that on Asus RT-AX89X that uses AQR113C PHY and firmware 5.4 this bit is set by default. With this bit set the AQR cannot achieve a link with its link-partner and it took me multiple hours of digging through the vendor GPL source to find this out, so lets always clear this bit during .config_init() to avoid a situation like this in the future. aqr107_wait_processor_intensive_op() is moved up because datasheet notes that any changes to this bit are processor intensive. This is a modified version of patch that got merged upstream as AQR113C has a separate config_init() upstream. Link: https://github.com/openwrt/openwrt/pull/15840 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
parent
cc459f55e1
commit
bb907d8d44
@ -0,0 +1,103 @@
|
|||||||
|
From cffac22c9215f1883d3848c788f9b03656dced27 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robert Marko <robimarko@gmail.com>
|
||||||
|
Date: Sun, 11 Feb 2024 18:39:19 +0100
|
||||||
|
Subject: [PATCH] net: phy: aquantia: clear PMD Global Transmit Disable bit
|
||||||
|
during init
|
||||||
|
|
||||||
|
PMD Global Transmit Disable bit should be cleared for normal operation.
|
||||||
|
This should be HW default, however I found that on Asus RT-AX89X that uses
|
||||||
|
AQR113C PHY and firmware 5.4 this bit is set by default.
|
||||||
|
|
||||||
|
With this bit set the AQR cannot achieve a link with its link-partner and
|
||||||
|
it took me multiple hours of digging through the vendor GPL source to find
|
||||||
|
this out, so lets always clear this bit during .config_init() to avoid a
|
||||||
|
situation like this in the future.
|
||||||
|
|
||||||
|
aqr107_wait_processor_intensive_op() is moved up because datasheet notes
|
||||||
|
that any changes to this bit are processor intensive.
|
||||||
|
|
||||||
|
Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||||
|
---
|
||||||
|
drivers/net/phy/aquantia/aquantia_main.c | 57 ++++++++++++++----------
|
||||||
|
1 file changed, 33 insertions(+), 24 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/aquantia/aquantia_main.c
|
||||||
|
+++ b/drivers/net/phy/aquantia/aquantia_main.c
|
||||||
|
@@ -507,6 +507,30 @@ static void aqr107_chip_info(struct phy_
|
||||||
|
fw_major, fw_minor, build_id, prov_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int aqr107_wait_processor_intensive_op(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ int val, err;
|
||||||
|
+
|
||||||
|
+ /* The datasheet notes to wait at least 1ms after issuing a
|
||||||
|
+ * processor intensive operation before checking.
|
||||||
|
+ * We cannot use the 'sleep_before_read' parameter of read_poll_timeout
|
||||||
|
+ * because that just determines the maximum time slept, not the minimum.
|
||||||
|
+ */
|
||||||
|
+ usleep_range(1000, 5000);
|
||||||
|
+
|
||||||
|
+ err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
|
||||||
|
+ VEND1_GLOBAL_GEN_STAT2, val,
|
||||||
|
+ !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG),
|
||||||
|
+ AQR107_OP_IN_PROG_SLEEP,
|
||||||
|
+ AQR107_OP_IN_PROG_TIMEOUT, false);
|
||||||
|
+ if (err) {
|
||||||
|
+ phydev_err(phydev, "timeout: processor-intensive MDIO operation\n");
|
||||||
|
+ return err;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int aqr107_config_init(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
@@ -530,6 +554,15 @@ static int aqr107_config_init(struct phy
|
||||||
|
if (!ret)
|
||||||
|
aqr107_chip_info(phydev);
|
||||||
|
|
||||||
|
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
|
||||||
|
+ MDIO_PMD_TXDIS_GLOBAL);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = aqr107_wait_processor_intensive_op(phydev);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -600,30 +633,6 @@ static void aqr107_link_change_notify(st
|
||||||
|
phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int aqr107_wait_processor_intensive_op(struct phy_device *phydev)
|
||||||
|
-{
|
||||||
|
- int val, err;
|
||||||
|
-
|
||||||
|
- /* The datasheet notes to wait at least 1ms after issuing a
|
||||||
|
- * processor intensive operation before checking.
|
||||||
|
- * We cannot use the 'sleep_before_read' parameter of read_poll_timeout
|
||||||
|
- * because that just determines the maximum time slept, not the minimum.
|
||||||
|
- */
|
||||||
|
- usleep_range(1000, 5000);
|
||||||
|
-
|
||||||
|
- err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
|
||||||
|
- VEND1_GLOBAL_GEN_STAT2, val,
|
||||||
|
- !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG),
|
||||||
|
- AQR107_OP_IN_PROG_SLEEP,
|
||||||
|
- AQR107_OP_IN_PROG_TIMEOUT, false);
|
||||||
|
- if (err) {
|
||||||
|
- phydev_err(phydev, "timeout: processor-intensive MDIO operation\n");
|
||||||
|
- return err;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static int aqr107_get_rate_matching(struct phy_device *phydev,
|
||||||
|
phy_interface_t iface)
|
||||||
|
{
|
@ -0,0 +1,103 @@
|
|||||||
|
From cffac22c9215f1883d3848c788f9b03656dced27 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robert Marko <robimarko@gmail.com>
|
||||||
|
Date: Sun, 11 Feb 2024 18:39:19 +0100
|
||||||
|
Subject: [PATCH] net: phy: aquantia: clear PMD Global Transmit Disable bit
|
||||||
|
during init
|
||||||
|
|
||||||
|
PMD Global Transmit Disable bit should be cleared for normal operation.
|
||||||
|
This should be HW default, however I found that on Asus RT-AX89X that uses
|
||||||
|
AQR113C PHY and firmware 5.4 this bit is set by default.
|
||||||
|
|
||||||
|
With this bit set the AQR cannot achieve a link with its link-partner and
|
||||||
|
it took me multiple hours of digging through the vendor GPL source to find
|
||||||
|
this out, so lets always clear this bit during .config_init() to avoid a
|
||||||
|
situation like this in the future.
|
||||||
|
|
||||||
|
aqr107_wait_processor_intensive_op() is moved up because datasheet notes
|
||||||
|
that any changes to this bit are processor intensive.
|
||||||
|
|
||||||
|
Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||||
|
---
|
||||||
|
drivers/net/phy/aquantia/aquantia_main.c | 57 ++++++++++++++----------
|
||||||
|
1 file changed, 33 insertions(+), 24 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/aquantia/aquantia_main.c
|
||||||
|
+++ b/drivers/net/phy/aquantia/aquantia_main.c
|
||||||
|
@@ -473,6 +473,30 @@ static void aqr107_chip_info(struct phy_
|
||||||
|
fw_major, fw_minor, build_id, prov_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int aqr107_wait_processor_intensive_op(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ int val, err;
|
||||||
|
+
|
||||||
|
+ /* The datasheet notes to wait at least 1ms after issuing a
|
||||||
|
+ * processor intensive operation before checking.
|
||||||
|
+ * We cannot use the 'sleep_before_read' parameter of read_poll_timeout
|
||||||
|
+ * because that just determines the maximum time slept, not the minimum.
|
||||||
|
+ */
|
||||||
|
+ usleep_range(1000, 5000);
|
||||||
|
+
|
||||||
|
+ err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
|
||||||
|
+ VEND1_GLOBAL_GEN_STAT2, val,
|
||||||
|
+ !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG),
|
||||||
|
+ AQR107_OP_IN_PROG_SLEEP,
|
||||||
|
+ AQR107_OP_IN_PROG_TIMEOUT, false);
|
||||||
|
+ if (err) {
|
||||||
|
+ phydev_err(phydev, "timeout: processor-intensive MDIO operation\n");
|
||||||
|
+ return err;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int aqr107_config_init(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
struct aqr107_priv *priv = phydev->priv;
|
||||||
|
@@ -498,6 +522,15 @@ static int aqr107_config_init(struct phy
|
||||||
|
if (!ret)
|
||||||
|
aqr107_chip_info(phydev);
|
||||||
|
|
||||||
|
+ ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
|
||||||
|
+ MDIO_PMD_TXDIS_GLOBAL);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = aqr107_wait_processor_intensive_op(phydev);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
ret = aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
@@ -580,30 +613,6 @@ static void aqr107_link_change_notify(st
|
||||||
|
phydev_info(phydev, "Aquantia 1000Base-T2 mode active\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int aqr107_wait_processor_intensive_op(struct phy_device *phydev)
|
||||||
|
-{
|
||||||
|
- int val, err;
|
||||||
|
-
|
||||||
|
- /* The datasheet notes to wait at least 1ms after issuing a
|
||||||
|
- * processor intensive operation before checking.
|
||||||
|
- * We cannot use the 'sleep_before_read' parameter of read_poll_timeout
|
||||||
|
- * because that just determines the maximum time slept, not the minimum.
|
||||||
|
- */
|
||||||
|
- usleep_range(1000, 5000);
|
||||||
|
-
|
||||||
|
- err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1,
|
||||||
|
- VEND1_GLOBAL_GEN_STAT2, val,
|
||||||
|
- !(val & VEND1_GLOBAL_GEN_STAT2_OP_IN_PROG),
|
||||||
|
- AQR107_OP_IN_PROG_SLEEP,
|
||||||
|
- AQR107_OP_IN_PROG_TIMEOUT, false);
|
||||||
|
- if (err) {
|
||||||
|
- phydev_err(phydev, "timeout: processor-intensive MDIO operation\n");
|
||||||
|
- return err;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static int aqr107_get_rate_matching(struct phy_device *phydev,
|
||||||
|
phy_interface_t iface)
|
||||||
|
{
|
@ -106,7 +106,7 @@ Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
|
|||||||
static int aqr_config_intr(struct phy_device *phydev)
|
static int aqr_config_intr(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
|
bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
|
||||||
@@ -860,6 +930,30 @@ static struct phy_driver aqr_driver[] =
|
@@ -869,6 +939,30 @@ static struct phy_driver aqr_driver[] =
|
||||||
.get_stats = aqr107_get_stats,
|
.get_stats = aqr107_get_stats,
|
||||||
.link_change_notify = aqr107_link_change_notify,
|
.link_change_notify = aqr107_link_change_notify,
|
||||||
},
|
},
|
||||||
@ -137,7 +137,7 @@ Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
|
|||||||
};
|
};
|
||||||
|
|
||||||
module_phy_driver(aqr_driver);
|
module_phy_driver(aqr_driver);
|
||||||
@@ -877,6 +971,8 @@ static struct mdio_device_id __maybe_unu
|
@@ -886,6 +980,8 @@ static struct mdio_device_id __maybe_unu
|
||||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113) },
|
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113) },
|
||||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
|
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
|
||||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
|
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
|
||||||
|
@ -21,7 +21,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|||||||
|
|
||||||
#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
|
#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
|
||||||
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
|
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
|
||||||
@@ -960,6 +962,30 @@ static struct phy_driver aqr_driver[] =
|
@@ -969,6 +971,30 @@ static struct phy_driver aqr_driver[] =
|
||||||
.get_strings = aqr107_get_strings,
|
.get_strings = aqr107_get_strings,
|
||||||
.get_stats = aqr107_get_stats,
|
.get_stats = aqr107_get_stats,
|
||||||
},
|
},
|
||||||
@ -52,7 +52,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|||||||
};
|
};
|
||||||
|
|
||||||
module_phy_driver(aqr_driver);
|
module_phy_driver(aqr_driver);
|
||||||
@@ -979,6 +1005,8 @@ static struct mdio_device_id __maybe_unu
|
@@ -988,6 +1014,8 @@ static struct mdio_device_id __maybe_unu
|
||||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
|
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
|
||||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
|
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
|
||||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
|
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
|
||||||
|
@ -97,7 +97,7 @@ Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
|
|||||||
static int aqr_config_intr(struct phy_device *phydev)
|
static int aqr_config_intr(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
|
bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
|
||||||
@@ -807,7 +875,7 @@ static struct phy_driver aqr_driver[] =
|
@@ -816,7 +884,7 @@ static struct phy_driver aqr_driver[] =
|
||||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
|
PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
|
||||||
.name = "Aquantia AQR112",
|
.name = "Aquantia AQR112",
|
||||||
.probe = aqr107_probe,
|
.probe = aqr107_probe,
|
||||||
@ -106,7 +106,7 @@ Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
|
|||||||
.config_intr = aqr_config_intr,
|
.config_intr = aqr_config_intr,
|
||||||
.handle_interrupt = aqr_handle_interrupt,
|
.handle_interrupt = aqr_handle_interrupt,
|
||||||
.get_tunable = aqr107_get_tunable,
|
.get_tunable = aqr107_get_tunable,
|
||||||
@@ -830,7 +898,7 @@ static struct phy_driver aqr_driver[] =
|
@@ -839,7 +907,7 @@ static struct phy_driver aqr_driver[] =
|
||||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
|
PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
|
||||||
.name = "Aquantia AQR412",
|
.name = "Aquantia AQR412",
|
||||||
.probe = aqr107_probe,
|
.probe = aqr107_probe,
|
||||||
|
@ -21,7 +21,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|||||||
|
|
||||||
#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
|
#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
|
||||||
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
|
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
|
||||||
@@ -1014,6 +1016,30 @@ static struct phy_driver aqr_driver[] =
|
@@ -1023,6 +1025,30 @@ static struct phy_driver aqr_driver[] =
|
||||||
.led_hw_control_get = aqr_phy_led_hw_control_get,
|
.led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||||
.led_polarity_set = aqr_phy_led_polarity_set,
|
.led_polarity_set = aqr_phy_led_polarity_set,
|
||||||
},
|
},
|
||||||
@ -52,7 +52,7 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
|||||||
};
|
};
|
||||||
|
|
||||||
module_phy_driver(aqr_driver);
|
module_phy_driver(aqr_driver);
|
||||||
@@ -1034,6 +1060,8 @@ static struct mdio_device_id __maybe_unu
|
@@ -1043,6 +1069,8 @@ static struct mdio_device_id __maybe_unu
|
||||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
|
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
|
||||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) },
|
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) },
|
||||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
|
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user