realtek: switch to use generic MDIO accessor functions
authorDaniel Golle <daniel@makrotopia.org>
Fri, 4 Feb 2022 12:28:37 +0000 (12:28 +0000)
committerDaniel Golle <daniel@makrotopia.org>
Thu, 17 Feb 2022 15:21:47 +0000 (15:21 +0000)
Instead of directly calling SoC-specific functions in order to access
(paged) MII registers or MMD registers, create infrastructure to allow
using the generic phy_*, phy_*_paged and phy_*_mmd functions.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c
target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c
target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.h
target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.c
target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.h
target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch [new file with mode: 0644]

index 9675ba88f12336a2cce5e87fb1ecc171d5223921..75243bab0778efbcb246da2cb7727137ecbcfe48 100644 (file)
@@ -292,11 +292,14 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
         */
        bus->read = priv->mii_bus->read;
        bus->write = priv->mii_bus->write;
+       bus->read_paged = priv->mii_bus->read_paged;
+       bus->write_paged = priv->mii_bus->write_paged;
        snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", bus->name, dev->id);
 
        bus->parent = dev;
        priv->ds->slave_mii_bus = bus;
-       priv->ds->slave_mii_bus->priv = priv;
+       priv->ds->slave_mii_bus->priv = priv->mii_bus->priv;
+       priv->ds->slave_mii_bus->access_capabilities = priv->mii_bus->access_capabilities;
 
        ret = mdiobus_register(priv->ds->slave_mii_bus);
        if (ret && mii_np) {
index eb566766cae9626ed53906b87ba98fdd6a7d0e4a..23d22f16e2410a2a35725827c3b7e6eb1cbcbc5f 100644 (file)
@@ -1623,7 +1623,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
        return phylink_ethtool_ksettings_set(priv->phylink, cmd);
 }
 
-static int rtl838x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+static int rtl838x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, int regnum)
 {
        u32 val;
        int err;
@@ -1631,13 +1631,29 @@ static int rtl838x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 
        if (mii_id >= 24 && mii_id <= 27 && priv->id == 0x8380)
                return rtl838x_read_sds_phy(mii_id, regnum);
-       err = rtl838x_read_phy(mii_id, 0, regnum, &val);
+
+       if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
+               err = rtl838x_read_mmd_phy(mii_id,
+                                          mdiobus_c45_devad(regnum),
+                                          regnum, &val);
+               pr_debug("MMD: %d dev %x register %x read %x, err %d\n", mii_id,
+                        mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
+                        val, err);
+       } else {
+               pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
+               err = rtl838x_read_phy(mii_id, page, regnum, &val);
+       }
        if (err)
                return err;
        return val;
 }
 
-static int rtl839x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+static int rtl838x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       return rtl838x_mdio_read_paged(bus, mii_id, 0, regnum);
+}
+
+static int rtl839x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, int regnum)
 {
        u32 val;
        int err;
@@ -1646,22 +1662,37 @@ static int rtl839x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393)
                return rtl839x_read_sds_phy(mii_id, regnum);
 
-       err = rtl839x_read_phy(mii_id, 0, regnum, &val);
-       if (err)
+       if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
+               err = rtl839x_read_mmd_phy(mii_id,
+                                          mdiobus_c45_devad(regnum),
+                                          regnum, &val);
+               pr_debug("MMD: %d dev %x register %x read %x, err %d\n", mii_id,
+                        mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
+                        val, err);
+       } else {
+               err = rtl839x_read_phy(mii_id, page, regnum, &val);
+               pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
+       }
+               if (err)
                return err;
        return val;
 }
 
-static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+static int rtl839x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       return rtl839x_mdio_read_paged(bus, mii_id, 0, regnum);
+}
+
+static int rtl930x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, int regnum)
 {
        u32 val;
        int err;
        struct rtl838x_eth_priv *priv = bus->priv;
 
        if (priv->phy_is_internal[mii_id])
-               return rtl930x_read_sds_phy(priv->sds_id[mii_id], 0, regnum);
+               return rtl930x_read_sds_phy(priv->sds_id[mii_id], page, regnum);
 
-       if (regnum & MII_ADDR_C45) {
+       if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
                err = rtl930x_read_mmd_phy(mii_id,
                                           mdiobus_c45_devad(regnum),
                                           regnum, &val);
@@ -1669,7 +1700,7 @@ static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
                         mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
                         val, err);
        } else {
-               err = rtl930x_read_phy(mii_id, 0, regnum, &val);
+               err = rtl930x_read_phy(mii_id, page, regnum, &val);
                pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
        }
        if (err)
@@ -1677,16 +1708,20 @@ static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        return val;
 }
 
+static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       return rtl930x_mdio_read_paged(bus, mii_id, 0, regnum);
+}
 
-static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+static int rtl931x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, int regnum)
 {
        u32 val;
        int err, v;
        struct rtl838x_eth_priv *priv = bus->priv;
 
        pr_debug("%s: In here, port %d\n", __func__, mii_id);
-       if (priv->sds_id[mii_id] >= 0 && mii_id >= 52) {
-               v = rtl931x_read_sds_phy(priv->sds_id[mii_id], 0, regnum);
+       if (priv->phy_is_internal[mii_id]) {
+               v = rtl931x_read_sds_phy(priv->sds_id[mii_id], page, regnum);
                if (v < 0) {
                        err = v;
                } else {
@@ -1694,7 +1729,7 @@ static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
                        val = v;
                }
        } else {
-               if (regnum & MII_ADDR_C45) {
+               if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
                        err = rtl931x_read_mmd_phy(mii_id,
                                                   mdiobus_c45_devad(regnum),
                                                   regnum, &val);
@@ -1702,7 +1737,7 @@ static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
                                 mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
                                 val, err);
                } else {
-                       err = rtl931x_read_phy(mii_id, 0, regnum, &val);
+                       err = rtl931x_read_phy(mii_id, page, regnum, &val);
                        pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
                }
        }
@@ -1712,8 +1747,13 @@ static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        return val;
 }
 
-static int rtl838x_mdio_write(struct mii_bus *bus, int mii_id,
-                             int regnum, u16 value)
+static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       return rtl931x_mdio_read_paged(bus, mii_id, 0, regnum);
+}
+
+static int rtl838x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
+                                   int regnum, u16 value)
 {
        u32 offset = 0;
        struct rtl838x_eth_priv *priv = bus->priv;
@@ -1725,13 +1765,29 @@ static int rtl838x_mdio_write(struct mii_bus *bus, int mii_id,
                sw_w32(value, RTL838X_SDS4_FIB_REG0 + offset + (regnum << 2));
                return 0;
        }
-       err = rtl838x_write_phy(mii_id, 0, regnum, value);
+
+       if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
+               err = rtl838x_write_mmd_phy(mii_id, mdiobus_c45_devad(regnum),
+                                           regnum, value);
+               pr_debug("MMD: %d dev %x register %x write %x, err %d\n", mii_id,
+                        mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
+                        value, err);
+
+               return err;
+       }
+       err = rtl838x_write_phy(mii_id, page, regnum, value);
        pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
        return err;
 }
 
-static int rtl839x_mdio_write(struct mii_bus *bus, int mii_id,
+static int rtl838x_mdio_write(struct mii_bus *bus, int mii_id,
                              int regnum, u16 value)
+{
+       return rtl838x_mdio_write_paged(bus, mii_id, 0, regnum, value);
+}
+
+static int rtl839x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
+                                   int regnum, u16 value)
 {
        struct rtl838x_eth_priv *priv = bus->priv;
        int err;
@@ -1739,39 +1795,61 @@ static int rtl839x_mdio_write(struct mii_bus *bus, int mii_id,
        if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393)
                return rtl839x_write_sds_phy(mii_id, regnum, value);
 
-       err = rtl839x_write_phy(mii_id, 0, regnum, value);
+       if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
+               err = rtl839x_write_mmd_phy(mii_id, mdiobus_c45_devad(regnum),
+                                           regnum, value);
+               pr_debug("MMD: %d dev %x register %x write %x, err %d\n", mii_id,
+                        mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
+                        value, err);
+
+               return err;
+       }
+
+       err = rtl839x_write_phy(mii_id, page, regnum, value);
        pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
        return err;
 }
 
-static int rtl930x_mdio_write(struct mii_bus *bus, int mii_id,
+static int rtl839x_mdio_write(struct mii_bus *bus, int mii_id,
                              int regnum, u16 value)
+{
+       return rtl839x_mdio_write_paged(bus, mii_id, 0, regnum, value);
+}
+
+static int rtl930x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
+                                   int regnum, u16 value)
 {
        struct rtl838x_eth_priv *priv = bus->priv;
        int err;
 
-       if (priv->sds_id[mii_id] >= 0)
-               return rtl930x_write_sds_phy(priv->sds_id[mii_id], 0, regnum, value);
+       if (priv->phy_is_internal[mii_id])
+               return rtl930x_write_sds_phy(priv->sds_id[mii_id], page, regnum, value);
 
-       if (regnum & MII_ADDR_C45)
+       if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD))
                return rtl930x_write_mmd_phy(mii_id, mdiobus_c45_devad(regnum),
                                             regnum, value);
 
-       err = rtl930x_write_phy(mii_id, 0, regnum, value);
+       err = rtl930x_write_phy(mii_id, page, regnum, value);
        pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
        return err;
 }
 
-static int rtl931x_mdio_write(struct mii_bus *bus, int mii_id,
+static int rtl930x_mdio_write(struct mii_bus *bus, int mii_id,
                              int regnum, u16 value)
+{
+       return rtl930x_mdio_write_paged(bus, mii_id, 0, regnum, value);
+}
+
+static int rtl931x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
+                                   int regnum, u16 value)
 {
        struct rtl838x_eth_priv *priv = bus->priv;
        int err;
 
-       if (priv->sds_id[mii_id] >= 0 && mii_id >= 52)
-               return rtl931x_write_sds_phy(priv->sds_id[mii_id], 0, regnum, value);
+       if (priv->phy_is_internal[mii_id])
+               return rtl931x_write_sds_phy(priv->sds_id[mii_id], page, regnum, value);
 
-       if (regnum & MII_ADDR_C45) {
+       if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
                err = rtl931x_write_mmd_phy(mii_id, mdiobus_c45_devad(regnum),
                                            regnum, value);
                pr_debug("MMD: %d dev %x register %x write %x, err %d\n", mii_id,
@@ -1781,11 +1859,17 @@ static int rtl931x_mdio_write(struct mii_bus *bus, int mii_id,
                return err;
        }
 
-       err = rtl931x_write_phy(mii_id, 0, regnum, value);
+       err = rtl931x_write_phy(mii_id, page, regnum, value);
        pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
        return err;
 }
 
+static int rtl931x_mdio_write(struct mii_bus *bus, int mii_id,
+                             int regnum, u16 value)
+{
+       return rtl931x_mdio_write_paged(bus, mii_id, 0, regnum, value);
+}
+
 static int rtl838x_mdio_reset(struct mii_bus *bus)
 {
        pr_debug("%s called\n", __func__);
@@ -2047,30 +2131,39 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
        case RTL8380_FAMILY_ID:
                priv->mii_bus->name = "rtl838x-eth-mdio";
                priv->mii_bus->read = rtl838x_mdio_read;
+               priv->mii_bus->read_paged = rtl838x_mdio_read_paged;
                priv->mii_bus->write = rtl838x_mdio_write;
+               priv->mii_bus->write_paged = rtl838x_mdio_write_paged;
                priv->mii_bus->reset = rtl838x_mdio_reset;
                break;
        case RTL8390_FAMILY_ID:
                priv->mii_bus->name = "rtl839x-eth-mdio";
                priv->mii_bus->read = rtl839x_mdio_read;
+               priv->mii_bus->read_paged = rtl839x_mdio_read_paged;
                priv->mii_bus->write = rtl839x_mdio_write;
+               priv->mii_bus->write_paged = rtl839x_mdio_write_paged;
                priv->mii_bus->reset = rtl839x_mdio_reset;
                break;
        case RTL9300_FAMILY_ID:
                priv->mii_bus->name = "rtl930x-eth-mdio";
                priv->mii_bus->read = rtl930x_mdio_read;
+               priv->mii_bus->read_paged = rtl930x_mdio_read_paged;
                priv->mii_bus->write = rtl930x_mdio_write;
+               priv->mii_bus->write_paged = rtl930x_mdio_write_paged;
                priv->mii_bus->reset = rtl930x_mdio_reset;
                priv->mii_bus->probe_capabilities = MDIOBUS_C22_C45;
                break;
        case RTL9310_FAMILY_ID:
                priv->mii_bus->name = "rtl931x-eth-mdio";
                priv->mii_bus->read = rtl931x_mdio_read;
+               priv->mii_bus->read_paged = rtl931x_mdio_read_paged;
                priv->mii_bus->write = rtl931x_mdio_write;
+               priv->mii_bus->write_paged = rtl931x_mdio_write_paged;
                priv->mii_bus->reset = rtl931x_mdio_reset;
                priv->mii_bus->probe_capabilities = MDIOBUS_C22_C45;
                break;
        }
+       priv->mii_bus->access_capabilities = MDIOBUS_ACCESS_C22_MMD;
        priv->mii_bus->priv = priv;
        priv->mii_bus->parent = &priv->pdev->dev;
 
index 6013de6c73e7743810030efe19b37415398d4ba7..2d1f80dc9d2c792fcf9ec34fc36b2838400380bb 100644 (file)
@@ -442,8 +442,12 @@ struct rtl838x_eth_reg {
 
 int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val);
 int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
+int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val);
+int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val);
 int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val);
 int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
+int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
+int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
 int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val);
 int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
 int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val);
index c1d6af63751f139e2f92547e36ddaa0866efd001..9b674e51ab8ded39bbd7099d785160bc0ee37a56 100644 (file)
@@ -38,74 +38,6 @@ static const struct firmware rtl838x_8380_fw;
 static const struct firmware rtl838x_8214fc_fw;
 static const struct firmware rtl838x_8218b_fw;
 
-int rtl838x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
-int rtl838x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val);
-int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
-int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val);
-int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
-int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val);
-int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
-int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val);
-
-static int read_phy(u32 port, u32 page, u32 reg, u32 *val)
-{      switch (soc_info.family) {
-       case RTL8380_FAMILY_ID:
-               return rtl838x_read_phy(port, page, reg, val);
-       case RTL8390_FAMILY_ID:
-               return rtl839x_read_phy(port, page, reg, val);
-       case RTL9300_FAMILY_ID:
-               return rtl930x_read_phy(port, page, reg, val);
-       case RTL9310_FAMILY_ID:
-               return rtl931x_read_phy(port, page, reg, val);
-       }
-       return -1;
-}
-
-static int write_phy(u32 port, u32 page, u32 reg, u32 val)
-{
-       switch (soc_info.family) {
-       case RTL8380_FAMILY_ID:
-               return rtl838x_write_phy(port, page, reg, val);
-       case RTL8390_FAMILY_ID:
-               return rtl839x_write_phy(port, page, reg, val);
-       case RTL9300_FAMILY_ID:
-               return rtl930x_write_phy(port, page, reg, val);
-       case RTL9310_FAMILY_ID:
-               return rtl931x_write_phy(port, page, reg, val);
-       }
-       return -1;
-}
-
-static int read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val)
-{
-       switch (soc_info.family) {
-       case RTL8380_FAMILY_ID:
-               return rtl838x_read_mmd_phy(port, devnum, regnum, val);
-       case RTL8390_FAMILY_ID:
-               return rtl839x_read_mmd_phy(port, devnum, regnum, val);
-       case RTL9300_FAMILY_ID:
-               return rtl930x_read_mmd_phy(port, devnum, regnum, val);
-       case RTL9310_FAMILY_ID:
-               return rtl931x_read_mmd_phy(port, devnum, regnum, val);
-       }
-       return -1;
-}
-
-int write_mmd_phy(u32 port, u32 devnum, u32 reg, u32 val)
-{
-       switch (soc_info.family) {
-       case RTL8380_FAMILY_ID:
-               return rtl838x_write_mmd_phy(port, devnum, reg, val);
-       case RTL8390_FAMILY_ID:
-               return rtl839x_write_mmd_phy(port, devnum, reg, val);
-       case RTL9300_FAMILY_ID:
-               return rtl930x_write_mmd_phy(port, devnum, reg, val);
-       case RTL9310_FAMILY_ID:
-               return rtl931x_write_mmd_phy(port, devnum, reg, val);
-       }
-       return -1;
-}
-
 static u64 disable_polling(int port)
 {
        u64 saved_state;
@@ -163,44 +95,25 @@ static int resume_polling(u64 saved_state)
        return 0;
 }
 
-static void rtl8380_int_phy_on_off(int mac, bool on)
+static void rtl8380_int_phy_on_off(struct phy_device *phydev, bool on)
 {
-       u32 val;
-
-       read_phy(mac, 0, 0, &val);
-       if (on)
-               write_phy(mac, 0, 0, val & ~BIT(11));
-       else
-               write_phy(mac, 0, 0, val | BIT(11));
+       phy_modify(phydev, 0, BIT(11), on?0:BIT(11));
 }
 
-static void rtl8380_rtl8214fc_on_off(int mac, bool on)
+static void rtl8380_rtl8214fc_on_off(struct phy_device *phydev, bool on)
 {
-       u32 val;
-
        /* fiber ports */
-       write_phy(mac, 4095, 30, 3);
-       read_phy(mac, 0, 16, &val);
-       if (on)
-               write_phy(mac, 0, 16, val & ~BIT(11));
-       else
-               write_phy(mac, 0, 16, val | BIT(11));
+       phy_write_paged(phydev, 4095, 30, 3);
+       phy_modify(phydev, 16, BIT(11), on?0:BIT(11));
 
        /* copper ports */
-       write_phy(mac, 4095, 30, 1);
-       read_phy(mac, 0, 16, &val);
-       if (on)
-               write_phy(mac, 0xa40, 16, val & ~BIT(11));
-       else
-               write_phy(mac, 0xa40, 16, val | BIT(11));
+       phy_write_paged(phydev, 4095, 30, 1);
+       phy_modify_paged(phydev, 0xa40, 16, BIT(11), on?0:BIT(11));
 }
 
-static void rtl8380_phy_reset(int mac)
+static void rtl8380_phy_reset(struct phy_device *phydev)
 {
-       u32 val;
-
-       read_phy(mac, 0, 0, &val);
-       write_phy(mac, 0, 0, val | BIT(15));
+       phy_modify(phydev, 0, BIT(15), BIT(15));
 }
 
 // The access registers for SDS_MODE_SEL and the LSB for each SDS within
@@ -499,7 +412,6 @@ static int rtl8226_read_status(struct phy_device *phydev)
 {
        int ret = 0, i;
        u32 val;
-       int port = phydev->mdio.addr;
 
 // TODO: ret = genphy_read_status(phydev);
 //     if (ret < 0) {
@@ -509,20 +421,20 @@ static int rtl8226_read_status(struct phy_device *phydev)
 
        // Link status must be read twice
        for (i = 0; i < 2; i++) {
-               read_mmd_phy(port, MMD_VEND2, 0xA402, &val);
+               val = phy_read_mmd(phydev, MMD_VEND2, 0xA402);
        }
        phydev->link = val & BIT(2) ? 1 : 0;
        if (!phydev->link)
                goto out;
 
        // Read duplex status
-       ret = read_mmd_phy(port, MMD_VEND2, 0xA434, &val);
-       if (ret)
+       val = phy_read_mmd(phydev, MMD_VEND2, 0xA434);
+       if (val < 0)
                goto out;
        phydev->duplex = !!(val & BIT(3));
 
        // Read speed
-       ret = read_mmd_phy(port, MMD_VEND2, 0xA434, &val);
+       val = phy_read_mmd(phydev, MMD_VEND2, 0xA434);
        switch (val & 0x0630) {
        case 0x0000:
                phydev->speed = SPEED_10;
@@ -553,12 +465,11 @@ static int rtl8226_advertise_aneg(struct phy_device *phydev)
 {
        int ret = 0;
        u32 v;
-       int port = phydev->mdio.addr;
 
        pr_info("In %s\n", __func__);
 
-       ret = read_mmd_phy(port, MMD_AN, 16, &v);
-       if (ret)
+       v = phy_read_mmd(phydev, MMD_AN, 16);
+       if (v < 0)
                goto out;
 
        v |= BIT(5); // HD 10M
@@ -566,25 +477,25 @@ static int rtl8226_advertise_aneg(struct phy_device *phydev)
        v |= BIT(7); // HD 100M
        v |= BIT(8); // FD 100M
 
-       ret = write_mmd_phy(port, MMD_AN, 16, v);
+       ret = phy_write_mmd(phydev, MMD_AN, 16, v);
 
        // Allow 1GBit
-       ret = read_mmd_phy(port, MMD_VEND2, 0xA412, &v);
-       if (ret)
+       v = phy_read_mmd(phydev, MMD_VEND2, 0xA412);
+       if (v < 0)
                goto out;
        v |= BIT(9); // FD 1000M
 
-       ret = write_mmd_phy(port, MMD_VEND2, 0xA412, v);
-       if (ret)
+       ret = phy_write_mmd(phydev, MMD_VEND2, 0xA412, v);
+       if (ret < 0)
                goto out;
 
        // Allow 2.5G
-       ret = read_mmd_phy(port, MMD_AN, 32, &v);
-       if (ret)
+       v = phy_read_mmd(phydev, MMD_AN, 32);
+       if (v < 0)
                goto out;
 
        v |= BIT(7);
-       ret = write_mmd_phy(port, MMD_AN, 32, v);
+       ret = phy_write_mmd(phydev, MMD_AN, 32, v);
 
 out:
        return ret;
@@ -594,7 +505,6 @@ static int rtl8226_config_aneg(struct phy_device *phydev)
 {
        int ret = 0;
        u32 v;
-       int port = phydev->mdio.addr;
 
        pr_debug("In %s\n", __func__);
        if (phydev->autoneg == AUTONEG_ENABLE) {
@@ -602,22 +512,22 @@ static int rtl8226_config_aneg(struct phy_device *phydev)
                if (ret)
                        goto out;
                // AutoNegotiationEnable
-               ret = read_mmd_phy(port, MMD_AN, 0, &v);
-               if (ret)
+               v = phy_read_mmd(phydev, MMD_AN, 0);
+               if (v < 0)
                        goto out;
 
                v |= BIT(12); // Enable AN
-               ret = write_mmd_phy(port, MMD_AN, 0, v);
-               if (ret)
+               ret = phy_write_mmd(phydev, MMD_AN, 0, v);
+               if (ret < 0)
                        goto out;
 
                // RestartAutoNegotiation
-               ret = read_mmd_phy(port, MMD_VEND2, 0xA400, &v);
-               if (ret)
+               v = phy_read_mmd(phydev, MMD_VEND2, 0xA400);
+               if (v < 0)
                        goto out;
                v |= BIT(9);
 
-               ret = write_mmd_phy(port, MMD_VEND2, 0xA400, v);
+               ret = phy_write_mmd(phydev, MMD_VEND2, 0xA400, v);
        }
 
 //     TODO: ret = __genphy_config_aneg(phydev, ret);
@@ -634,11 +544,11 @@ static int rtl8226_get_eee(struct phy_device *phydev,
 
        pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
 
-       read_mmd_phy(addr, MMD_AN, 60, &val);
+       val = phy_read_mmd(phydev, MMD_AN, 60);
        if (e->eee_enabled) {
                e->eee_enabled = !!(val & BIT(1));
                if (!e->eee_enabled) {
-                       read_mmd_phy(addr, MMD_AN, 62, &val);
+                       val = phy_read_mmd(phydev, MMD_AN, 62);
                        e->eee_enabled = !!(val & BIT(0));
                }
        }
@@ -659,29 +569,29 @@ static int rtl8226_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
        poll_state = disable_polling(port);
 
        // Remember aneg state
-       read_mmd_phy(port, MMD_AN, 0, &val);
+       val = phy_read_mmd(phydev, MMD_AN, 0);
        an_enabled = !!(val & BIT(12));
 
        // Setup 100/1000MBit
-       read_mmd_phy(port, MMD_AN, 60, &val);
+       val = phy_read_mmd(phydev, MMD_AN, 60);
        if (e->eee_enabled)
                val |= 0x6;
        else
                val &= 0x6;
-       write_mmd_phy(port, MMD_AN, 60, val);
+       phy_write_mmd(phydev, MMD_AN, 60, val);
 
        // Setup 2.5GBit
-       read_mmd_phy(port, MMD_AN, 62, &val);
+       val = phy_read_mmd(phydev, MMD_AN, 62);
        if (e->eee_enabled)
                val |= 0x1;
        else
                val &= 0x1;
-       write_mmd_phy(port, MMD_AN, 62, val);
+       phy_write_mmd(phydev, MMD_AN, 62, val);
 
        // RestartAutoNegotiation
-       read_mmd_phy(port, MMD_VEND2, 0xA400, &val);
+       val = phy_read_mmd(phydev, MMD_VEND2, 0xA400);
        val |= BIT(9);
-       write_mmd_phy(port, MMD_VEND2, 0xA400, val);
+       phy_write_mmd(phydev, MMD_VEND2, 0xA400, val);
 
        resume_polling(poll_state);
 
@@ -733,18 +643,18 @@ out:
 
 static int rtl8390_configure_generic(struct phy_device *phydev)
 {
-       u32 val, phy_id;
        int mac = phydev->mdio.addr;
+       u32 val, phy_id;
 
-       read_phy(mac, 0, 2, &val);
+       val = phy_read(phydev, 2);
        phy_id = val << 16;
-       read_phy(mac, 0, 3, &val);
+       val = phy_read(phydev, 3);
        phy_id |= val;
        pr_debug("Phy on MAC %d: %x\n", mac, phy_id);
 
        /* Read internal PHY ID */
-       write_phy(mac, 31, 27, 0x0002);
-       read_phy(mac, 31, 28, &val);
+       phy_write_paged(phydev, 31, 27, 0x0002);
+       val = phy_read_paged(phydev, 31, 28);
 
        /* Internal RTL8218B, version 2 */
        phydev_info(phydev, "Detected unknown %x\n", val);
@@ -760,16 +670,15 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev)
        u32 *rtl838x_6275B_intPhy_perport;
        u32 *rtl8218b_6276B_hwEsd_perport;
 
-
-       read_phy(mac, 0, 2, &val);
+       val = phy_read(phydev, 2);
        phy_id = val << 16;
-       read_phy(mac, 0, 3, &val);
+       val = phy_read(phydev, 3);
        phy_id |= val;
        pr_debug("Phy on MAC %d: %x\n", mac, phy_id);
 
        /* Read internal PHY ID */
-       write_phy(mac, 31, 27, 0x0002);
-       read_phy(mac, 31, 28, &val);
+       phy_write_paged(phydev, 31, 27, 0x0002);
+       val = phy_read_paged(phydev, 31, 28);
        if (val != 0x6275) {
                phydev_err(phydev, "Expected internal RTL8218B, found PHY-ID %x\n", val);
                return -1;
@@ -796,22 +705,22 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev)
        if (sw_r32(RTL838X_DMY_REG31) == 0x1)
                ipd_flag = 1;
 
-       read_phy(mac, 0, 0, &val);
-       if (val & (1 << 11))
-               rtl8380_int_phy_on_off(mac, true);
+       val = phy_read(phydev, 0);
+       if (val & BIT(11))
+               rtl8380_int_phy_on_off(phydev, true);
        else
-               rtl8380_phy_reset(mac);
+               rtl8380_phy_reset(phydev);
        msleep(100);
 
        /* Ready PHY for patch */
        for (p = 0; p < 8; p++) {
-               write_phy(mac + p, 0xfff, 0x1f, 0x0b82);
-               write_phy(mac + p, 0xfff, 0x10, 0x0010);
+               phy_package_port_write_paged(phydev, p, 0xfff, 0x1f, 0x0b82);
+               phy_package_port_write_paged(phydev, p, 0xfff, 0x10, 0x0010);
        }
        msleep(500);
        for (p = 0; p < 8; p++) {
                for (i = 0; i < 100 ; i++) {
-                       read_phy(mac + p, 0x0b80, 0x10, &val);
+                       val = phy_package_port_read_paged(phydev, p, 0x0b80, 0x10);
                        if (val & 0x40)
                                break;
                }
@@ -825,14 +734,14 @@ static int rtl8380_configure_int_rtl8218b(struct phy_device *phydev)
        for (p = 0; p < 8; p++) {
                i = 0;
                while (rtl838x_6275B_intPhy_perport[i * 2]) {
-                       write_phy(mac + p, 0xfff,
+                       phy_package_port_write_paged(phydev, p, 0xfff,
                                rtl838x_6275B_intPhy_perport[i * 2],
                                rtl838x_6275B_intPhy_perport[i * 2 + 1]);
                        i++;
                }
                i = 0;
                while (rtl8218b_6276B_hwEsd_perport[i * 2]) {
-                       write_phy(mac + p, 0xfff,
+                       phy_package_port_write_paged(phydev, p, 0xfff,
                                rtl8218b_6276B_hwEsd_perport[i * 2],
                                rtl8218b_6276B_hwEsd_perport[i * 2 + 1]);
                        i++;
@@ -855,15 +764,15 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
                phydev_err(phydev, "External RTL8218B must have PHY-IDs 0 or 16!\n");
                return -1;
        }
-       read_phy(mac, 0, 2, &val);
+       val = phy_read(phydev, 2);
        phy_id = val << 16;
-       read_phy(mac, 0, 3, &val);
+       val = phy_read(phydev, 3);
        phy_id |= val;
        pr_info("Phy on MAC %d: %x\n", mac, phy_id);
 
        /* Read internal PHY ID */
-       write_phy(mac, 31, 27, 0x0002);
-       read_phy(mac, 31, 28, &val);
+       phy_write_paged(phydev, 31, 27, 0x0002);
+       val = phy_read_paged(phydev, 31, 28);
        if (val != 0x6276) {
                phydev_err(phydev, "Expected external RTL8218B, found PHY-ID %x\n", val);
                return -1;
@@ -888,22 +797,25 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
        rtl8380_rtl8218b_perport = (void *)h + sizeof(struct fw_header)
                        + h->parts[2].start;
 
-       read_phy(mac, 0, 0, &val);
+       val = phy_read(phydev, 0);
        if (val & (1 << 11))
-               rtl8380_int_phy_on_off(mac, true);
+               rtl8380_int_phy_on_off(phydev, true);
        else
-               rtl8380_phy_reset(mac);
+               rtl8380_phy_reset(phydev);
+
        msleep(100);
 
        /* Get Chip revision */
-       write_phy(mac, 0xfff, 0x1f, 0x0);
-       write_phy(mac,  0xfff, 0x1b, 0x4);
-       read_phy(mac, 0xfff, 0x1c, &val);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0);
+       phy_write_paged(phydev, 0xfff, 0x1b, 0x4);
+       val = phy_read_paged(phydev, 0xfff, 0x1c);
+
+       phydev_info(phydev, "Detected chip revision %04x\n", val);
 
        i = 0;
        while (rtl8380_rtl8218b_perchip[i * 3]
                && rtl8380_rtl8218b_perchip[i * 3 + 1]) {
-               write_phy(mac + rtl8380_rtl8218b_perchip[i * 3],
+                       phy_package_port_write_paged(phydev, rtl8380_rtl8218b_perchip[i * 3],
                                          0xfff, rtl8380_rtl8218b_perchip[i * 3 + 1],
                                          rtl8380_rtl8218b_perchip[i * 3 + 2]);
                i++;
@@ -911,22 +823,23 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
 
        /* Enable PHY */
        for (i = 0; i < 8; i++) {
-               write_phy(mac + i, 0xfff, 0x1f, 0x0000);
-               write_phy(mac + i, 0xfff, 0x00, 0x1140);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0000);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x00, 0x1140);
        }
        mdelay(100);
 
        /* Request patch */
        for (i = 0; i < 8; i++) {
-               write_phy(mac + i,  0xfff, 0x1f, 0x0b82);
-               write_phy(mac + i,  0xfff, 0x10, 0x0010);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0b82);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x10, 0x0010);
        }
+
        mdelay(300);
 
        /* Verify patch readiness */
        for (i = 0; i < 8; i++) {
                for (l = 0; l < 100; l++) {
-                       read_phy(mac + i, 0xb80, 0x10, &val);
+                       val = phy_package_port_read_paged(phydev, i, 0xb80, 0x10);
                        if (val & 0x40)
                                break;
                }
@@ -937,36 +850,36 @@ static int rtl8380_configure_ext_rtl8218b(struct phy_device *phydev)
        }
 
        /* Use Broadcast ID method for patching */
-       write_phy(mac, 0xfff, 0x1f, 0x0000);
-       write_phy(mac, 0xfff, 0x1d, 0x0008);
-       write_phy(mac, 0xfff, 0x1f, 0x0266);
-       write_phy(mac, 0xfff, 0x16, 0xff00 + mac);
-       write_phy(mac, 0xfff, 0x1f, 0x0000);
-       write_phy(mac, 0xfff, 0x1d, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1d, 0x0008);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0266);
+       phy_write_paged(phydev, 0xfff, 0x16, 0xff00 + mac);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1d, 0x0000);
        mdelay(1);
 
-       write_phy(mac, 0xfff, 30, 8);
-       write_phy(mac, 0x26e, 17, 0xb);
-       write_phy(mac, 0x26e, 16, 0x2);
+       phy_write_paged(phydev, 0xfff, 30, 8);
+       phy_write_paged(phydev, 0x26e, 17, 0xb);
+       phy_write_paged(phydev, 0x26e, 16, 0x2);
        mdelay(1);
-       read_phy(mac, 0x26e, 19, &ipd);
-       write_phy(mac, 0, 30, 0);
-       ipd = (ipd >> 4) & 0xf;
+       ipd = phy_read_paged(phydev, 0x26e, 19);
+       phy_write_paged(phydev, 0, 30, 0);
+       ipd = (ipd >> 4) & 0xf; /* unused ? */
 
        i = 0;
        while (rtl8218B_6276B_rtl8380_perport[i * 2]) {
-               write_phy(mac, 0xfff, rtl8218B_6276B_rtl8380_perport[i * 2],
+               phy_write_paged(phydev, 0xfff, rtl8218B_6276B_rtl8380_perport[i * 2],
                                  rtl8218B_6276B_rtl8380_perport[i * 2 + 1]);
                i++;
        }
 
        /*Disable broadcast ID*/
-       write_phy(mac, 0xfff, 0x1f, 0x0000);
-       write_phy(mac, 0xfff, 0x1d, 0x0008);
-       write_phy(mac, 0xfff, 0x1f, 0x0266);
-       write_phy(mac, 0xfff, 0x16, 0x00 + mac);
-       write_phy(mac, 0xfff, 0x1f, 0x0000);
-       write_phy(mac, 0xfff, 0x1d, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1d, 0x0008);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0266);
+       phy_write_paged(phydev, 0xfff, 0x16, 0x00 + mac);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1d, 0x0000);
        mdelay(1);
 
        return 0;
@@ -987,72 +900,33 @@ static int rtl8218b_ext_match_phy_device(struct phy_device *phydev)
                return phydev->phy_id == PHY_ID_RTL8218B_E;
 }
 
-static int rtl8218b_read_mmd(struct phy_device *phydev,
-                                    int devnum, u16 regnum)
-{
-       int ret;
-       u32 val;
-       int addr = phydev->mdio.addr;
-
-       ret = read_mmd_phy(addr, devnum, regnum, &val);
-       if (ret)
-               return ret;
-       return val;
-}
-
-static int rtl8218b_write_mmd(struct phy_device *phydev,
-                                     int devnum, u16 regnum, u16 val)
+static void rtl8380_rtl8214fc_media_set(struct phy_device *phydev, bool set_fibre)
 {
-       int addr = phydev->mdio.addr;
-
-       return rtl838x_write_mmd_phy(addr, devnum, regnum, val);
-}
-
-static int rtl8226_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
-{
-       int port = phydev->mdio.addr;  // the SoC translates port addresses to PHY addr
-       int err;
-       u32 val;
-
-       err = read_mmd_phy(port, devnum, regnum, &val);
-       if (err)
-               return err;
-       return val;
-}
-
-static int rtl8226_write_mmd(struct phy_device *phydev, int devnum, u16 regnum, u16 val)
-{
-       int port = phydev->mdio.addr; // the SoC translates port addresses to PHY addr
-
-       return write_mmd_phy(port, devnum, regnum, val);
-}
+       int mac = phydev->mdio.addr;
 
-static void rtl8380_rtl8214fc_media_set(int mac, bool set_fibre)
-{
-       int base = mac - (mac % 4);
        static int reg[] = {16, 19, 20, 21};
        int val, media, power;
 
        pr_info("%s: port %d, set_fibre: %d\n", __func__, mac, set_fibre);
-       write_phy(base, 0xfff, 29, 8);
-       read_phy(base, 0x266, reg[mac % 4], &val);
+       phy_package_write_paged(phydev, 0xfff, 29, 8);
+       val = phy_package_read_paged(phydev, 0x266, reg[mac % 4]);
 
        media = (val >> 10) & 0x3;
        pr_info("Current media %x\n", media);
        if (media & 0x2) {
                pr_info("Powering off COPPER\n");
-               write_phy(base, 0xfff, 29, 1);
+               phy_package_write_paged(phydev, 0xfff, 29, 1);
                /* Ensure power is off */
-               read_phy(base, 0xa40, 16, &power);
+               power = phy_package_read_paged(phydev, 0xa40, 16);
                if (!(power & (1 << 11)))
-                       write_phy(base, 0xa40, 16, power | (1 << 11));
+                       phy_package_write_paged(phydev, 0xa40, 16, power | (1 << 11));
        } else {
                pr_info("Powering off FIBRE");
-               write_phy(base, 0xfff, 29, 3);
+               phy_package_write_paged(phydev, 0xfff, 29, 3);
                /* Ensure power is off */
-               read_phy(base, 0xa40, 16, &power);
+               power = phy_package_read_paged(phydev, 0xa40, 16);
                if (!(power & (1 << 11)))
-                       write_phy(base, 0xa40, 16, power | (1 << 11));
+                       phy_package_write_paged(phydev, 0xa40, 16, power | (1 << 11));
        }
 
        if (set_fibre) {
@@ -1062,38 +936,39 @@ static void rtl8380_rtl8214fc_media_set(int mac, bool set_fibre)
                val |= 1 << 10;
                val |= 1 << 11;
        }
-       write_phy(base, 0xfff, 29, 8);
-       write_phy(base, 0x266, reg[mac % 4], val);
-       write_phy(base, 0xfff, 29, 0);
+       phy_package_write_paged(phydev, 0xfff, 29, 8);
+       phy_package_write_paged(phydev, 0x266, reg[mac % 4], val);
+       phy_package_write_paged(phydev, 0xfff, 29, 0);
 
        if (set_fibre) {
                pr_info("Powering on FIBRE");
-               write_phy(base, 0xfff, 29, 3);
+               phy_package_write_paged(phydev, 0xfff, 29, 3);
                /* Ensure power is off */
-               read_phy(base, 0xa40, 16, &power);
+               power = phy_package_read_paged(phydev, 0xa40, 16);
                if (power & (1 << 11))
-                       write_phy(base, 0xa40, 16, power & ~(1 << 11));
+                       phy_package_write_paged(phydev, 0xa40, 16, power & ~(1 << 11));
        } else {
                pr_info("Powering on COPPER\n");
-               write_phy(base, 0xfff, 29, 1);
+               phy_package_write_paged(phydev, 0xfff, 29, 1);
                /* Ensure power is off */
-               read_phy(base, 0xa40, 16, &power);
+               power = phy_package_read_paged(phydev, 0xa40, 16);
                if (power & (1 << 11))
-                       write_phy(base, 0xa40, 16, power & ~(1 << 11));
+                       phy_package_write_paged(phydev, 0xa40, 16, power & ~(1 << 11));
        }
 
-       write_phy(base, 0xfff, 29, 0);
+       phy_package_write_paged(phydev, 0xfff, 29, 0);
 }
 
-static bool rtl8380_rtl8214fc_media_is_fibre(int mac)
+static bool rtl8380_rtl8214fc_media_is_fibre(struct phy_device *phydev)
 {
-       int base = mac - (mac % 4);
+       int mac = phydev->mdio.addr;
+
        static int reg[] = {16, 19, 20, 21};
        u32 val;
 
-       write_phy(base, 0xfff, 29, 8);
-       read_phy(base, 0x266, reg[mac % 4], &val);
-       write_phy(base, 0xfff, 29, 0);
+       phy_package_write_paged(phydev, 0xfff, 29, 8);
+       val = phy_package_read_paged(phydev, 0x266, reg[mac % 4]);
+       phy_package_write_paged(phydev, 0xfff, 29, 0);
        if (val & (1 << 11))
                return false;
        return true;
@@ -1106,7 +981,7 @@ static int rtl8214fc_set_port(struct phy_device *phydev, int port)
 
        pr_debug("%s port %d to %d\n", __func__, addr, port);
 
-       rtl8380_rtl8214fc_media_set(addr, is_fibre);
+       rtl8380_rtl8214fc_media_set(phydev, is_fibre);
        return 0;
 }
 
@@ -1115,7 +990,7 @@ static int rtl8214fc_get_port(struct phy_device *phydev)
        int addr = phydev->mdio.addr;
 
        pr_debug("%s: port %d\n", __func__, addr);
-       if (rtl8380_rtl8214fc_media_is_fibre(addr))
+       if (rtl8380_rtl8214fc_media_is_fibre(phydev))
                return PORT_FIBRE;
        return PORT_MII;
 }
@@ -1126,40 +1001,40 @@ static int rtl8214fc_get_port(struct phy_device *phydev)
  * but the only way that works since the kernel first enables EEE in the MAC
  * and then sets up the PHY. The MAC-based approach would require the oppsite.
  */
-void rtl8218d_eee_set(int port, bool enable)
+void rtl8218d_eee_set(struct phy_device *phydev, bool enable)
 {
        u32 val;
        bool an_enabled;
 
-       pr_debug("In %s %d, enable %d\n", __func__, port, enable);
+       pr_debug("In %s %d, enable %d\n", __func__, phydev->mdio.addr, enable);
        /* Set GPHY page to copper */
-       write_phy(port, 0xa42, 30, 0x0001);
+       phy_write_paged(phydev, 0xa42, 30, 0x0001);
 
-       read_phy(port, 0, 0, &val);
+       val = phy_read(phydev, 0);
        an_enabled = val & BIT(12);
 
        /* Enable 100M (bit 1) / 1000M (bit 2) EEE */
-       read_mmd_phy(port, 7, 60, &val);
+       val = phy_read_mmd(phydev, 7, 60);
        val |= BIT(2) | BIT(1);
-       write_mmd_phy(port, 7, 60, enable ? 0x6 : 0);
+       phy_write_mmd(phydev, 7, 60, enable ? 0x6 : 0);
 
        /* 500M EEE ability */
-       read_phy(port, 0xa42, 20, &val);
+       val = phy_read_paged(phydev, 0xa42, 20);
        if (enable)
                val |= BIT(7);
        else
                val &= ~BIT(7);
-       write_phy(port, 0xa42, 20, val);
+       phy_write_paged(phydev, 0xa42, 20, val);
 
        /* Restart AN if enabled */
        if (an_enabled) {
-               read_phy(port, 0, 0, &val);
+               val = phy_read(phydev, 0);
                val |= BIT(9);
-               write_phy(port, 0, 0, val);
+               phy_write(phydev, 0, val);
        }
 
        /* GPHY page back to auto*/
-       write_phy(port, 0xa42, 30, 0);
+       phy_write_paged(phydev, 0xa42, 30, 0);
 }
 
 static int rtl8218b_get_eee(struct phy_device *phydev,
@@ -1171,21 +1046,21 @@ static int rtl8218b_get_eee(struct phy_device *phydev,
        pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
 
        /* Set GPHY page to copper */
-       write_phy(addr, 0xa42, 29, 0x0001);
+       phy_write_paged(phydev, 0xa42, 29, 0x0001);
 
-       read_phy(addr, 7, 60, &val);
+       val = phy_read_paged(phydev, 7, 60);
        if (e->eee_enabled) {
                // Verify vs MAC-based EEE
                e->eee_enabled = !!(val & BIT(7));
                if (!e->eee_enabled) {
-                       read_phy(addr, 0x0A43, 25, &val);
+                       val = phy_read_paged(phydev, 0x0A43, 25);
                        e->eee_enabled = !!(val & BIT(4));
                }
        }
        pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
 
        /* GPHY page to auto */
-       write_phy(addr, 0xa42, 29, 0x0000);
+       phy_write_paged(phydev, 0xa42, 29, 0x0000);
 
        return 0;
 }
@@ -1199,15 +1074,15 @@ static int rtl8218d_get_eee(struct phy_device *phydev,
        pr_debug("In %s, port %d, was enabled: %d\n", __func__, addr, e->eee_enabled);
 
        /* Set GPHY page to copper */
-       write_phy(addr, 0xa42, 30, 0x0001);
+       phy_write_paged(phydev, 0xa42, 30, 0x0001);
 
-       read_phy(addr, 7, 60, &val);
+       val = phy_read_paged(phydev, 7, 60);
        if (e->eee_enabled)
                e->eee_enabled = !!(val & BIT(7));
        pr_debug("%s: enabled: %d\n", __func__, e->eee_enabled);
 
        /* GPHY page to auto */
-       write_phy(addr, 0xa42, 30, 0x0000);
+       phy_write_paged(phydev, 0xa42, 30, 0x0000);
 
        return 0;
 }
@@ -1222,7 +1097,7 @@ static int rtl8214fc_set_eee(struct phy_device *phydev,
 
        pr_debug("In %s port %d, enabled %d\n", __func__, port, e->eee_enabled);
 
-       if (rtl8380_rtl8214fc_media_is_fibre(port)) {
+       if (rtl8380_rtl8214fc_media_is_fibre(phydev)) {
                netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", port);
                return -ENOTSUPP;
        }
@@ -1230,38 +1105,39 @@ static int rtl8214fc_set_eee(struct phy_device *phydev,
        poll_state = disable_polling(port);
 
        /* Set GPHY page to copper */
-       write_phy(port, 0xa42, 29, 0x0001);
+       phy_write_paged(phydev, 0xa42, 29, 0x0001);
 
        // Get auto-negotiation status
-       read_phy(port, 0, 0, &val);
+       val = phy_read(phydev, 0);
        an_enabled = val & BIT(12);
 
        pr_info("%s: aneg: %d\n", __func__, an_enabled);
-       read_phy(port, 0x0A43, 25, &val);
+       val = phy_read_paged(phydev, 0x0A43, 25);
        val &= ~BIT(5);  // Use MAC-based EEE
-       write_phy(port, 0x0A43, 25, val);
+       phy_write_paged(phydev, 0x0A43, 25, val);
 
        /* Enable 100M (bit 1) / 1000M (bit 2) EEE */
-       write_phy(port, 7, 60, e->eee_enabled ? 0x6 : 0);
+       phy_write_paged(phydev, 7, 60, e->eee_enabled ? 0x6 : 0);
 
        /* 500M EEE ability */
-       read_phy(port, 0xa42, 20, &val);
+       val = phy_read_paged(phydev, 0xa42, 20);
        if (e->eee_enabled)
                val |= BIT(7);
        else
                val &= ~BIT(7);
-       write_phy(port, 0xa42, 20, val);
+
+       phy_write_paged(phydev, 0xa42, 20, val);
 
        /* Restart AN if enabled */
        if (an_enabled) {
                pr_info("%s: doing aneg\n", __func__);
-               read_phy(port, 0, 0, &val);
+               val = phy_read(phydev, 0);
                val |= BIT(9);
-               write_phy(port, 0, 0, val);
+               phy_write(phydev, 0, val);
        }
 
        /* GPHY page back to auto*/
-       write_phy(port, 0xa42, 29, 0);
+       phy_write_paged(phydev, 0xa42, 29, 0);
 
        resume_polling(poll_state);
 
@@ -1274,7 +1150,7 @@ static int rtl8214fc_get_eee(struct phy_device *phydev,
        int addr = phydev->mdio.addr;
 
        pr_debug("In %s port %d, enabled %d\n", __func__, addr, e->eee_enabled);
-       if (rtl8380_rtl8214fc_media_is_fibre(addr)) {
+       if (rtl8380_rtl8214fc_media_is_fibre(phydev)) {
                netdev_err(phydev->attached_dev, "Port %d configured for FIBRE", addr);
                return -ENOTSUPP;
        }
@@ -1294,41 +1170,41 @@ static int rtl8218b_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
        poll_state = disable_polling(port);
 
        /* Set GPHY page to copper */
-       write_phy(port, 0, 30, 0x0001);
-       read_phy(port, 0, 0, &val);
+       phy_write(phydev, 30, 0x0001);
+       val = phy_read(phydev, 0);
        an_enabled = val & BIT(12);
 
        if (e->eee_enabled) {
                /* 100/1000M EEE Capability */
-               write_phy(port, 0, 13, 0x0007);
-               write_phy(port, 0, 14, 0x003C);
-               write_phy(port, 0, 13, 0x4007);
-               write_phy(port, 0, 14, 0x0006);
+               phy_write(phydev, 13, 0x0007);
+               phy_write(phydev, 14, 0x003C);
+               phy_write(phydev, 13, 0x4007);
+               phy_write(phydev, 14, 0x0006);
 
-               read_phy(port, 0x0A43, 25, &val);
+               val = phy_read_paged(phydev, 0x0A43, 25);
                val |= BIT(4);
-               write_phy(port, 0x0A43, 25, val);
+               phy_write_paged(phydev, 0x0A43, 25, val);
        } else {
                /* 100/1000M EEE Capability */
-               write_phy(port, 0, 13, 0x0007);
-               write_phy(port, 0, 14, 0x003C);
-               write_phy(port, 0, 13, 0x0007);
-               write_phy(port, 0, 14, 0x0000);
+               phy_write(phydev, 13, 0x0007);
+               phy_write(phydev, 14, 0x003C);
+               phy_write(phydev, 13, 0x0007);
+               phy_write(phydev, 14, 0x0000);
 
-               read_phy(port, 0x0A43, 25, &val);
+               val = phy_read_paged(phydev, 0x0A43, 25);
                val &= ~BIT(4);
-               write_phy(port, 0x0A43, 25, val);
+               phy_write_paged(phydev, 0x0A43, 25, val);
        }
 
        /* Restart AN if enabled */
        if (an_enabled) {
-               read_phy(port, 0, 0, &val);
+               val = phy_read(phydev, 0);
                val |= BIT(9);
-               write_phy(port, 0, 0, val);
+               phy_write(phydev, 0, val);
        }
 
        /* GPHY page back to auto*/
-       write_phy(port, 0xa42, 30, 0);
+       phy_write_paged(phydev, 0xa42, 30, 0);
 
        pr_info("%s done\n", __func__);
        resume_polling(poll_state);
@@ -1345,7 +1221,7 @@ static int rtl8218d_set_eee(struct phy_device *phydev, struct ethtool_eee *e)
 
        poll_state = disable_polling(addr);
 
-       rtl8218d_eee_set(addr, (bool) e->eee_enabled);
+       rtl8218d_eee_set(phydev, (bool) e->eee_enabled);
 
        resume_polling(poll_state);
 
@@ -1362,16 +1238,16 @@ static int rtl8380_configure_rtl8214c(struct phy_device *phydev)
        u32 phy_id, val;
        int mac = phydev->mdio.addr;
 
-       read_phy(mac, 0, 2, &val);
+       val = phy_read(phydev, 2);
        phy_id = val << 16;
-       read_phy(mac, 0, 3, &val);
+       val = phy_read(phydev, 3);
        phy_id |= val;
        pr_debug("Phy on MAC %d: %x\n", mac, phy_id);
 
        phydev_info(phydev, "Detected external RTL8214C\n");
 
        /* GPHY auto conf */
-       write_phy(mac, 0xa42, 29, 0);
+       phy_write_paged(phydev, 0xa42, 29, 0);
        return 0;
 }
 
@@ -1384,17 +1260,17 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
        u32 *rtl8380_rtl8214fc_perchip;
        u32 *rtl8380_rtl8214fc_perport;
 
-       read_phy(mac, 0, 2, &val);
+       val = phy_read(phydev, 2);
        phy_id = val << 16;
-       read_phy(mac, 0, 3, &val);
+       val = phy_read(phydev, 3);
        phy_id |= val;
        pr_debug("Phy on MAC %d: %x\n", mac, phy_id);
 
        /* Read internal PHY id */
-       write_phy(mac, 0, 30, 0x0001);
-       write_phy(mac, 0, 31, 0x0a42);
-       write_phy(mac, 31, 27, 0x0002);
-       read_phy(mac, 31, 28, &val);
+       phy_write_paged(phydev, 0, 30, 0x0001);
+       phy_write_paged(phydev, 0, 31, 0x0a42);
+       phy_write_paged(phydev, 31, 27, 0x0002);
+       val = phy_read_paged(phydev, 31, 28);
        if (val != 0x6276) {
                phydev_err(phydev, "Expected external RTL8214FC, found PHY-ID %x\n", val);
                return -1;
@@ -1417,17 +1293,17 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
                   + h->parts[1].start;
 
        /* detect phy version */
-       write_phy(mac, 0xfff, 27, 0x0004);
-       read_phy(mac, 0xfff, 28, &val);
+       phy_write_paged(phydev, 0xfff, 27, 0x0004);
+       val = phy_read_paged(phydev, 0xfff, 28);
 
-       read_phy(mac, 0, 16, &val);
+       val = phy_read(phydev, 16);
        if (val & (1 << 11))
-               rtl8380_rtl8214fc_on_off(mac, true);
+               rtl8380_rtl8214fc_on_off(phydev, true);
        else
-               rtl8380_phy_reset(mac);
+               rtl8380_phy_reset(phydev);
 
        msleep(100);
-       write_phy(mac, 0, 30, 0x0001);
+       phy_write_paged(phydev, 0, 30, 0x0001);
 
        i = 0;
        while (rtl8380_rtl8214fc_perchip[i * 3]
@@ -1435,36 +1311,36 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
                if (rtl8380_rtl8214fc_perchip[i * 3 + 1] == 0x1f)
                        page = rtl8380_rtl8214fc_perchip[i * 3 + 2];
                if (rtl8380_rtl8214fc_perchip[i * 3 + 1] == 0x13 && page == 0x260) {
-                       read_phy(mac + rtl8380_rtl8214fc_perchip[i * 3], 0x260, 13, &val);
+                       val = phy_read_paged(phydev, 0x260, 13);
                        val = (val & 0x1f00) | (rtl8380_rtl8214fc_perchip[i * 3 + 2]
                                & 0xe0ff);
-                       write_phy(mac + rtl8380_rtl8214fc_perchip[i * 3],
-                                         0xfff, rtl8380_rtl8214fc_perchip[i * 3 + 1], val);
+                       phy_write_paged(phydev, 0xfff,
+                                       rtl8380_rtl8214fc_perchip[i * 3 + 1], val);
                } else {
-                       write_phy(mac + rtl8380_rtl8214fc_perchip[i * 3],
-                                         0xfff, rtl8380_rtl8214fc_perchip[i * 3 + 1],
-                                         rtl8380_rtl8214fc_perchip[i * 3 + 2]);
+                       phy_write_paged(phydev, 0xfff,
+                                       rtl8380_rtl8214fc_perchip[i * 3 + 1],
+                                       rtl8380_rtl8214fc_perchip[i * 3 + 2]);
                }
                i++;
        }
 
        /* Force copper medium */
        for (i = 0; i < 4; i++) {
-               write_phy(mac + i, 0xfff, 0x1f, 0x0000);
-               write_phy(mac + i, 0xfff, 0x1e, 0x0001);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0000);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x1e, 0x0001);
        }
 
        /* Enable PHY */
        for (i = 0; i < 4; i++) {
-               write_phy(mac + i, 0xfff, 0x1f, 0x0000);
-               write_phy(mac + i, 0xfff, 0x00, 0x1140);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0000);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x00, 0x1140);
        }
        mdelay(100);
 
        /* Disable Autosensing */
        for (i = 0; i < 4; i++) {
                for (l = 0; l < 100; l++) {
-                       read_phy(mac + i, 0x0a42, 0x10, &val);
+                       val = phy_package_port_read_paged(phydev, i, 0x0a42, 0x10);
                        if ((val & 0x7) >= 3)
                                break;
                }
@@ -1476,15 +1352,15 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
 
        /* Request patch */
        for (i = 0; i < 4; i++) {
-               write_phy(mac + i,  0xfff, 0x1f, 0x0b82);
-               write_phy(mac + i,  0xfff, 0x10, 0x0010);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x1f, 0x0b82);
+               phy_package_port_write_paged(phydev, i, 0xfff, 0x10, 0x0010);
        }
        mdelay(300);
 
        /* Verify patch readiness */
        for (i = 0; i < 4; i++) {
                for (l = 0; l < 100; l++) {
-                       read_phy(mac + i, 0xb80, 0x10, &val);
+                       val = phy_package_port_read_paged(phydev, i, 0xb80, 0x10);
                        if (val & 0x40)
                                break;
                }
@@ -1493,36 +1369,35 @@ static int rtl8380_configure_rtl8214fc(struct phy_device *phydev)
                        return -1;
                }
        }
-
        /* Use Broadcast ID method for patching */
-       write_phy(mac, 0xfff, 0x1f, 0x0000);
-       write_phy(mac, 0xfff, 0x1d, 0x0008);
-       write_phy(mac, 0xfff, 0x1f, 0x0266);
-       write_phy(mac, 0xfff, 0x16, 0xff00 + mac);
-       write_phy(mac, 0xfff, 0x1f, 0x0000);
-       write_phy(mac, 0xfff, 0x1d, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1d, 0x0008);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0266);
+       phy_write_paged(phydev, 0xfff, 0x16, 0xff00 + mac);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1d, 0x0000);
        mdelay(1);
 
        i = 0;
        while (rtl8380_rtl8214fc_perport[i * 2]) {
-               write_phy(mac, 0xfff, rtl8380_rtl8214fc_perport[i * 2],
+               phy_write_paged(phydev, 0xfff, rtl8380_rtl8214fc_perport[i * 2],
                                  rtl8380_rtl8214fc_perport[i * 2 + 1]);
                i++;
        }
 
        /*Disable broadcast ID*/
-       write_phy(mac, 0xfff, 0x1f, 0x0000);
-       write_phy(mac, 0xfff, 0x1d, 0x0008);
-       write_phy(mac, 0xfff, 0x1f, 0x0266);
-       write_phy(mac, 0xfff, 0x16, 0x00 + mac);
-       write_phy(mac, 0xfff, 0x1f, 0x0000);
-       write_phy(mac, 0xfff, 0x1d, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1d, 0x0008);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0266);
+       phy_write_paged(phydev, 0xfff, 0x16, 0x00 + mac);
+       phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
+       phy_write_paged(phydev, 0xfff, 0x1d, 0x0000);
        mdelay(1);
 
        /* Auto medium selection */
        for (i = 0; i < 4; i++) {
-               write_phy(mac + i, 0xfff, 0x1f, 0x0000);
-               write_phy(mac + i, 0xfff, 0x1e, 0x0000);
+               phy_write_paged(phydev, 0xfff, 0x1f, 0x0000);
+               phy_write_paged(phydev, 0xfff, 0x1e, 0x0000);
        }
 
        return 0;
@@ -3765,41 +3640,41 @@ int rtl931x_link_sts_get(u32 sds)
 static int rtl8214fc_phy_probe(struct phy_device *phydev)
 {
        struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
        int addr = phydev->mdio.addr;
+       int ret = 0;
 
        /* 839x has internal SerDes */
        if (soc_info.id == 0x8393)
                return -ENODEV;
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL8214FC";
-
        /* 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)) {
-               /* Configuration must be done whil patching still possible */
-               return rtl8380_configure_rtl8214fc(phydev);
+               struct rtl83xx_shared_private *shared = phydev->shared->priv;
+               shared->name = "RTL8214FC";
+               /* Configuration must be done while patching still possible */
+               ret = rtl8380_configure_rtl8214fc(phydev);
+               if (ret)
+                       return ret;
        }
+
        return 0;
 }
 
 static int rtl8214c_phy_probe(struct phy_device *phydev)
 {
        struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
        int addr = phydev->mdio.addr;
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL8214C";
-
        /* 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 = "RTL8214C";
                /* Configuration must be done whil patching still possible */
                return rtl8380_configure_rtl8214c(phydev);
        }
@@ -3809,27 +3684,27 @@ static int rtl8214c_phy_probe(struct phy_device *phydev)
 static int rtl8218b_ext_phy_probe(struct phy_device *phydev)
 {
        struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
        int addr = phydev->mdio.addr;
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL8218B (external)";
-
        /* All base addresses of the PHYs start at multiples of 8 */
-       if (!(addr % 8) && soc_info.family == RTL8380_FAMILY_ID) {
-               /* Configuration must be done while patching still possible */
-               return rtl8380_configure_ext_rtl8218b(phydev);
+       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);
+               }
        }
+
        return 0;
 }
 
 static int rtl8218b_int_phy_probe(struct phy_device *phydev)
 {
        struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
        int addr = phydev->mdio.addr;
 
        if (soc_info.family != RTL8380_FAMILY_ID)
@@ -3837,61 +3712,43 @@ static int rtl8218b_int_phy_probe(struct phy_device *phydev)
        if (addr >= 24)
                return -ENODEV;
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL8218B (internal)";
-
+       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);
        }
+
        return 0;
 }
 
 static int rtl8218d_phy_probe(struct phy_device *phydev)
 {
        struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
        int addr = phydev->mdio.addr;
 
        pr_debug("%s: id: %d\n", __func__, addr);
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL8218D";
+       /* 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);
        }
        return 0;
 }
 
-static int rtl8226_phy_probe(struct phy_device *phydev)
-{
-       struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
-       int addr = phydev->mdio.addr;
-
-       pr_info("%s: id: %d\n", __func__, addr);
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL8226";
-
-       return 0;
-}
-
 static int rtl838x_serdes_probe(struct phy_device *phydev)
 {
-       struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
        int addr = phydev->mdio.addr;
 
        if (soc_info.family != RTL8380_FAMILY_ID)
@@ -3899,12 +3756,6 @@ static int rtl838x_serdes_probe(struct phy_device *phydev)
        if (addr < 24)
                return -ENODEV;
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL8380 Serdes";
-
        /* On the RTL8380M, PHYs 24-27 connect to the internal SerDes */
        if (soc_info.id == 0x8380) {
                if (addr == 24)
@@ -3916,8 +3767,6 @@ static int rtl838x_serdes_probe(struct phy_device *phydev)
 
 static int rtl8393_serdes_probe(struct phy_device *phydev)
 {
-       struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
        int addr = phydev->mdio.addr;
 
        pr_info("%s: id: %d\n", __func__, addr);
@@ -3927,18 +3776,11 @@ static int rtl8393_serdes_probe(struct phy_device *phydev)
        if (addr < 24)
                return -ENODEV;
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL8393 Serdes";
        return rtl8390_configure_serdes(phydev);
 }
 
 static int rtl8390_serdes_probe(struct phy_device *phydev)
 {
-       struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
        int addr = phydev->mdio.addr;
 
        if (soc_info.family != RTL8390_FAMILY_ID)
@@ -3947,27 +3789,14 @@ static int rtl8390_serdes_probe(struct phy_device *phydev)
        if (addr < 24)
                return -ENODEV;
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL8390 Serdes";
        return rtl8390_configure_generic(phydev);
 }
 
 static int rtl9300_serdes_probe(struct phy_device *phydev)
 {
-       struct device *dev = &phydev->mdio.dev;
-       struct rtl838x_phy_priv *priv;
-
        if (soc_info.family != RTL9300_FAMILY_ID)
                return -ENODEV;
 
-       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->name = "RTL9300 Serdes";
        phydev_info(phydev, "Detected internal RTL9300 Serdes\n");
 
        return rtl9300_configure_serdes(phydev);
@@ -3978,6 +3807,7 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8214C),
                .name           = "Realtek RTL8214C",
                .features       = PHY_GBIT_FEATURES,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .match_phy_device = rtl8214c_match_phy_device,
                .probe          = rtl8214c_phy_probe,
                .suspend        = genphy_suspend,
@@ -3988,13 +3818,12 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8214FC),
                .name           = "Realtek RTL8214FC",
                .features       = PHY_GBIT_FIBRE_FEATURES,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .match_phy_device = rtl8214fc_match_phy_device,
                .probe          = rtl8214fc_phy_probe,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
                .set_loopback   = genphy_loopback,
-               .read_mmd       = rtl8218b_read_mmd,
-               .write_mmd      = rtl8218b_write_mmd,
                .set_port       = rtl8214fc_set_port,
                .get_port       = rtl8214fc_get_port,
                .set_eee        = rtl8214fc_set_eee,
@@ -4004,13 +3833,12 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_E),
                .name           = "Realtek RTL8218B (external)",
                .features       = PHY_GBIT_FEATURES,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .match_phy_device = rtl8218b_ext_match_phy_device,
                .probe          = rtl8218b_ext_phy_probe,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
                .set_loopback   = genphy_loopback,
-               .read_mmd       = rtl8218b_read_mmd,
-               .write_mmd      = rtl8218b_write_mmd,
                .set_eee        = rtl8218b_set_eee,
                .get_eee        = rtl8218b_get_eee,
        },
@@ -4018,6 +3846,7 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8218D),
                .name           = "REALTEK RTL8218D",
                .features       = PHY_GBIT_FEATURES,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .probe          = rtl8218d_phy_probe,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
@@ -4029,12 +3858,10 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8221B),
                .name           = "REALTEK RTL8221B",
                .features       = PHY_GBIT_FEATURES,
-               .probe          = rtl8226_phy_probe,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
                .set_loopback   = genphy_loopback,
-               .read_mmd       = rtl8226_read_mmd,
-               .write_mmd      = rtl8226_write_mmd,
                .read_page      = rtl8226_read_page,
                .write_page     = rtl8226_write_page,
                .read_status    = rtl8226_read_status,
@@ -4046,12 +3873,10 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8226),
                .name           = "REALTEK RTL8226",
                .features       = PHY_GBIT_FEATURES,
-               .probe          = rtl8226_phy_probe,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
                .set_loopback   = genphy_loopback,
-               .read_mmd       = rtl8226_read_mmd,
-               .write_mmd      = rtl8226_write_mmd,
                .read_page      = rtl8226_read_page,
                .write_page     = rtl8226_write_page,
                .read_status    = rtl8226_read_status,
@@ -4063,12 +3888,11 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I),
                .name           = "Realtek RTL8218B (internal)",
                .features       = PHY_GBIT_FEATURES,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .probe          = rtl8218b_int_phy_probe,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
                .set_loopback   = genphy_loopback,
-               .read_mmd       = rtl8218b_read_mmd,
-               .write_mmd      = rtl8218b_write_mmd,
                .set_eee        = rtl8218b_set_eee,
                .get_eee        = rtl8218b_get_eee,
        },
@@ -4076,18 +3900,18 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8218B_I),
                .name           = "Realtek RTL8380 SERDES",
                .features       = PHY_GBIT_FIBRE_FEATURES,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .probe          = rtl838x_serdes_probe,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
                .set_loopback   = genphy_loopback,
-               .read_mmd       = rtl8218b_read_mmd,
-               .write_mmd      = rtl8218b_write_mmd,
                .read_status    = rtl8380_read_status,
        },
        {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8393_I),
                .name           = "Realtek RTL8393 SERDES",
                .features       = PHY_GBIT_FIBRE_FEATURES,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .probe          = rtl8393_serdes_probe,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
@@ -4098,6 +3922,7 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL8390_GENERIC),
                .name           = "Realtek RTL8390 Generic",
                .features       = PHY_GBIT_FIBRE_FEATURES,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .probe          = rtl8390_serdes_probe,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
@@ -4107,6 +3932,7 @@ static struct phy_driver rtl83xx_phy_driver[] = {
                PHY_ID_MATCH_MODEL(PHY_ID_RTL9300_I),
                .name           = "REALTEK RTL9300 SERDES",
                .features       = PHY_GBIT_FIBRE_FEATURES,
+               .flags          = PHY_HAS_REALTEK_PAGES,
                .probe          = rtl9300_serdes_probe,
                .suspend        = genphy_suspend,
                .resume         = genphy_resume,
index 1ccb560d2ab6214df3f997f7379d65aa67531d15..553d9a1575e6cfa98e113edd98911e7d92439bbd 100644 (file)
@@ -1,7 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
-// TODO: not really used
-struct rtl838x_phy_priv {
+struct rtl83xx_shared_private {
        char *name;
 };
 
diff --git a/target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch b/target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch
new file mode 100644 (file)
index 0000000..eeb26fa
--- /dev/null
@@ -0,0 +1,840 @@
+From 5d84f16b0036b33487b94abef15ad3c224c81ee9 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Thu, 3 Feb 2022 16:38:50 +0000
+Subject: [PATCH] net: mdio: support hardware-assisted indirect access
+
+MDIO controllers found in Switch-SoCs can offload some MDIO operations
+to the hardware:
+ * MMD register access via Clause-22
+   Instead of using multiple operations to access MMD registers via
+   MII register MII_MMD_CTRL and MII_MMD_DATA some controllers
+   allow transparent access to MMD PHY registers.
+
+ * paged MII register access
+   Some PHYs (namely RealTek and Vitesse) use vendor-defined MII
+   register 0x1f for paged access. Some MDIO host controllers support
+   transparent paged access when used with such PHYs.
+
+ * add convenience accessors to fully support paged access also on
+   multi-PHY packages (like the embedded PHYs in RTL83xx):
+   phy_package_read_paged and phy_package_write_paged
+   phy_package_port_read and phy_package_port_write
+   phy_package_port_read_paged and phy_package_port_write_paged
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ drivers/net/phy/mdio_bus.c | 335 ++++++++++++++++++++++++++++++++++++-
+ drivers/net/phy/phy-core.c |  66 +++++++-
+ include/linux/mdio.h       |  59 +++++++
+ include/linux/phy.h        | 129 ++++++++++++++
+ include/uapi/linux/mii.h   |   1 +
+ 5 files changed, 580 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/phy/mdio_bus.c
++++ b/drivers/net/phy/mdio_bus.c
+@@ -734,6 +734,32 @@ out:
+ }
+ /**
++ * __mdiobus_select_page - Unlocked version of the mdiobus_select_page function
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: register page to select
++ *
++ * Selects a MDIO bus register page. Caller must hold the mdio bus lock.
++ *
++ * NOTE: MUST NOT be called from interrupt context.
++ */
++int __mdiobus_select_page(struct mii_bus *bus, int addr, u16 page)
++{
++      lockdep_assert_held_once(&bus->mdio_lock);
++
++      if (bus->selected_page[addr] == page)
++              return 0;
++
++      bus->selected_page[addr] = page;
++      if (bus->read_paged)
++              return 0;
++
++      return bus->write(bus, addr, MII_MAINPAGE, page);
++
++}
++EXPORT_SYMBOL(__mdiobus_select_page);
++
++/**
+  * __mdiobus_read - Unlocked version of the mdiobus_read function
+  * @bus: the mii_bus struct
+  * @addr: the phy address
+@@ -749,7 +775,10 @@ int __mdiobus_read(struct mii_bus *bus,
+       WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
+-      retval = bus->read(bus, addr, regnum);
++      if (bus->read_paged)
++              retval = bus->read_paged(bus, addr, bus->selected_page[addr], regnum);
++      else
++              retval = bus->read(bus, addr, regnum);
+       trace_mdio_access(bus, 1, addr, regnum, retval, retval);
+       mdiobus_stats_acct(&bus->stats[addr], true, retval);
+@@ -759,6 +788,40 @@ int __mdiobus_read(struct mii_bus *bus,
+ EXPORT_SYMBOL(__mdiobus_read);
+ /**
++ * __mdiobus_read_paged - Unlocked version of the mdiobus_read_paged function
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: the register page to access
++ * @regnum: register number to read
++ *
++ * Read a MDIO bus register. Caller must hold the mdio bus lock.
++ *
++ * NOTE: MUST NOT be called from interrupt context.
++ */
++int __mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum)
++{
++      int retval;
++      int oldpage;
++
++      lockdep_assert_held_once(&bus->mdio_lock);
++
++      if (bus->read_paged) {
++              retval = bus->read_paged(bus, addr, page, regnum);
++      } else {
++              oldpage = bus->selected_page[addr];
++              __mdiobus_select_page(bus, addr, page);
++              retval = bus->read(bus, addr, regnum);
++              __mdiobus_select_page(bus, addr, oldpage);
++      }
++
++      trace_mdio_access(bus, 1, addr, regnum, retval, retval);
++      mdiobus_stats_acct(&bus->stats[addr], true, retval);
++
++      return retval;
++}
++EXPORT_SYMBOL(__mdiobus_read_paged);
++
++/**
+  * __mdiobus_write - Unlocked version of the mdiobus_write function
+  * @bus: the mii_bus struct
+  * @addr: the phy address
+@@ -775,7 +838,10 @@ int __mdiobus_write(struct mii_bus *bus,
+       WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock));
+-      err = bus->write(bus, addr, regnum, val);
++      if (bus->write_paged)
++              err = bus->write_paged(bus, addr, bus->selected_page[addr], regnum, val);
++      else
++              err = bus->write(bus, addr, regnum, val);
+       trace_mdio_access(bus, 0, addr, regnum, val, err);
+       mdiobus_stats_acct(&bus->stats[addr], false, err);
+@@ -785,6 +851,39 @@ int __mdiobus_write(struct mii_bus *bus,
+ EXPORT_SYMBOL(__mdiobus_write);
+ /**
++ * __mdiobus_write_paged - Unlocked version of the mdiobus_write_paged function
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: the register page to access
++ * @regnum: register number to write
++ * @val: value to write to @regnum
++ *
++ * Write a MDIO bus register. Caller must hold the mdio bus lock.
++ *
++ * NOTE: MUST NOT be called from interrupt context.
++ */
++int __mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val)
++{
++      int err, oldpage;
++
++      lockdep_assert_held_once(&bus->mdio_lock);
++
++      if (bus->write_paged) {
++              err = bus->write_paged(bus, addr, page, regnum, val);
++      } else {
++              oldpage = bus->selected_page[addr];
++              __mdiobus_select_page(bus, addr, page);
++              err = bus->write(bus, addr, regnum, val);
++              __mdiobus_select_page(bus, addr, oldpage);
++      }
++      trace_mdio_access(bus, 0, addr, regnum, val, err);
++      mdiobus_stats_acct(&bus->stats[addr], false, err);
++      return err;
++}
++EXPORT_SYMBOL(__mdiobus_write_paged);
++
++
++/**
+  * __mdiobus_modify_changed - Unlocked version of the mdiobus_modify function
+  * @bus: the mii_bus struct
+  * @addr: the phy address
+@@ -817,6 +916,43 @@ int __mdiobus_modify_changed(struct mii_
+ EXPORT_SYMBOL_GPL(__mdiobus_modify_changed);
+ /**
++ * __mdiobus_modify_changed_paged - Unlocked version of the mdiobus_modify_paged function
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @regnum: register number to modify
++ * @mask: bit mask of bits to clear
++ * @set: bit mask of bits to set
++ *
++ * Read, modify, and if any change, write the register value back to the
++ * device. Any error returns a negative number.
++ *
++ * NOTE: MUST NOT be called from interrupt context.
++ */
++int __mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u32 regnum, u16 page,
++                                 u16 mask, u16 set)
++{
++      int new, ret, oldpage;
++
++      oldpage = bus->selected_page[addr];
++      __mdiobus_select_page(bus, addr, page);
++
++      ret = __mdiobus_read_paged(bus, addr, page, regnum);
++      if (ret < 0)
++              return ret;
++
++      new = (ret & ~mask) | set;
++      if (new == ret)
++              return 0;
++
++      ret = __mdiobus_write_paged(bus, addr, page, regnum, new);
++
++      __mdiobus_select_page(bus, addr, oldpage);
++
++      return ret < 0 ? ret : 1;
++}
++EXPORT_SYMBOL_GPL(__mdiobus_modify_changed_paged);
++
++/**
+  * mdiobus_read_nested - Nested version of the mdiobus_read function
+  * @bus: the mii_bus struct
+  * @addr: the phy address
+@@ -842,6 +978,79 @@ int mdiobus_read_nested(struct mii_bus *
+ EXPORT_SYMBOL(mdiobus_read_nested);
+ /**
++ * mdiobus_select_page_nested - Nested version of the mdiobus_select_page function
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: register page to access
++ *
++ * In case of nested MDIO bus access avoid lockdep false positives by
++ * using mutex_lock_nested().
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ */
++int mdiobus_select_page_nested(struct mii_bus *bus, int addr, u16 page)
++{
++      int retval;
++
++      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++      retval = __mdiobus_select_page(bus, addr, page);
++      mutex_unlock(&bus->mdio_lock);
++
++      return retval;
++}
++EXPORT_SYMBOL(mdiobus_select_page_nested);
++
++/**
++ * mdiobus_read_paged_nested - Nested version of the mdiobus_read_paged function
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: register page to access
++ * @regnum: register number to read
++ *
++ * In case of nested MDIO bus access avoid lockdep false positives by
++ * using mutex_lock_nested().
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ */
++int mdiobus_read_paged_nested(struct mii_bus *bus, int addr, u16 page, u32 regnum)
++{
++      int retval;
++
++      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++      retval = __mdiobus_read_paged(bus, addr, page, regnum);
++      mutex_unlock(&bus->mdio_lock);
++
++      return retval;
++}
++EXPORT_SYMBOL(mdiobus_read_paged_nested);
++
++/**
++ * mdiobus_select_page - Convenience function for setting the MII register page
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: the register page to set
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ */
++int mdiobus_select_page(struct mii_bus *bus, int addr, u16 page)
++{
++      int retval;
++
++      mutex_lock(&bus->mdio_lock);
++      retval = __mdiobus_select_page(bus, addr, page);
++      mutex_unlock(&bus->mdio_lock);
++
++      return retval;
++}
++EXPORT_SYMBOL(mdiobus_select_page);
++
++/**
+  * mdiobus_read - Convenience function for reading a given MII mgmt register
+  * @bus: the mii_bus struct
+  * @addr: the phy address
+@@ -864,6 +1073,29 @@ int mdiobus_read(struct mii_bus *bus, in
+ EXPORT_SYMBOL(mdiobus_read);
+ /**
++ * mdiobus_read_paged - Convenience function for reading a given paged MII mgmt register
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: register page to access
++ * @regnum: register number to read
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ */
++int mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum)
++{
++      int retval;
++
++      mutex_lock(&bus->mdio_lock);
++      retval = __mdiobus_read_paged(bus, addr, page, regnum);
++      mutex_unlock(&bus->mdio_lock);
++
++      return retval;
++}
++EXPORT_SYMBOL(mdiobus_read_paged);
++
++/**
+  * mdiobus_write_nested - Nested version of the mdiobus_write function
+  * @bus: the mii_bus struct
+  * @addr: the phy address
+@@ -890,6 +1122,33 @@ int mdiobus_write_nested(struct mii_bus
+ EXPORT_SYMBOL(mdiobus_write_nested);
+ /**
++ * mdiobus_write_paged_nested - Nested version of the mdiobus_write_aged function
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: the register page to access
++ * @regnum: register number to write
++ * @val: value to write to @regnum
++ *
++ * In case of nested MDIO bus access avoid lockdep false positives by
++ * using mutex_lock_nested().
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ */
++int mdiobus_write_paged_nested(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val)
++{
++      int err;
++
++      mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
++      err = __mdiobus_write_paged(bus, addr, page, regnum, val);
++      mutex_unlock(&bus->mdio_lock);
++
++      return err;
++}
++EXPORT_SYMBOL(mdiobus_write_paged_nested);
++
++/**
+  * mdiobus_write - Convenience function for writing a given MII mgmt register
+  * @bus: the mii_bus struct
+  * @addr: the phy address
+@@ -913,6 +1172,30 @@ int mdiobus_write(struct mii_bus *bus, i
+ EXPORT_SYMBOL(mdiobus_write);
+ /**
++ * mdiobus_write_paged - Convenience function for writing a given paged MII mgmt register
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: the register page to access
++ * @regnum: register number to write
++ * @val: value to write to @regnum
++ *
++ * NOTE: MUST NOT be called from interrupt context,
++ * because the bus read/write functions may wait for an interrupt
++ * to conclude the operation.
++ */
++int mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val)
++{
++      int err;
++
++      mutex_lock(&bus->mdio_lock);
++      err = __mdiobus_write_paged(bus, addr, page, regnum, val);
++      mutex_unlock(&bus->mdio_lock);
++
++      return err;
++}
++EXPORT_SYMBOL(mdiobus_write_paged);
++
++/**
+  * mdiobus_modify - Convenience function for modifying a given mdio device
+  *    register
+  * @bus: the mii_bus struct
+@@ -934,6 +1217,51 @@ int mdiobus_modify(struct mii_bus *bus,
+ EXPORT_SYMBOL_GPL(mdiobus_modify);
+ /**
++ * mdiobus_modify_paged - Convenience function for modifying a given mdio device
++ *    register
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: the register page to access
++ * @regnum: register number to write
++ * @mask: bit mask of bits to clear
++ * @set: bit mask of bits to set
++ */
++int mdiobus_modify_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 mask, u16 set)
++{
++      int err;
++
++      mutex_lock(&bus->mdio_lock);
++      err = __mdiobus_modify_changed_paged(bus, addr, page, regnum, mask, set);
++      mutex_unlock(&bus->mdio_lock);
++
++      return err < 0 ? err : 0;
++}
++EXPORT_SYMBOL_GPL(mdiobus_modify_paged);
++
++/**
++ * mdiobus_modify_changed_paged - Convenience function for modifying a given paged
++ * mdio device register and returning if it changed
++ * @bus: the mii_bus struct
++ * @addr: the phy address
++ * @page: the register page to access
++ * @regnum: register number to write
++ * @mask: bit mask of bits to clear
++ * @set: bit mask of bits to set
++ */
++int mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum,
++                               u16 mask, u16 set)
++{
++      int err;
++
++      mutex_lock(&bus->mdio_lock);
++      err = __mdiobus_modify_changed_paged(bus, addr, page, regnum, mask, set);
++      mutex_unlock(&bus->mdio_lock);
++
++      return err;
++}
++EXPORT_SYMBOL_GPL(mdiobus_modify_changed_paged);
++
++/**
+  * mdio_bus_match - determine if given MDIO driver supports the given
+  *                MDIO device
+  * @dev: target MDIO device
+--- a/drivers/net/phy/phy-core.c
++++ b/drivers/net/phy/phy-core.c
+@@ -481,10 +481,16 @@ int __phy_read_mmd(struct phy_device *ph
+               struct mii_bus *bus = phydev->mdio.bus;
+               int phy_addr = phydev->mdio.addr;
+-              mmd_phy_indirect(bus, phy_addr, devad, regnum);
+-
+-              /* Read the content of the MMD's selected register */
+-              val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
++              if (bus->access_capabilities & MDIOBUS_ACCESS_C22_MMD) {
++                      val = __mdiobus_c22_mmd_read(phydev->mdio.bus,
++                                                   phydev->mdio.addr,
++                                                   devad, regnum);
++              } else {
++                      mmd_phy_indirect(bus, phy_addr, devad, regnum);
++
++                      /* Read the content of the MMD's selected register */
++                      val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
++              }
+       }
+       return val;
+ }
+@@ -537,12 +543,18 @@ int __phy_write_mmd(struct phy_device *p
+               struct mii_bus *bus = phydev->mdio.bus;
+               int phy_addr = phydev->mdio.addr;
+-              mmd_phy_indirect(bus, phy_addr, devad, regnum);
++              if (bus->access_capabilities & MDIOBUS_ACCESS_C22_MMD) {
++                      ret = __mdiobus_c22_mmd_write(phydev->mdio.bus,
++                                                    phydev->mdio.addr,
++                                                    devad, regnum, val);
++              } else {
++                      mmd_phy_indirect(bus, phy_addr, devad, regnum);
+-              /* Write the data into MMD's selected register */
+-              __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
++                      /* Write the data into MMD's selected register */
++                      __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
+-              ret = 0;
++                      ret = 0;
++              }
+       }
+       return ret;
+ }
+@@ -748,6 +760,13 @@ EXPORT_SYMBOL_GPL(phy_modify_mmd);
+ static int __phy_read_page(struct phy_device *phydev)
+ {
++      if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) {
++              struct mii_bus *bus = phydev->mdio.bus;
++              int phy_addr = phydev->mdio.addr;
++
++              return bus->selected_page[phy_addr];
++      }
++
+       if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n"))
+               return -EOPNOTSUPP;
+@@ -756,6 +775,13 @@ static int __phy_read_page(struct phy_de
+ static int __phy_write_page(struct phy_device *phydev, int page)
+ {
++      if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) {
++              struct mii_bus *bus = phydev->mdio.bus;
++              int phy_addr = phydev->mdio.addr;
++
++              return __mdiobus_select_page(bus, phy_addr, page);
++      }
++
+       if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n"))
+               return -EOPNOTSUPP;
+@@ -857,6 +883,18 @@ int phy_read_paged(struct phy_device *ph
+ {
+       int ret = 0, oldpage;
++      if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) {
++              struct mii_bus *bus = phydev->mdio.bus;
++              int phy_addr = phydev->mdio.addr;
++
++              if (bus->read_paged) {
++                      phy_lock_mdio_bus(phydev);
++                      ret = bus->read_paged(bus, phy_addr, page, regnum);
++                      phy_unlock_mdio_bus(phydev);
++                      return ret;
++              }
++      }
++
+       oldpage = phy_select_page(phydev, page);
+       if (oldpage >= 0)
+               ret = __phy_read(phydev, regnum);
+@@ -878,6 +916,18 @@ int phy_write_paged(struct phy_device *p
+ {
+       int ret = 0, oldpage;
++      if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) {
++              struct mii_bus *bus = phydev->mdio.bus;
++              int phy_addr = phydev->mdio.addr;
++
++              if (bus->write_paged) {
++                      phy_lock_mdio_bus(phydev);
++                      ret = bus->write_paged(bus, phy_addr, page, regnum, val);
++                      phy_unlock_mdio_bus(phydev);
++                      return ret;
++              }
++      }
++
+       oldpage = phy_select_page(phydev, page);
+       if (oldpage >= 0)
+               ret = __phy_write(phydev, regnum, val);
+--- a/include/linux/mdio.h
++++ b/include/linux/mdio.h
+@@ -14,6 +14,7 @@
+  * IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips.
+  */
+ #define MII_ADDR_C45          (1<<30)
++#define MII_ADDR_C22_MMD      (1<<29)
+ #define MII_DEVADDR_C45_SHIFT 16
+ #define MII_DEVADDR_C45_MASK  GENMASK(20, 16)
+ #define MII_REGADDR_C45_MASK  GENMASK(15, 0)
+@@ -327,11 +328,19 @@ static inline void mii_10gbt_stat_mod_li
+                        advertising, lpa & MDIO_AN_10GBT_STAT_LP10G);
+ }
++int __mdiobus_select_page(struct mii_bus *bus, int addr, u16 page);
+ int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
+ int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
+ int __mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
+                            u16 mask, u16 set);
++int __mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum);
++int __mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val);
++int __mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u32 regnum, u16 page,
++                                 u16 mask, u16 set);
++
++int mdiobus_select_page(struct mii_bus *bus, int addr, u16 page);
++int mdiobus_select_page_nested(struct mii_bus *bus, int addr, u16 page);
+ int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
+ int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum);
+ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
+@@ -339,11 +348,51 @@ int mdiobus_write_nested(struct mii_bus
+ int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask,
+                  u16 set);
++int mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum);
++int mdiobus_read_nested_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum);
++int mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val);
++int mdiobus_write_nested_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val);
++int mdiobus_modify_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 mask,
++                       u16 set);
++int mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum,
++                               u16 mask, u16 set);
++
++static inline int mdiodev_read_paged(struct mdio_device *mdiodev, u16 page,
++                                   u32 regnum)
++{
++      return mdiobus_read_paged(mdiodev->bus, mdiodev->addr, page, regnum);
++}
++
++static inline int mdiodev_write_paged(struct mdio_device *mdiodev, u16 page,
++                                    u32 regnum, u16 val)
++{
++      return mdiobus_write_paged(mdiodev->bus, mdiodev->addr, page, regnum, val);
++}
++
++static inline int mdiodev_modify_paged(struct mdio_device *mdiodev, u16 page,
++                                     u32 regnum, u16 mask, u16 set)
++{
++      return mdiobus_modify_paged(mdiodev->bus, mdiodev->addr, page, regnum,
++                                  mask, set);
++}
++
++static inline int mdiodev_modify_changed_paged(struct mdio_device *mdiodev, u16 page,
++                                             u32 regnum, u16 mask, u16 set)
++{
++      return mdiobus_modify_changed_paged(mdiodev->bus, mdiodev->addr, page, regnum,
++                                          mask, set);
++}
++
+ static inline u32 mdiobus_c45_addr(int devad, u16 regnum)
+ {
+       return MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum;
+ }
++static inline u32 mdiobus_c22_mmd_addr(int devad, u16 regnum)
++{
++      return MII_ADDR_C22_MMD | devad << MII_DEVADDR_C45_SHIFT | regnum;
++}
++
+ static inline u16 mdiobus_c45_regad(u32 regnum)
+ {
+       return FIELD_GET(MII_REGADDR_C45_MASK, regnum);
+@@ -367,6 +416,19 @@ static inline int __mdiobus_c45_write(st
+                              val);
+ }
++static inline int __mdiobus_c22_mmd_read(struct mii_bus *bus, int prtad,
++                                       int devad, u16 regnum)
++{
++      return __mdiobus_read(bus, prtad, mdiobus_c22_mmd_addr(devad, regnum));
++}
++
++static inline int __mdiobus_c22_mmd_write(struct mii_bus *bus, int prtad,
++                                        int devad, u16 regnum, u16 val)
++{
++      return __mdiobus_write(bus, prtad, mdiobus_c22_mmd_addr(devad, regnum),
++                             val);
++}
++
+ static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
+                                  u16 regnum)
+ {
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -80,6 +80,7 @@ extern const int phy_10gbit_features_arr
+ #define PHY_IS_INTERNAL               0x00000001
+ #define PHY_RST_AFTER_CLK_EN  0x00000002
+ #define PHY_POLL_CABLE_TEST   0x00000004
++#define PHY_HAS_REALTEK_PAGES 0x00000010
+ #define MDIO_DEVICE_IS_PHY    0x80000000
+ /**
+@@ -374,6 +375,22 @@ struct mii_bus {
+       /** @shared: shared state across different PHYs */
+       struct phy_package_shared *shared[PHY_MAX_ADDR];
++
++      /** @access_capabilities: hardware-assisted access capabilties */
++      enum {
++              MDIOBUS_ACCESS_SOFTWARE_ONLY = 0,
++              MDIOBUS_ACCESS_C22_MMD = 0x1,
++      } access_capabilities;
++
++      /** @read: Perform a read transfer on the bus, offloading page access */
++      int (*read_paged)(struct mii_bus *bus, int addr, u16 page, int regnum);
++      /** @write: Perform a write transfer on the bus, offloading page access */
++      int (*write_paged)(struct mii_bus *bus, int addr, u16 page, int regnum, u16 val);
++      /** currently selected page when page access is offloaded
++       * array should be PHY_MAX_ADDR+1size, but current design of the MDIO driver
++       * uses port addresses as phy addresses and they are up to 6 bit.
++       */
++      u16 selected_page[64];
+ };
+ #define to_mii_bus(d) container_of(d, struct mii_bus, dev)
+@@ -1651,6 +1668,66 @@ static inline int __phy_package_read(str
+       return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
+ }
++static inline int phy_package_read_port(struct phy_device *phydev, u16 port, u32 regnum)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return mdiobus_read(phydev->mdio.bus, shared->addr + port, regnum);
++}
++
++static inline int __phy_package_read_port(struct phy_device *phydev, u16 port, u32 regnum)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return __mdiobus_read(phydev->mdio.bus, shared->addr + port, regnum);
++}
++
++static inline int phy_package_read_paged(struct phy_device *phydev, u16 page, u32 regnum)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return mdiobus_read_paged(phydev->mdio.bus, shared->addr, page, regnum);
++}
++
++static inline int __phy_package_read_paged(struct phy_device *phydev, u16 page, u32 regnum)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return __mdiobus_read_paged(phydev->mdio.bus, shared->addr, page, regnum);
++}
++
++static inline int phy_package_port_read_paged(struct phy_device *phydev, u16 port, u16 page, u32 regnum)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return mdiobus_read_paged(phydev->mdio.bus, shared->addr + port, page, regnum);
++}
++
++static inline int __phy_package_port_read_paged(struct phy_device *phydev, u16 port, u16 page, u32 regnum)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return __mdiobus_read_paged(phydev->mdio.bus, shared->addr + port, page, regnum);
++}
++
+ static inline int phy_package_write(struct phy_device *phydev,
+                                   u32 regnum, u16 val)
+ {
+@@ -1673,6 +1750,72 @@ static inline int __phy_package_write(st
+       return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
+ }
++static inline int phy_package_port_write(struct phy_device *phydev,
++                                       u16 port, u32 regnum, u16 val)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return mdiobus_write(phydev->mdio.bus, shared->addr + port, regnum, val);
++}
++
++static inline int __phy_package_port_write(struct phy_device *phydev,
++                                    u16 port, u32 regnum, u16 val)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return __mdiobus_write(phydev->mdio.bus, shared->addr + port, regnum, val);
++}
++
++static inline int phy_package_port_write_paged(struct phy_device *phydev,
++                                      u16 port, u16 page, u32 regnum, u16 val)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return mdiobus_write_paged(phydev->mdio.bus, shared->addr + port, page, regnum, val);
++}
++
++static inline int __phy_package_port_write_paged(struct phy_device *phydev,
++                                      u16 port, u16 page, u32 regnum, u16 val)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return __mdiobus_write_paged(phydev->mdio.bus, shared->addr + port, page, regnum, val);
++}
++
++static inline int phy_package_write_paged(struct phy_device *phydev,
++                                        u16 page, u32 regnum, u16 val)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return mdiobus_write_paged(phydev->mdio.bus, shared->addr, page, regnum, val);
++}
++
++static inline int __phy_package_write_paged(struct phy_device *phydev,
++                                        u16 page, u32 regnum, u16 val)
++{
++      struct phy_package_shared *shared = phydev->shared;
++
++      if (!shared)
++              return -EIO;
++
++      return __mdiobus_write_paged(phydev->mdio.bus, shared->addr, page, regnum, val);
++}
++
+ static inline bool __phy_package_set_once(struct phy_device *phydev,
+                                         unsigned int b)
+ {
+--- a/include/uapi/linux/mii.h
++++ b/include/uapi/linux/mii.h
+@@ -36,6 +36,7 @@
+ #define MII_RESV2             0x1a    /* Reserved...                 */
+ #define MII_TPISTATUS         0x1b    /* TPI status for 10mbps       */
+ #define MII_NCONFIG           0x1c    /* Network interface config    */
++#define MII_MAINPAGE          0x1f    /* Page register               */
+ /* Basic mode control register. */
+ #define BMCR_RESV             0x003f  /* Unused...                   */