From b53202a8c3f728c348c5376e5b5fb36af7c37744 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Fri, 4 Feb 2022 12:28:37 +0000 Subject: [PATCH] realtek: switch to use generic MDIO accessor functions 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 --- .../drivers/net/dsa/rtl83xx/common.c | 5 +- .../drivers/net/ethernet/rtl838x_eth.c | 151 +++- .../drivers/net/ethernet/rtl838x_eth.h | 4 + .../files-5.10/drivers/net/phy/rtl83xx-phy.c | 708 ++++++--------- .../files-5.10/drivers/net/phy/rtl83xx-phy.h | 3 +- ...rt-hardware-assisted-indirect-access.patch | 840 ++++++++++++++++++ 6 files changed, 1238 insertions(+), 473 deletions(-) create mode 100644 target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c index 9675ba88f1..75243bab07 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c @@ -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) { diff --git a/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c index eb566766ca..23d22f16e2 100644 --- a/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.c @@ -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; diff --git a/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.h b/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.h index 6013de6c73..2d1f80dc9d 100644 --- a/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.h +++ b/target/linux/realtek/files-5.10/drivers/net/ethernet/rtl838x_eth.h @@ -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); diff --git a/target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.c b/target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.c index c1d6af6375..9b674e51ab 100644 --- a/target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.c +++ b/target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.c @@ -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, diff --git a/target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.h b/target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.h index 1ccb560d2a..553d9a1575 100644 --- a/target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.h +++ b/target/linux/realtek/files-5.10/drivers/net/phy/rtl83xx-phy.h @@ -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 index 0000000000..eeb26fa199 --- /dev/null +++ b/target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch @@ -0,0 +1,840 @@ +From 5d84f16b0036b33487b94abef15ad3c224c81ee9 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +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 +--- + 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... */ -- 2.30.2