diff mbox series

[RFC] drivers: net: mdio_bus: try indirect clause 45 regs access

Message ID 3e2c01449dc29bc3d138d3a19e0c2220495dd7ed.1589710856.git.baruch@tkos.co.il
State New
Headers show
Series [RFC] drivers: net: mdio_bus: try indirect clause 45 regs access | expand

Commit Message

Baruch Siach May 17, 2020, 10:20 a.m. UTC
When the MDIO bus does not support directly clause 45 access, fallback
to indirect registers access method to read/write clause 45 registers
using clause 22 registers.

Signed-off-by: Baruch Siach <baruch@tkos.co.il>
---

Is that the right course?

Currently, this does not really work on the my target machine, which is
using the Armada 385 native MDIO bus (mvmdio) connected to clause 45
Marvell 88E2110 PHY. Registers MDIO_DEVS1 and MDIO_DEVS1 read bogus
values which breaks PHY identification. However, the phytool utility
reads the same registers correctly:

phytool eth1/2:1/5
ieee-phy: reg:0x05 val:0x008a

eth1 is connected to another PHY (clause 22) on the same MDIO bus.

The same hardware works nicely with the mdio-gpio bus implementation,
when mdio pins are muxed as GPIOs.
---
 drivers/net/phy/mdio_bus.c | 12 ++++++++++++
 drivers/net/phy/phy-core.c |  2 +-
 include/linux/phy.h        |  2 ++
 3 files changed, 15 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 7a4eb3f2cb74..12e39f794b29 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -790,6 +790,12 @@  int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
 	WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
 
 	retval = bus->read(bus, addr, regnum);
+	if (retval == -EOPNOTSUPP && regnum & MII_ADDR_C45) {
+		int c45_devad = (regnum >> 16) & 0x1f;
+
+		mmd_phy_indirect(bus, addr, c45_devad, regnum & 0xfff);
+		retval = bus->read(bus, addr, MII_MMD_DATA);
+	}
 
 	trace_mdio_access(bus, 1, addr, regnum, retval, retval);
 	mdiobus_stats_acct(&bus->stats[addr], true, retval);
@@ -816,6 +822,12 @@  int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
 	WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
 
 	err = bus->write(bus, addr, regnum, val);
+	if (err == -EOPNOTSUPP && regnum & MII_ADDR_C45) {
+		int c45_devad = (regnum >> 16) & 0x1f;
+
+		mmd_phy_indirect(bus, addr, c45_devad, regnum & 0xfff);
+		err = bus->write(bus, addr, MII_MMD_DATA, val);
+	}
 
 	trace_mdio_access(bus, 0, addr, regnum, val, err);
 	mdiobus_stats_acct(&bus->stats[addr], false, err);
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 66b8c61ca74c..74b8cf8599aa 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -395,7 +395,7 @@  int phy_speed_down_core(struct phy_device *phydev)
 	return __set_linkmode_max_speed(min_common_speed, phydev->advertising);
 }
 
-static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
+void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
 			     u16 regnum)
 {
 	/* Write the desired MMD Devad */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 2432ca463ddc..6e7a5fc1906f 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -864,6 +864,8 @@  int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
 		     u16 mask, u16 set);
 int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
 		   u16 mask, u16 set);
+void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
+		      u16 regnum);
 
 /**
  * __phy_set_bits - Convenience function for setting bits in a PHY register