mirror of
https://git.openwrt.org/openwrt/openwrt.git
synced 2026-01-28 03:37:17 +01:00
airoha: add pending patch to fix Aeonsemi AS21xxx PHY
Add pending patch to make address some workaround needed to make the Aeonsemi AS21xxx PHY working on the Airoha AN7581/AN7583 board. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
parent
26da4bf552
commit
927fe598db
6 changed files with 590 additions and 0 deletions
|
|
@ -0,0 +1,129 @@
|
|||
From f2c6f8711c3866caafee997cfa60af4f38879be0 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 25 Jun 2025 00:45:11 +0200
|
||||
Subject: [PATCH 1/2] net: phy: add PHY_DETACH_NO_HW_RESET PHY flag
|
||||
|
||||
Some PHY require a firmware to correctly work and such firmware might
|
||||
get reset when the GPIO reset is assert.
|
||||
|
||||
This is the case for the Aeonsemi PHY where when the PHY is torn down,
|
||||
phy_detach() is called that assert the GPIO reset pin resetting the
|
||||
firmware.
|
||||
|
||||
To handle this introduce a flag, PHY_DETACH_NO_HW_RESET that instruct
|
||||
phy_detach() to skip asserting the GPIO reset on detaching the PHY.
|
||||
|
||||
The PHY is still reset in all other case where it's removed or the PHY
|
||||
fails to probe.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/net/phy/as21xxx.c | 10 ++++++++++
|
||||
drivers/net/phy/phy_device.c | 3 ++-
|
||||
include/linux/phy.h | 1 +
|
||||
3 files changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/phy/as21xxx.c
|
||||
+++ b/drivers/net/phy/as21xxx.c
|
||||
@@ -964,6 +964,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1),
|
||||
@@ -976,6 +977,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1),
|
||||
@@ -988,6 +990,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1),
|
||||
@@ -1000,6 +1003,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1),
|
||||
@@ -1012,6 +1016,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1),
|
||||
@@ -1024,6 +1029,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1),
|
||||
@@ -1036,6 +1042,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1),
|
||||
@@ -1048,6 +1055,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1),
|
||||
@@ -1060,6 +1068,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1),
|
||||
@@ -1072,6 +1081,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
+ .flags = PHY_DETACH_NO_RESET,
|
||||
},
|
||||
};
|
||||
module_phy_driver(as21xxx_drivers);
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -2074,7 +2074,8 @@ void phy_detach(struct phy_device *phyde
|
||||
device_release_driver(&phydev->mdio.dev);
|
||||
|
||||
/* Assert the reset signal */
|
||||
- phy_device_reset(phydev, 1);
|
||||
+ if (!(phydev->drv->flags & PHY_DETACH_NO_HW_RESET))
|
||||
+ phy_device_reset(phydev, 1);
|
||||
|
||||
/*
|
||||
* The phydev might go away on the put_device() below, so avoid
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -90,6 +90,7 @@ extern const int phy_10gbit_features_arr
|
||||
#define PHY_RST_AFTER_CLK_EN 0x00000002
|
||||
#define PHY_POLL_CABLE_TEST 0x00000004
|
||||
#define PHY_ALWAYS_CALL_SUSPEND 0x00000008
|
||||
+#define PHY_DETACH_NO_HW_RESET 0x00000010
|
||||
#define MDIO_DEVICE_IS_PHY 0x80000000
|
||||
|
||||
/**
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
From 7ad1470c3d08c1abea747aa0c789e924f63fcbc4 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Wed, 25 Jun 2025 00:51:45 +0200
|
||||
Subject: [PATCH 2/2] net: phy: as21xxx: add flag PHY_DETACH_NO_HW_RESET
|
||||
|
||||
Add flag PHY_DETACH_NO_HW_RESET to handle firmware getting reset on
|
||||
calling phy_detach() if the GPIO reset PIN is defined in DT.
|
||||
|
||||
This will skip the firmware from getting reset permitting the PHY to
|
||||
continue work when the PHY is torn down and gets up again.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/net/phy/as21xxx.c | 20 ++++++++++----------
|
||||
1 file changed, 10 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/as21xxx.c
|
||||
+++ b/drivers/net/phy/as21xxx.c
|
||||
@@ -964,7 +964,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21011PB1),
|
||||
@@ -977,7 +977,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21010PB1),
|
||||
@@ -990,7 +990,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21010JB1),
|
||||
@@ -1003,7 +1003,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21210PB1),
|
||||
@@ -1016,7 +1016,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21510JB1),
|
||||
@@ -1029,7 +1029,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21510PB1),
|
||||
@@ -1042,7 +1042,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21511JB1),
|
||||
@@ -1055,7 +1055,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21210JB1),
|
||||
@@ -1068,7 +1068,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(PHY_ID_AS21511PB1),
|
||||
@@ -1081,7 +1081,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
.led_hw_control_get = as21xxx_led_hw_control_get,
|
||||
.led_polarity_set = as21xxx_led_polarity_set,
|
||||
- .flags = PHY_DETACH_NO_RESET,
|
||||
+ .flags = PHY_DETACH_NO_HW_RESET,
|
||||
},
|
||||
};
|
||||
module_phy_driver(as21xxx_drivers);
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
From 0146a02d9d182796c3d8e4a432c4d94cac042f8e Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Mon, 7 Jul 2025 18:58:25 +0200
|
||||
Subject: [PATCH 1/4] net: phy: as21xxx: handle corner case with link and
|
||||
autoneg complete
|
||||
|
||||
Add missing case in custom read_link, when autoneg is started, autoneg
|
||||
complete bit is reset but link is still not up.
|
||||
|
||||
Fixes: 830877d89edc ("net: phy: Add support for Aeonsemi AS21xxx PHYs")
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/net/phy/as21xxx.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/as21xxx.c
|
||||
+++ b/drivers/net/phy/as21xxx.c
|
||||
@@ -658,6 +658,13 @@ static int as21xxx_read_link(struct phy_
|
||||
return status;
|
||||
|
||||
phydev->link = !!(status & MDIO_STAT1_LSTATUS);
|
||||
+ phydev->autoneg_complete = !!(status & MDIO_AN_STAT1_COMPLETE);
|
||||
+
|
||||
+ /* Consider the case that autoneg was started and "aneg complete"
|
||||
+ * bit has been reset, but "link up" bit not yet.
|
||||
+ */
|
||||
+ if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete)
|
||||
+ phydev->link = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
From d90186b1e48dd4a428abf889b1eb17d2469de08b Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Tue, 8 Jul 2025 10:50:42 +0200
|
||||
Subject: [PATCH 2/4] net: phy: as21xxx: fix read_status speed handling
|
||||
|
||||
With further test with 2.5G NIC it was discovered that
|
||||
phy_resolve_aneg_linkmode is not enough to detect speed higher that 1G
|
||||
when autoneg is enabled.
|
||||
|
||||
Also in the switch case there is a typo where the speed mask is AND with
|
||||
VEND1_SPEED_STATUS instead of the correct mask VEND1_SPEED_MASK.
|
||||
|
||||
Rework the read_status code to always read the speed from the vendor
|
||||
register and parse the generic bit only for the pause frame.
|
||||
|
||||
Fixes: 830877d89edc ("net: phy: Add support for Aeonsemi AS21xxx PHYs")
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/net/phy/as21xxx.c | 96 +++++++++++++++++++++------------------
|
||||
1 file changed, 53 insertions(+), 43 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/as21xxx.c
|
||||
+++ b/drivers/net/phy/as21xxx.c
|
||||
@@ -671,7 +671,7 @@ static int as21xxx_read_link(struct phy_
|
||||
|
||||
static int as21xxx_read_c22_lpa(struct phy_device *phydev)
|
||||
{
|
||||
- int lpagb;
|
||||
+ int lpagb, lpa;
|
||||
|
||||
/* MII_STAT1000 are only filled in the mapped C22
|
||||
* in C45, use that to fill lpagb values and check.
|
||||
@@ -698,12 +698,20 @@ static int as21xxx_read_c22_lpa(struct p
|
||||
mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
|
||||
lpagb);
|
||||
|
||||
+ lpa = phy_read_mmd(phydev, MDIO_MMD_AN,
|
||||
+ AS21XXX_MDIO_AN_C22 + MII_LPA);
|
||||
+ if (lpa < 0)
|
||||
+ return lpa;
|
||||
+
|
||||
+ mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, lpa);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int as21xxx_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int bmcr, old_link = phydev->link;
|
||||
+ int speed;
|
||||
int ret;
|
||||
|
||||
ret = as21xxx_read_link(phydev, &bmcr);
|
||||
@@ -720,58 +728,60 @@ static int as21xxx_read_status(struct ph
|
||||
phydev->asym_pause = 0;
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE) {
|
||||
- ret = genphy_c45_read_lpa(phydev);
|
||||
- if (ret)
|
||||
- return ret;
|
||||
+ if (!phydev->autoneg_complete) {
|
||||
+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising,
|
||||
+ 0);
|
||||
+ mii_lpa_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
ret = as21xxx_read_c22_lpa(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
-
|
||||
- phy_resolve_aneg_linkmode(phydev);
|
||||
} else {
|
||||
- int speed;
|
||||
-
|
||||
linkmode_zero(phydev->lp_advertising);
|
||||
+ }
|
||||
|
||||
- speed = phy_read_mmd(phydev, MDIO_MMD_VEND1,
|
||||
- VEND1_SPEED_STATUS);
|
||||
- if (speed < 0)
|
||||
- return speed;
|
||||
-
|
||||
- switch (speed & VEND1_SPEED_STATUS) {
|
||||
- case VEND1_SPEED_10000:
|
||||
- phydev->speed = SPEED_10000;
|
||||
+ speed = phy_read_mmd(phydev, MDIO_MMD_VEND1,
|
||||
+ VEND1_SPEED_STATUS);
|
||||
+ if (speed < 0)
|
||||
+ return speed;
|
||||
+
|
||||
+ switch (speed & VEND1_SPEED_MASK) {
|
||||
+ case VEND1_SPEED_10000:
|
||||
+ phydev->speed = SPEED_10000;
|
||||
+ phydev->duplex = DUPLEX_FULL;
|
||||
+ break;
|
||||
+ case VEND1_SPEED_5000:
|
||||
+ phydev->speed = SPEED_5000;
|
||||
+ phydev->duplex = DUPLEX_FULL;
|
||||
+ break;
|
||||
+ case VEND1_SPEED_2500:
|
||||
+ phydev->speed = SPEED_2500;
|
||||
+ phydev->duplex = DUPLEX_FULL;
|
||||
+ break;
|
||||
+ case VEND1_SPEED_1000:
|
||||
+ phydev->speed = SPEED_1000;
|
||||
+ if (bmcr & BMCR_FULLDPLX)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
- break;
|
||||
- case VEND1_SPEED_5000:
|
||||
- phydev->speed = SPEED_5000;
|
||||
- phydev->duplex = DUPLEX_FULL;
|
||||
- break;
|
||||
- case VEND1_SPEED_2500:
|
||||
- phydev->speed = SPEED_2500;
|
||||
- phydev->duplex = DUPLEX_FULL;
|
||||
- break;
|
||||
- case VEND1_SPEED_1000:
|
||||
- phydev->speed = SPEED_1000;
|
||||
- if (bmcr & BMCR_FULLDPLX)
|
||||
- phydev->duplex = DUPLEX_FULL;
|
||||
- else
|
||||
- phydev->duplex = DUPLEX_HALF;
|
||||
- break;
|
||||
- case VEND1_SPEED_100:
|
||||
- phydev->speed = SPEED_100;
|
||||
- phydev->duplex = DUPLEX_FULL;
|
||||
- break;
|
||||
- case VEND1_SPEED_10:
|
||||
- phydev->speed = SPEED_10;
|
||||
- phydev->duplex = DUPLEX_FULL;
|
||||
- break;
|
||||
- default:
|
||||
- return -EINVAL;
|
||||
- }
|
||||
+ else
|
||||
+ phydev->duplex = DUPLEX_HALF;
|
||||
+ break;
|
||||
+ case VEND1_SPEED_100:
|
||||
+ phydev->speed = SPEED_100;
|
||||
+ phydev->duplex = DUPLEX_FULL;
|
||||
+ break;
|
||||
+ case VEND1_SPEED_10:
|
||||
+ phydev->speed = SPEED_10;
|
||||
+ phydev->duplex = DUPLEX_FULL;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
}
|
||||
|
||||
+ if (phydev->autoneg == AUTONEG_ENABLE)
|
||||
+ phy_resolve_aneg_pause(phydev);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
From 6003da596beb6b8974e61b7ff494476a323fbef5 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Tue, 8 Jul 2025 11:29:49 +0200
|
||||
Subject: [PATCH 3/4] net: phy: as21xxx: force C45 OPs for AUTONEG
|
||||
|
||||
With further testing with 2.5G NIC, it was discovered that the PHY
|
||||
require the C45 OPs to configure and restart ANEG or speed higher than
|
||||
1G doesn't function correctly.
|
||||
|
||||
To force C45 OPs with generic PHY function, clear the C22 bit from
|
||||
devices_in_package bitmask.
|
||||
|
||||
Fixes: 830877d89edc ("net: phy: Add support for Aeonsemi AS21xxx PHYs")
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/net/phy/as21xxx.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/as21xxx.c
|
||||
+++ b/drivers/net/phy/as21xxx.c
|
||||
@@ -616,6 +616,13 @@ static int as21xxx_probe(struct phy_devi
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ /* Even if PHY declare support for Clause 22 register,
|
||||
+ * Clause 45 register should be used for ANEG configuration
|
||||
+ * and restart. Clear the C22 bit for devices_in_package to
|
||||
+ * force C45 generic OPs in generic PHY ANGE OPs.
|
||||
+ */
|
||||
+ phydev->c45_ids.devices_in_package &= ~BIT(0);
|
||||
+
|
||||
ret = aeon_ipc_sync_parity(phydev, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
From fabaa8a7183d10217e14af437fd3805bd6dd9eba Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Sat, 18 Oct 2025 04:12:41 +0200
|
||||
Subject: [PATCH] net: phy: as21xxx: implement read workaround for C45 read
|
||||
|
||||
This PHY have lots of problems with MDIO read operation. We somehow
|
||||
workaround this with using C45 operation for pretty much everything but
|
||||
this is not enough. The reference code for this PHY makes a write to an
|
||||
unused PHY to workaround this read problem. This was also confirmed by
|
||||
Aeonsemi.
|
||||
|
||||
Various test were made to try to workaround this ins alternative way
|
||||
than the random write.
|
||||
|
||||
One effective solution was to limit the write only to BMSR. And also
|
||||
write to BMSR is safe since they are only read only registers.
|
||||
|
||||
This is only done for read operation as write operation doesn't suffer
|
||||
from this problem.
|
||||
|
||||
Worth to mention that when multiple Aeonsemi PHY are mounted, the
|
||||
workaround doesn't work if we write to another Aeonsemi PHY.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/net/phy/as21xxx.c | 25 +++++++++++++++++++++++++
|
||||
1 file changed, 25 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/as21xxx.c
|
||||
+++ b/drivers/net/phy/as21xxx.c
|
||||
@@ -966,6 +966,21 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int as21xxx_read_mmd(struct phy_device *phydev, int devad,
|
||||
+ u16 regnum)
|
||||
+{
|
||||
+ struct mii_bus *bus = phydev->mdio.bus;
|
||||
+ int val;
|
||||
+
|
||||
+ val = __mdiobus_c45_read(bus, phydev->mdio.addr, devad,
|
||||
+ regnum);
|
||||
+
|
||||
+ /* FIXME: verify if it's actually ok to limit this to MII_BMSR */
|
||||
+ __mdiobus_write(bus, 0x0, MII_BMSR, 0x1);
|
||||
+
|
||||
+ return val;
|
||||
+}
|
||||
+
|
||||
static struct phy_driver as21xxx_drivers[] = {
|
||||
{
|
||||
/* PHY expose in C45 as 0x7500 0x9410
|
||||
@@ -983,6 +998,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
@@ -996,6 +1012,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
@@ -1009,6 +1026,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
@@ -1022,6 +1040,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
@@ -1035,6 +1054,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
@@ -1048,6 +1068,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
@@ -1061,6 +1082,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
@@ -1074,6 +1096,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
@@ -1087,6 +1110,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
@@ -1100,6 +1124,7 @@ static struct phy_driver as21xxx_drivers
|
||||
.probe = as21xxx_probe,
|
||||
.match_phy_device = as21xxx_match_phy_device,
|
||||
.read_status = as21xxx_read_status,
|
||||
+ .read_mmd = as21xxx_read_mmd,
|
||||
.led_brightness_set = as21xxx_led_brightness_set,
|
||||
.led_hw_is_supported = as21xxx_led_hw_is_supported,
|
||||
.led_hw_control_set = as21xxx_led_hw_control_set,
|
||||
Loading…
Add table
Reference in a new issue