RealTek 2.5GE PHYs have all standard Clause-22 registers mapped also
inside MDIO_MMD_VEND2 at offset 0xa400. This is used mainly in case the
PHY is inside a copper SFP module which uses the RollBall MDIO-over-I2C
method which *only* supports Clause-45. In order to support such
modules, the PHY driver has previously been split into a C22-only and
C45-only instances, creating quite a bit of redundancy and confusion.
In preparation of reunifying the two driver instances, add support for
translating MDIO_MMD_VEND2 registers 0xa400 to 0xa438 back to standard
Clause-22 access in case the PHY is accessed on a Clause-22 bus.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/net/phy/realtek/realtek_main.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c
index 7302b25b8908b..886694ff995f6 100644
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -143,6 +143,7 @@
#define RTL822X_VND2_TO_PAGE(reg) ((reg) >> 4)
#define RTL822X_VND2_TO_PAGE_REG(reg) (16 + (((reg) & GENMASK(3, 0)) >> 1))
+#define RTL822X_VND2_TO_C22_REG(reg) (((reg) - 0xa400) / 2)
#define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg))
#define RTL8221B_VND2_INER 0xa4d2
@@ -1264,6 +1265,11 @@ static int rtl822xb_read_mmd(struct phy_device *phydev, int devnum, u16 reg)
return mmd_phy_read(phydev->mdio.bus, phydev->mdio.addr,
phydev->is_c45, devnum, reg);
+ /* Simplify access to C22-registers addressed inside MDIO_MMD_VEND2 */
+ if (reg >= RTL822X_VND2_C22_REG(0) &&
+ reg <= RTL822X_VND2_C22_REG(30))
+ return __phy_read(phydev, RTL822X_VND2_TO_C22_REG(reg));
+
/* Use paged access for MDIO_MMD_VEND2 over Clause-22 */
page = RTL822X_VND2_TO_PAGE(reg);
oldpage = __phy_read(phydev, RTL821x_PAGE_SELECT);
@@ -1299,6 +1305,11 @@ static int rtl822xb_write_mmd(struct phy_device *phydev, int devnum, u16 reg,
return mmd_phy_write(phydev->mdio.bus, phydev->mdio.addr,
phydev->is_c45, devnum, reg, val);
+ /* Simplify access to C22-registers addressed inside MDIO_MMD_VEND2 */
+ if (reg >= RTL822X_VND2_C22_REG(0) &&
+ reg <= RTL822X_VND2_C22_REG(30))
+ return __phy_write(phydev, RTL822X_VND2_TO_C22_REG(reg), val);
+
/* Use paged access for MDIO_MMD_VEND2 over Clause-22 */
page = RTL822X_VND2_TO_PAGE(reg);
oldpage = __phy_read(phydev, RTL821x_PAGE_SELECT);
--
2.52.0
On Fri, Jan 09, 2026 at 03:03:22AM +0000, Daniel Golle wrote: > RealTek 2.5GE PHYs have all standard Clause-22 registers mapped also > inside MDIO_MMD_VEND2 at offset 0xa400. This is used mainly in case the > PHY is inside a copper SFP module which uses the RollBall MDIO-over-I2C > method which *only* supports Clause-45. It isn't just Rollball. There are SoCs out there which have separate MDIO buses, one bus signals at 3.3V and can generate only clause 22 frames. The other operates at 1.2V and can only generate clause 45 frames. While hardware may elect to generate and recognise either frame types at either voltage, this goes some way to explain why there are implementations that only support one or the other on a particular pair of MDC/MDIO wires. Armada 8040 has this setup - there is one MDIO bus that only supports clause 22 frames, and there is a separate MDIO bus that only supports clause 45 frames. -- RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
On Fri, Jan 09, 2026 at 09:32:18PM +0000, Russell King (Oracle) wrote: > On Fri, Jan 09, 2026 at 03:03:22AM +0000, Daniel Golle wrote: > > RealTek 2.5GE PHYs have all standard Clause-22 registers mapped also > > inside MDIO_MMD_VEND2 at offset 0xa400. This is used mainly in case the > > PHY is inside a copper SFP module which uses the RollBall MDIO-over-I2C > > method which *only* supports Clause-45. > > It isn't just Rollball. There are SoCs out there which have separate > MDIO buses, one bus signals at 3.3V and can generate only clause 22 > frames. The other operates at 1.2V and can only generate clause 45 > frames. > > While hardware may elect to generate and recognise either frame types > at either voltage, this goes some way to explain why there are > implementations that only support one or the other on a particular > pair of MDC/MDIO wires. > > Armada 8040 has this setup - there is one MDIO bus that only supports > clause 22 frames, and there is a separate MDIO bus that only supports > clause 45 frames. Interesting. And a bit annoying. I wasn't aware of the electrical difference (signal voltage). Never the less, even with this change applied you now get a driver which uses *only* Clause-45 access in case phydev->is_45 is true, and only Clause-22 in case phydev->is_45 is false. From what I understood this was the intended outcome of having two dedicated drivers, and you can have the very same results now with a single driver. If you would like me to broaden the commit message and clarify this, please let me know.
On 1/9/2026 4:03 AM, Daniel Golle wrote: > RealTek 2.5GE PHYs have all standard Clause-22 registers mapped also > inside MDIO_MMD_VEND2 at offset 0xa400. This is used mainly in case the > PHY is inside a copper SFP module which uses the RollBall MDIO-over-I2C > method which *only* supports Clause-45. In order to support such > modules, the PHY driver has previously been split into a C22-only and > C45-only instances, creating quite a bit of redundancy and confusion. > To complement: RTL812x MAC/PHY chips allow access to MDIO_MMD_VEND2 of the integrated PHY only. There is no native C22 MDIO access. > In preparation of reunifying the two driver instances, add support for > translating MDIO_MMD_VEND2 registers 0xa400 to 0xa438 back to standard > Clause-22 access in case the PHY is accessed on a Clause-22 bus. > > Signed-off-by: Daniel Golle <daniel@makrotopia.org> > --- > drivers/net/phy/realtek/realtek_main.c | 11 +++++++++++ > 1 file changed, 11 insertions(+) > > diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c > index 7302b25b8908b..886694ff995f6 100644 > --- a/drivers/net/phy/realtek/realtek_main.c > +++ b/drivers/net/phy/realtek/realtek_main.c > @@ -143,6 +143,7 @@ > > #define RTL822X_VND2_TO_PAGE(reg) ((reg) >> 4) > #define RTL822X_VND2_TO_PAGE_REG(reg) (16 + (((reg) & GENMASK(3, 0)) >> 1)) > +#define RTL822X_VND2_TO_C22_REG(reg) (((reg) - 0xa400) / 2) > #define RTL822X_VND2_C22_REG(reg) (0xa400 + 2 * (reg)) > > #define RTL8221B_VND2_INER 0xa4d2 > @@ -1264,6 +1265,11 @@ static int rtl822xb_read_mmd(struct phy_device *phydev, int devnum, u16 reg) > return mmd_phy_read(phydev->mdio.bus, phydev->mdio.addr, > phydev->is_c45, devnum, reg); > > + /* Simplify access to C22-registers addressed inside MDIO_MMD_VEND2 */ > + if (reg >= RTL822X_VND2_C22_REG(0) && > + reg <= RTL822X_VND2_C22_REG(30)) > + return __phy_read(phydev, RTL822X_VND2_TO_C22_REG(reg)); > + > /* Use paged access for MDIO_MMD_VEND2 over Clause-22 */ > page = RTL822X_VND2_TO_PAGE(reg); > oldpage = __phy_read(phydev, RTL821x_PAGE_SELECT); > @@ -1299,6 +1305,11 @@ static int rtl822xb_write_mmd(struct phy_device *phydev, int devnum, u16 reg, > return mmd_phy_write(phydev->mdio.bus, phydev->mdio.addr, > phydev->is_c45, devnum, reg, val); > > + /* Simplify access to C22-registers addressed inside MDIO_MMD_VEND2 */ > + if (reg >= RTL822X_VND2_C22_REG(0) && > + reg <= RTL822X_VND2_C22_REG(30)) > + return __phy_write(phydev, RTL822X_VND2_TO_C22_REG(reg), val); > + > /* Use paged access for MDIO_MMD_VEND2 over Clause-22 */ > page = RTL822X_VND2_TO_PAGE(reg); > oldpage = __phy_read(phydev, RTL821x_PAGE_SELECT);
© 2016 - 2026 Red Hat, Inc.