From: Markus Stockhausen Date: Wed, 6 Aug 2025 10:42:00 +0000 (-0400) Subject: realtek: RTL930x: reorganize mdio functions and SerDes register layout X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F19692%2Fhead;p=thirdparty%2Fopenwrt.git realtek: RTL930x: reorganize mdio functions and SerDes register layout The RTL930x mdio functions are scattered around the code. Relocate them to the bus (still inside the ethernet driver). With this change the phy identification looks into the proper registers. The SerDes phy identifier (register 2/3) must be changed. Additionally provide a consistent SerDes register access through the mdio bus. Until now when a SerDes directly drives a SFP module there is no clear rule of how to handle its register set that consists of two parts: - c22 phy registers 0-15 live in the fiber page (2) of the SerDes - other SerDes specific registers exist in pages before and after The mdio bus and other SerDes functions are a wild mix of directly looking into page 2 or just using self defined methods to access data. Adapt the bus to the new consistent phy interface that mixes the SerDes register set like classic Realtek phys do it. - Use register 31 as page select (already in the bus) - Always keep the common registers 0-15 in place and read fiber page - Map the SerDes internal registers into the upper vendor specific registers 16-23 according to the page select register (31). That gives a register mapping as follows: +-----------------------+-----------------------+---------------+-------------+ | reg 0x00-0x0f | reg 0x10-0x17 | reg 0x18-0x1e | reg 0x1f | +-----------------------+-----------------------+---------------+-------------+ | SerDes fiber page (3) | real SerDes registers | zero | SerDes page | | registers 0 - 15 | in packages of 8 | | select reg | +-----------------------+-----------------------+---------------+-------------+ Example to make it as clear as possible. SerDes registers on a RTL930x show Page / Reg | 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B ... -------------+---------------------------------------------------------------- 0 - SDS | 0C03 0F00 7060 7106 074D 0EBF 0F0F 0359 5248 0000 0F80 0000 ... 1 - SDS_EXT | 0000 0000 85FA 8C6D 5CCC 0000 20D8 0003 79AA 8C64 00C3 1482 ... 2 - FIB | 1140 6189 001C CA40 01A0 0000 0000 0004 0000 0000 0000 0000 ... 3 - FIB_EXT | 1140 6109 001C CA40 01A0 0000 0000 0004 0000 0000 0000 0000 ... This translates to this phy layout | SerDes fiber registers normal SerDes registers zero p.sel Page / Reg | 0x00 0x01 0x02 0x03 ... 0x10 0x11 0x12 0x13 ... 0x18 ... 0x1f -------------+--------------------------------------------------------------- 0 | 1140 6189 001C CA40 ... 0C03 0F00 7060 7106 ... 0000 ... 0000 1 | 1140 6189 001C CA40 ... 5248 0000 0F80 0000 ... 0000 ... 0001 ... 4 | 1140 6189 001C CA40 ... 0000 0000 85FA 8C6D ... 0000 ... 0004 Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/19692 Signed-off-by: Robert Marko --- diff --git a/target/linux/realtek/files-6.12/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h b/target/linux/realtek/files-6.12/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h index 2946674036e..808cbd245c6 100644 --- a/target/linux/realtek/files-6.12/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h +++ b/target/linux/realtek/files-6.12/arch/mips/include/asm/mach-rtl838x/mach-rtl83xx.h @@ -415,13 +415,6 @@ struct rtl83xx_soc_info { }; /* rtl83xx-related functions used across subsystems */ -int rtl838x_smi_wait_op(int timeout); -int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val); -int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val); -int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val); -int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val); -int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val); -int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val); int rtl931x_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-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h index 07cd98572a5..7dff91e3b75 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h @@ -194,9 +194,6 @@ int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port); /* phy functions that will need to be moved to the future mdio driver */ -int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); -int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, 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 regnum, u32 val); diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c index 034b5c09f05..d7f611f943b 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c @@ -741,125 +741,6 @@ irqreturn_t rtldsa_930x_switch_irq(int irq, void *dev_id) return IRQ_HANDLED; } -int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val) -{ - u32 v; - int err = 0; - - pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, val); - - if (port > 63 || page > 4095 || reg > 31) - return -ENOTSUPP; - - val &= 0xffff; - mutex_lock(&smi_lock); - - sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0); - sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); - v = reg << 20 | page << 3 | 0x1f << 15 | BIT(2) | BIT(0); - sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); - - do { - v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); - } while (v & 0x1); - - if (v & 0x2) - err = -EIO; - - mutex_unlock(&smi_lock); - - return err; -} - -int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val) -{ - u32 v; - int err = 0; - - if (port > 63 || page > 4095 || reg > 31) - return -ENOTSUPP; - - mutex_lock(&smi_lock); - - sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); - v = reg << 20 | page << 3 | 0x1f << 15 | 1; - sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); - - do { - v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); - } while ( v & 0x1); - - if (v & BIT(25)) { - pr_debug("Error reading phy %d, register %d\n", port, reg); - err = -EIO; - } - *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff); - - pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, *val); - - mutex_unlock(&smi_lock); - - return err; -} - -/* Write to an mmd register of the PHY */ -int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val) -{ - int err = 0; - u32 v; - - mutex_lock(&smi_lock); - - /* Set PHY to access */ - sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0); - - /* Set data to write */ - sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); - - /* Set MMD device number and register to write to */ - sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3); - - v = BIT(2) | BIT(1) | BIT(0); /* WRITE | MMD-access | EXEC */ - sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); - - do { - v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); - } while (v & BIT(0)); - - pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err); - mutex_unlock(&smi_lock); - return err; -} - -/* Read an mmd register of the PHY */ -int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) -{ - int err = 0; - u32 v; - - mutex_lock(&smi_lock); - - /* Set PHY to access */ - sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); - - /* Set MMD device number and register to write to */ - sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3); - - v = BIT(1) | BIT(0); /* MMD-access | EXEC */ - sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); - - do { - v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); - } while (v & BIT(0)); - /* There is no error-checking via BIT 25 of v, as it does not seem to be set correctly */ - *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff); - pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err); - - mutex_unlock(&smi_lock); - - return err; -} - /* Calculate both the block 0 and the block 1 hash, and return in * lower and higher word of the return value since only 12 bit of * the hash are significant diff --git a/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c b/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c index 66e06bbb31e..66b808dba91 100644 --- a/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c +++ b/target/linux/realtek/files-6.12/drivers/net/ethernet/rtl838x_eth.c @@ -27,11 +27,6 @@ extern struct rtl83xx_soc_info soc_info; extern int rtl83xx_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data); -extern int rtl930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); -extern int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val); -extern int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val); -extern int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val); - extern int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val); extern int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val); extern int rtl931x_read_sds_phy(int phy_addr, int page, int phy_reg); @@ -2276,6 +2271,127 @@ int rtmdio_930x_write_sds_phy(int sds, int page, int regnum, u16 val) return ret; } +/* RTL930x specific MDIO functions */ + +static int rtmdio_930x_write_phy(u32 port, u32 page, u32 reg, u32 val) +{ + u32 v; + int err = 0; + + pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, val); + + if (port > 63 || page > 4095 || reg > 31) + return -ENOTSUPP; + + val &= 0xffff; + mutex_lock(&rtmdio_lock); + + sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0); + sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); + v = reg << 20 | page << 3 | 0x1f << 15 | BIT(2) | BIT(0); + sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); + + do { + v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); + } while (v & 0x1); + + if (v & 0x2) + err = -EIO; + + mutex_unlock(&rtmdio_lock); + + return err; +} + +static int rtmdio_930x_read_phy(u32 port, u32 page, u32 reg, u32 *val) +{ + u32 v; + int err = 0; + + if (port > 63 || page > 4095 || reg > 31) + return -ENOTSUPP; + + mutex_lock(&rtmdio_lock); + + sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); + v = reg << 20 | page << 3 | 0x1f << 15 | 1; + sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); + + do { + v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); + } while ( v & 0x1); + + if (v & BIT(25)) { + pr_debug("Error reading phy %d, register %d\n", port, reg); + err = -EIO; + } + *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff); + + pr_debug("%s: port %d, page: %d, reg: %x, val: %x\n", __func__, port, page, reg, *val); + + mutex_unlock(&rtmdio_lock); + + return err; +} + +/* Write to an mmd register of the PHY */ +static int rtmdio_930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val) +{ + int err = 0; + u32 v; + + mutex_lock(&rtmdio_lock); + + /* Set PHY to access */ + sw_w32(BIT(port), RTL930X_SMI_ACCESS_PHY_CTRL_0); + + /* Set data to write */ + sw_w32_mask(0xffff << 16, val << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); + + /* Set MMD device number and register to write to */ + sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3); + + v = BIT(2) | BIT(1) | BIT(0); /* WRITE | MMD-access | EXEC */ + sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); + + do { + v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); + } while (v & BIT(0)); + + pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, val, err); + mutex_unlock(&rtmdio_lock); + return err; +} + +/* Read an mmd register of the PHY */ +static int rtmdio_930x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val) +{ + int err = 0; + u32 v; + + mutex_lock(&rtmdio_lock); + + /* Set PHY to access */ + sw_w32_mask(0xffff << 16, port << 16, RTL930X_SMI_ACCESS_PHY_CTRL_2); + + /* Set MMD device number and register to write to */ + sw_w32(devnum << 16 | (regnum & 0xffff), RTL930X_SMI_ACCESS_PHY_CTRL_3); + + v = BIT(1) | BIT(0); /* MMD-access | EXEC */ + sw_w32(v, RTL930X_SMI_ACCESS_PHY_CTRL_1); + + do { + v = sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_1); + } while (v & BIT(0)); + /* There is no error-checking via BIT 25 of v, as it does not seem to be set correctly */ + *val = (sw_r32(RTL930X_SMI_ACCESS_PHY_CTRL_2) & 0xffff); + pr_debug("%s: port %d, regnum: %x, val: %x (err %d)\n", __func__, port, regnum, *val, err); + + mutex_unlock(&rtmdio_lock); + + return err; +} + /* These are the core functions of our new Realtek SoC MDIO bus. */ static int rtmdio_read_c45(struct mii_bus *bus, int addr, int devnum, int regnum) @@ -2347,7 +2463,7 @@ static int rtmdio_write_sds_phy(struct rtmdio_bus_priv *priv, int sds, int page, return ret; } -static int rtmdio_83xx_read(struct mii_bus *bus, int addr, int regnum) +static int rtmdio_read(struct mii_bus *bus, int addr, int regnum) { struct rtmdio_bus_priv *priv = bus->priv; int err, val; @@ -2388,12 +2504,8 @@ static int rtmdio_93xx_read(struct mii_bus *bus, int addr, int regnum) priv->raw[addr] = (priv->page[addr] == priv->rawpage); if (priv->phy_is_internal[addr]) { - if (priv->family_id == RTL9300_FAMILY_ID) - return rtmdio_930x_read_sds_phy(priv->sds_id[addr], - priv->page[addr], regnum); - else - return rtl931x_read_sds_phy(priv->sds_id[addr], - priv->page[addr], regnum); + return rtl931x_read_sds_phy(priv->sds_id[addr], + priv->page[addr], regnum); } err = (*priv->read_phy)(addr, priv->page[addr], regnum, &val); @@ -2419,7 +2531,7 @@ static int rtmdio_write_c45(struct mii_bus *bus, int addr, int devnum, int regnu return err; } -static int rtmdio_83xx_write(struct mii_bus *bus, int addr, int regnum, u16 val) +static int rtmdio_write(struct mii_bus *bus, int addr, int regnum, u16 val) { struct rtmdio_bus_priv *priv = bus->priv; int err, page; @@ -2480,12 +2592,8 @@ static int rtmdio_93xx_write(struct mii_bus *bus, int addr, int regnum, u16 val) if (!priv->raw[addr] && (regnum != RTMDIO_PAGE_SELECT || page == priv->rawpage)) { priv->raw[addr] = (page == priv->rawpage); if (priv->phy_is_internal[addr]) { - if (priv->family_id == RTL9300_FAMILY_ID) - return rtmdio_930x_write_sds_phy(priv->sds_id[addr], - page, regnum, val); - else - return rtl931x_write_sds_phy(priv->sds_id[addr], - page, regnum, val); + return rtl931x_write_sds_phy(priv->sds_id[addr], + page, regnum, val); } err = (*priv->write_phy)(addr, page, regnum, val); @@ -2767,8 +2875,8 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) switch(priv->family_id) { case RTL8380_FAMILY_ID: priv->mii_bus->name = "rtl838x-eth-mdio"; - priv->mii_bus->read = rtmdio_83xx_read; - priv->mii_bus->write = rtmdio_83xx_write; + priv->mii_bus->read = rtmdio_read; + priv->mii_bus->write = rtmdio_write; priv->mii_bus->reset = rtmdio_838x_reset; bus_priv->read_sds_phy = rtmdio_838x_read_sds_phy; bus_priv->write_sds_phy = rtmdio_838x_write_sds_phy; @@ -2781,8 +2889,8 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) break; case RTL8390_FAMILY_ID: priv->mii_bus->name = "rtl839x-eth-mdio"; - priv->mii_bus->read = rtmdio_83xx_read; - priv->mii_bus->write = rtmdio_83xx_write; + priv->mii_bus->read = rtmdio_read; + priv->mii_bus->write = rtmdio_write; priv->mii_bus->reset = rtmdio_839x_reset; bus_priv->read_sds_phy = rtmdio_839x_read_sds_phy; bus_priv->write_sds_phy = rtmdio_839x_write_sds_phy; @@ -2795,13 +2903,15 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv) break; case RTL9300_FAMILY_ID: priv->mii_bus->name = "rtl930x-eth-mdio"; - priv->mii_bus->read = rtmdio_93xx_read; - priv->mii_bus->write = rtmdio_93xx_write; + priv->mii_bus->read = rtmdio_read; + priv->mii_bus->write = rtmdio_write; priv->mii_bus->reset = rtmdio_930x_reset; - bus_priv->read_mmd_phy = rtl930x_read_mmd_phy; - bus_priv->write_mmd_phy = rtl930x_write_mmd_phy; - bus_priv->read_phy = rtl930x_read_phy; - bus_priv->write_phy = rtl930x_write_phy; + bus_priv->read_sds_phy = rtmdio_930x_read_sds_phy; + bus_priv->write_sds_phy = rtmdio_930x_write_sds_phy; + bus_priv->read_mmd_phy = rtmdio_930x_read_mmd_phy; + bus_priv->write_mmd_phy = rtmdio_930x_write_mmd_phy; + bus_priv->read_phy = rtmdio_930x_read_phy; + bus_priv->write_phy = rtmdio_930x_write_phy; bus_priv->cpu_port = RTL930X_CPU_PORT; bus_priv->rawpage = 0xfff; break; diff --git a/target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.h b/target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.h index 7fca3bb8c5b..f57eb508675 100644 --- a/target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.h +++ b/target/linux/realtek/files-6.12/drivers/net/phy/rtl83xx-phy.h @@ -32,7 +32,7 @@ struct __attribute__ ((__packed__)) fw_header { #define PHY_ID_RTL8226 0x001cc838 #define PHY_ID_RTL8390_GENERIC 0x001ccab0 #define PHY_ID_RTL8393_I 0x001c8393 -#define PHY_ID_RTL9300_I 0x70d03106 +#define PHY_ID_RTL9300_I 0x338002a0 /* These PHYs share the same id (0x001cc981) */ #define PHY_IS_NOT_RTL821X 0