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
@@ -967,6 +967,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
@@ -984,6 +999,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,
@@ -997,6 +1013,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,
@@ -1010,6 +1027,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,
@@ -1023,6 +1041,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,
@@ -1036,6 +1055,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,
@@ -1049,6 +1069,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,
@@ -1062,6 +1083,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,
@@ -1075,6 +1097,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,
@@ -1088,6 +1111,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,
@@ -1101,6 +1125,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,
