realtek: phy: late phy package patching
authorMarkus Stockhausen <[email protected]>
Tue, 19 Aug 2025 09:06:37 +0000 (05:06 -0400)
committerHauke Mehrtens <[email protected]>
Fri, 29 Aug 2025 22:18:18 +0000 (00:18 +0200)
Currently phy packages (like RTL8214x/RTL8218x) are patched and
initialized as soon as the first phy of the package is found.
In this situation the shared structure is not finalized because
devm_phy_package_join() has only been called for the first phy.
This is no issue as the patching directly hammers the bus addresses
for the follow-up phys.

In the future we want to simplify the package handling and allow
to access all phy_device structures from only one phy_device of
the package. With this we can use normal phy_read/phy_write.

Switch the probing logic to "late patching". With this we will
initialize the firmware of the package when the last phy of the
package has been found and thus the shared structure is complete.

Provide get_base_phy() as the first package helper that allows
to determine the first phy of the package from any other phy.

While we are here drop the shared structure that only repeats the
phy name and has no other use.

Signed-off-by: Markus Stockhausen <[email protected]>
Link: https://github.com/openwrt/openwrt/pull/19810
Signed-off-by: Hauke Mehrtens <[email protected]>
target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.c
target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.h

index 1cf18b5ca31660317b0a17afe719be13eb3e4e75..01f24080b8e388ac462072d83366f0853e6607c3 100644 (file)
@@ -106,6 +106,11 @@ static const struct firmware rtl838x_8380_fw;
 static const struct firmware rtl838x_8214fc_fw;
 static const struct firmware rtl838x_8218b_fw;
 
+static inline struct phy_device *get_base_phy(struct phy_device *phydev)
+{
+       return mdiobus_get_phy(phydev->mdio.bus, phydev->shared->base_addr);
+}
+
 static u64 disable_polling(int port)
 {
        u64 saved_state;
@@ -3576,20 +3581,13 @@ static const struct sfp_upstream_ops rtl8214fc_sfp_ops = {
 
 static int rtl8214fc_phy_probe(struct phy_device *phydev)
 {
-       struct device *dev = &phydev->mdio.dev;
-       int addr = phydev->mdio.addr;
+       int base_addr = phydev->mdio.addr & ~3;
        int ret = 0;
 
-       /* All base addresses of the PHYs start at multiples of 8 */
-       devm_phy_package_join(dev, phydev, addr & (~7),
-                               sizeof(struct rtl83xx_shared_private));
-
-       if (!(addr % 8)) {
-               struct rtl83xx_shared_private *shared = phydev->shared->priv;
-               shared->name = "RTL8214FC";
-               /* Configuration must be done while patching still possible */
+       devm_phy_package_join(&phydev->mdio.dev, phydev, base_addr, 0);
+       if (phydev->mdio.addr == base_addr + 3) {
                if (soc_info.family == RTL8380_FAMILY_ID)
-                       ret = rtl8380_configure_rtl8214fc(phydev);
+                       ret = rtl8380_configure_rtl8214fc(get_base_phy(phydev));
                if (ret)
                        return ret;
        }
@@ -3599,39 +3597,23 @@ static int rtl8214fc_phy_probe(struct phy_device *phydev)
 
 static int rtl8214c_phy_probe(struct phy_device *phydev)
 {
-       struct device *dev = &phydev->mdio.dev;
-       int addr = phydev->mdio.addr;
-
-       /* All base addresses of the PHYs start at multiples of 8 */
-       devm_phy_package_join(dev, phydev, addr & (~7),
-                               sizeof(struct rtl83xx_shared_private));
+       int base_addr = phydev->mdio.addr & ~3;
 
-       if (!(addr % 8)) {
-               struct rtl83xx_shared_private *shared = phydev->shared->priv;
-               shared->name = "RTL8214C";
-               /* Configuration must be done whil patching still possible */
-               return rtl8380_configure_rtl8214c(phydev);
-       }
+       devm_phy_package_join(&phydev->mdio.dev, phydev, base_addr, 0);
+       if (phydev->mdio.addr == base_addr + 3)
+               return rtl8380_configure_rtl8214c(get_base_phy(phydev));
 
        return 0;
 }
 
 static int rtl8218b_ext_phy_probe(struct phy_device *phydev)
 {
-       struct device *dev = &phydev->mdio.dev;
-       int addr = phydev->mdio.addr;
+       int base_addr = phydev->mdio.addr & ~7;
 
-       /* All base addresses of the PHYs start at multiples of 8 */
-       devm_phy_package_join(dev, phydev, addr & (~7),
-                               sizeof(struct rtl83xx_shared_private));
-
-       if (!(addr % 8)) {
-               struct rtl83xx_shared_private *shared = phydev->shared->priv;
-               shared->name = "RTL8218B (external)";
-               if (soc_info.family == RTL8380_FAMILY_ID) {
-                       /* Configuration must be done while patching still possible */
-                       return rtl8380_configure_ext_rtl8218b(phydev);
-               }
+       devm_phy_package_join(&phydev->mdio.dev, phydev, base_addr, 0);
+       if (phydev->mdio.addr == base_addr + 7) {
+               if (soc_info.family == RTL8380_FAMILY_ID)
+                       return rtl8380_configure_ext_rtl8218b(get_base_phy(phydev));
        }
 
        return 0;
@@ -3639,46 +3621,25 @@ static int rtl8218b_ext_phy_probe(struct phy_device *phydev)
 
 static int rtl8218b_int_phy_probe(struct phy_device *phydev)
 {
-       struct device *dev = &phydev->mdio.dev;
-       int addr = phydev->mdio.addr;
+       int base_addr = phydev->mdio.addr & ~7;
 
        if (soc_info.family != RTL8380_FAMILY_ID)
                return -ENODEV;
-       if (addr >= 24)
+       if (base_addr >= 24)
                return -ENODEV;
 
-       pr_debug("%s: id: %d\n", __func__, addr);
-       /* All base addresses of the PHYs start at multiples of 8 */
-       devm_phy_package_join(dev, phydev, addr & (~7),
-                             sizeof(struct rtl83xx_shared_private));
-
-       if (!(addr % 8)) {
-               struct rtl83xx_shared_private *shared = phydev->shared->priv;
-               shared->name = "RTL8218B (internal)";
-               /* Configuration must be done while patching still possible */
-               return rtl8380_configure_int_rtl8218b(phydev);
-       }
+       devm_phy_package_join(&phydev->mdio.dev, phydev, base_addr, 0);
+       if (phydev->mdio.addr == base_addr + 7)
+               return rtl8380_configure_int_rtl8218b(get_base_phy(phydev));
 
        return 0;
 }
 
 static int rtl8218d_phy_probe(struct phy_device *phydev)
 {
-       struct device *dev = &phydev->mdio.dev;
-       int addr = phydev->mdio.addr;
+       int base_addr = phydev->mdio.addr & ~7;
 
-       pr_debug("%s: id: %d\n", __func__, addr);
-       /* All base addresses of the PHYs start at multiples of 8 */
-       devm_phy_package_join(dev, phydev, addr & (~7),
-                             sizeof(struct rtl83xx_shared_private));
-
-       /* All base addresses of the PHYs start at multiples of 8 */
-       if (!(addr % 8)) {
-               struct rtl83xx_shared_private *shared = phydev->shared->priv;
-               shared->name = "RTL8218D";
-               /* Configuration must be done while patching still possible */
-/* TODO:               return configure_rtl8218d(phydev); */
-       }
+       devm_phy_package_join(&phydev->mdio.dev, phydev, base_addr, 0);
 
        return 0;
 }
index 652e27a5c59d45f750305ff1de38cc4c06297a47..2f55fb0d90569d9fc19f0b2b5b6a7115b8bc84d4 100644 (file)
@@ -1,9 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
-struct rtl83xx_shared_private {
-       char *name;
-};
-
 struct __attribute__ ((__packed__)) part {
        uint16_t start;
        uint8_t wordsize;