From: Markus Stockhausen Date: Sat, 13 Jun 2026 14:36:31 +0000 (+0200) Subject: realtek: mdio: backport upstream patches X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee02f6f16bf06db60867aad7e125caba189e1e7e;p=thirdparty%2Fopenwrt.git realtek: mdio: backport upstream patches Another round of MDIO driver patches was accepted upstream. Not production relevant as OpenWrt still uses the downstream driver. Link: https://github.com/openwrt/openwrt/pull/23768 Signed-off-by: Markus Stockhausen --- diff --git a/target/linux/realtek/patches-6.18/031-21-v7.2-net-mdio-realtek-rtl9300-Add-prefix-to-register-fiel.patch b/target/linux/realtek/patches-6.18/031-21-v7.2-net-mdio-realtek-rtl9300-Add-prefix-to-register-fiel.patch new file mode 100644 index 00000000000..e89eb4fb30e --- /dev/null +++ b/target/linux/realtek/patches-6.18/031-21-v7.2-net-mdio-realtek-rtl9300-Add-prefix-to-register-fiel.patch @@ -0,0 +1,147 @@ +From 474400cf3f9faec064a35a7725c72a52f5ec6e5f Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Sun, 7 Jun 2026 09:10:20 +0200 +Subject: [PATCH 04/15] net: mdio: realtek-rtl9300: Add prefix to register + field defines + +The current Realtek Otto MDIO driver has some define leftovers without +a SoC prefix. When adding new devices there will be an overlap for some +of them. Sort this out as follows: + +- PHY_CTRL_CMD/PHY_CTRL_MMD_DEVAD/PHY_CTRL_MMD_REG are common for all + series. Leave them as is but move them into a separate block. +- Add RTL9300 prefix to all other defines and adapt the callers. + +Reviewed-by: Andrew Lunn +Signed-off-by: Markus Stockhausen +--- + drivers/net/mdio/mdio-realtek-rtl9300.c | 63 +++++++++++++------------ + 1 file changed, 32 insertions(+), 31 deletions(-) + +--- a/drivers/net/mdio/mdio-realtek-rtl9300.c ++++ b/drivers/net/mdio/mdio-realtek-rtl9300.c +@@ -59,23 +59,24 @@ + #define RTL9300_SMI_PORT0_15_POLLING_SEL 0xca08 + #define RTL9300_SMI_ACCESS_PHY_CTRL_0 0xcb70 + #define RTL9300_SMI_ACCESS_PHY_CTRL_1 0xcb74 +-#define PHY_CTRL_REG_ADDR GENMASK(24, 20) +-#define PHY_CTRL_PARK_PAGE GENMASK(19, 15) +-#define PHY_CTRL_MAIN_PAGE GENMASK(14, 3) +-#define PHY_CTRL_WRITE BIT(2) +-#define PHY_CTRL_READ 0 +-#define PHY_CTRL_TYPE_C45 BIT(1) +-#define PHY_CTRL_TYPE_C22 0 +-#define PHY_CTRL_CMD BIT(0) +-#define PHY_CTRL_FAIL BIT(25) ++#define RTL9300_PHY_CTRL_REG_ADDR GENMASK(24, 20) ++#define RTL9300_PHY_CTRL_PARK_PAGE GENMASK(19, 15) ++#define RTL9300_PHY_CTRL_MAIN_PAGE GENMASK(14, 3) ++#define RTL9300_PHY_CTRL_WRITE BIT(2) ++#define RTL9300_PHY_CTRL_READ 0 ++#define RTL9300_PHY_CTRL_TYPE_C45 BIT(1) ++#define RTL9300_PHY_CTRL_TYPE_C22 0 ++#define RTL9300_PHY_CTRL_FAIL BIT(25) + #define RTL9300_SMI_ACCESS_PHY_CTRL_2 0xcb78 +-#define PHY_CTRL_INDATA GENMASK(31, 16) +-#define PHY_CTRL_DATA GENMASK(15, 0) ++#define RTL9300_PHY_CTRL_INDATA GENMASK(31, 16) ++#define RTL9300_PHY_CTRL_DATA GENMASK(15, 0) + #define RTL9300_SMI_ACCESS_PHY_CTRL_3 0xcb7c +-#define PHY_CTRL_MMD_DEVAD GENMASK(20, 16) +-#define PHY_CTRL_MMD_REG GENMASK(15, 0) + #define RTL9300_SMI_PORT0_5_ADDR_CTRL 0xcb80 + ++#define PHY_CTRL_CMD BIT(0) ++#define PHY_CTRL_MMD_DEVAD GENMASK(20, 16) ++#define PHY_CTRL_MMD_REG GENMASK(15, 0) ++ + #define MAP_ADDRS_PER_REG 6 + #define MAP_BITS_PER_ADDR 5 + #define MAP_BITS_PER_BUS 2 +@@ -204,7 +205,7 @@ static int otto_emdio_read_cmd(struct mi + if (ret) + return ret; + +- *value = FIELD_GET(PHY_CTRL_DATA, *value); ++ *value = FIELD_GET(RTL9300_PHY_CTRL_DATA, *value); + + return 0; + } +@@ -223,27 +224,27 @@ static int otto_emdio_9300_read_c22(stru + { + struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus); + struct otto_emdio_cmd_regs cmd_data = { +- .c22_data = FIELD_PREP(PHY_CTRL_REG_ADDR, regnum) | +- FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) | +- FIELD_PREP(PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)), +- .io_data = FIELD_PREP(PHY_CTRL_INDATA, port), ++ .c22_data = FIELD_PREP(RTL9300_PHY_CTRL_REG_ADDR, regnum) | ++ FIELD_PREP(RTL9300_PHY_CTRL_PARK_PAGE, 0x1f) | ++ FIELD_PREP(RTL9300_PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)), ++ .io_data = FIELD_PREP(RTL9300_PHY_CTRL_INDATA, port), + }; + +- return otto_emdio_read_cmd(bus, PHY_CTRL_TYPE_C22, &cmd_data, value); ++ return otto_emdio_read_cmd(bus, RTL9300_PHY_CTRL_TYPE_C22, &cmd_data, value); + } + + static int otto_emdio_9300_write_c22(struct mii_bus *bus, int port, int regnum, u16 value) + { + struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus); + struct otto_emdio_cmd_regs cmd_data = { +- .c22_data = FIELD_PREP(PHY_CTRL_REG_ADDR, regnum) | +- FIELD_PREP(PHY_CTRL_PARK_PAGE, 0x1f) | +- FIELD_PREP(PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)), +- .io_data = FIELD_PREP(PHY_CTRL_INDATA, value), ++ .c22_data = FIELD_PREP(RTL9300_PHY_CTRL_REG_ADDR, regnum) | ++ FIELD_PREP(RTL9300_PHY_CTRL_PARK_PAGE, 0x1f) | ++ FIELD_PREP(RTL9300_PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)), ++ .io_data = FIELD_PREP(RTL9300_PHY_CTRL_INDATA, value), + .port_mask_low = BIT(port), + }; + +- return otto_emdio_write_cmd(bus, PHY_CTRL_TYPE_C22, &cmd_data); ++ return otto_emdio_write_cmd(bus, RTL9300_PHY_CTRL_TYPE_C22, &cmd_data); + } + + static int otto_emdio_9300_read_c45(struct mii_bus *bus, int port, +@@ -252,10 +253,10 @@ static int otto_emdio_9300_read_c45(stru + struct otto_emdio_cmd_regs cmd_data = { + .c45_data = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) | + FIELD_PREP(PHY_CTRL_MMD_REG, regnum), +- .io_data = FIELD_PREP(PHY_CTRL_INDATA, port), ++ .io_data = FIELD_PREP(RTL9300_PHY_CTRL_INDATA, port), + }; + +- return otto_emdio_read_cmd(bus, PHY_CTRL_TYPE_C45, &cmd_data, value); ++ return otto_emdio_read_cmd(bus, RTL9300_PHY_CTRL_TYPE_C45, &cmd_data, value); + } + + static int otto_emdio_9300_write_c45(struct mii_bus *bus, int port, +@@ -264,11 +265,11 @@ static int otto_emdio_9300_write_c45(str + struct otto_emdio_cmd_regs cmd_data = { + .c45_data = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) | + FIELD_PREP(PHY_CTRL_MMD_REG, regnum), +- .io_data = FIELD_PREP(PHY_CTRL_INDATA, value), ++ .io_data = FIELD_PREP(RTL9300_PHY_CTRL_INDATA, value), + .port_mask_low = BIT(port), + }; + +- return otto_emdio_write_cmd(bus, PHY_CTRL_TYPE_C45, &cmd_data); ++ return otto_emdio_write_cmd(bus, RTL9300_PHY_CTRL_TYPE_C45, &cmd_data); + } + + static int otto_emdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) +@@ -582,9 +583,9 @@ static int otto_emdio_probe(struct platf + static const struct otto_emdio_info otto_emdio_9300_info = { + .addr_map_base = RTL9300_SMI_PORT0_5_ADDR_CTRL, + .bus_map_base = RTL9300_SMI_PORT0_15_POLLING_SEL, +- .cmd_fail = PHY_CTRL_FAIL, +- .cmd_read = PHY_CTRL_READ, +- .cmd_write = PHY_CTRL_WRITE, ++ .cmd_fail = RTL9300_PHY_CTRL_FAIL, ++ .cmd_read = RTL9300_PHY_CTRL_READ, ++ .cmd_write = RTL9300_PHY_CTRL_WRITE, + .cmd_regs = { + .c22_data = RTL9300_SMI_ACCESS_PHY_CTRL_1, + .c45_data = RTL9300_SMI_ACCESS_PHY_CTRL_3, diff --git a/target/linux/realtek/patches-6.18/031-22-v7.2-net-mdio-realtek-rtl9300-Make-otto_emdio_read_cmd-ge.patch b/target/linux/realtek/patches-6.18/031-22-v7.2-net-mdio-realtek-rtl9300-Make-otto_emdio_read_cmd-ge.patch new file mode 100644 index 00000000000..a5998f14872 --- /dev/null +++ b/target/linux/realtek/patches-6.18/031-22-v7.2-net-mdio-realtek-rtl9300-Make-otto_emdio_read_cmd-ge.patch @@ -0,0 +1,63 @@ +From 2b24f54b8751e483a67443f93941a81c05ccce67 Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Sun, 7 Jun 2026 10:12:51 +0200 +Subject: [PATCH 05/15] net: mdio: realtek-rtl9300: Make otto_emdio_read_cmd() + generic + +The otto_emdio_read_cmd() helper still uses RTL9300 specific properties. +This cannot be made generic as the I/O register has different layouts for +the different SoCs. E.g. + +- RTL930x: data in bits 31-16, data out bits 15-0 +- RTL931x: data in bits 15-0, data out bits 31-16 + +Add a mask parameter to the function signature and fill it properly +in the callers. As the masks will always have bits set from constant +defines, there is no need for a consistency check. + +Reviewed-by: Maxime Chevallier +Signed-off-by: Markus Stockhausen +--- + drivers/net/mdio/mdio-realtek-rtl9300.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/net/mdio/mdio-realtek-rtl9300.c ++++ b/drivers/net/mdio/mdio-realtek-rtl9300.c +@@ -191,7 +191,7 @@ static int otto_emdio_run_cmd(struct mii + } + + static int otto_emdio_read_cmd(struct mii_bus *bus, u32 cmd, +- struct otto_emdio_cmd_regs *cmd_data, u32 *value) ++ struct otto_emdio_cmd_regs *cmd_data, u32 mask, u32 *value) + { + struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus); + int ret; +@@ -205,7 +205,7 @@ static int otto_emdio_read_cmd(struct mi + if (ret) + return ret; + +- *value = FIELD_GET(RTL9300_PHY_CTRL_DATA, *value); ++ *value = field_get(mask, *value); + + return 0; + } +@@ -230,7 +230,8 @@ static int otto_emdio_9300_read_c22(stru + .io_data = FIELD_PREP(RTL9300_PHY_CTRL_INDATA, port), + }; + +- return otto_emdio_read_cmd(bus, RTL9300_PHY_CTRL_TYPE_C22, &cmd_data, value); ++ return otto_emdio_read_cmd(bus, RTL9300_PHY_CTRL_TYPE_C22, &cmd_data, ++ RTL9300_PHY_CTRL_DATA, value); + } + + static int otto_emdio_9300_write_c22(struct mii_bus *bus, int port, int regnum, u16 value) +@@ -256,7 +257,8 @@ static int otto_emdio_9300_read_c45(stru + .io_data = FIELD_PREP(RTL9300_PHY_CTRL_INDATA, port), + }; + +- return otto_emdio_read_cmd(bus, RTL9300_PHY_CTRL_TYPE_C45, &cmd_data, value); ++ return otto_emdio_read_cmd(bus, RTL9300_PHY_CTRL_TYPE_C45, &cmd_data, ++ RTL9300_PHY_CTRL_DATA, value); + } + + static int otto_emdio_9300_write_c45(struct mii_bus *bus, int port, diff --git a/target/linux/realtek/patches-6.18/031-23-v7.2-net-mdio-realtek-rtl9300-Add-registers-for-high-port.patch b/target/linux/realtek/patches-6.18/031-23-v7.2-net-mdio-realtek-rtl9300-Add-registers-for-high-port.patch new file mode 100644 index 00000000000..06e6607e418 --- /dev/null +++ b/target/linux/realtek/patches-6.18/031-23-v7.2-net-mdio-realtek-rtl9300-Add-registers-for-high-port.patch @@ -0,0 +1,58 @@ +From 2628d4b57215ff57c062644523badbabeb22a095 Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Sun, 7 Jun 2026 09:24:09 +0200 +Subject: [PATCH 06/15] net: mdio: realtek-rtl9300: Add registers for high port + count models + +The high port count models of the Realtek Otto switches have additional +registers to instrument the MDIO controller. These are: + +- High port mask: A bitfield that extends the already existing low port + mask to select ports starting from 32. +- Broadcast: This takes the port number during reads on the RTL931x. +- Extended page: Some additional page info. The SDK does not give much + information about this. Basically some fixed value must be written + into it during access. + +Reviewed-by: Andrew Lunn +Signed-off-by: Markus Stockhausen +--- + drivers/net/mdio/mdio-realtek-rtl9300.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/drivers/net/mdio/mdio-realtek-rtl9300.c ++++ b/drivers/net/mdio/mdio-realtek-rtl9300.c +@@ -91,6 +91,10 @@ struct otto_emdio_cmd_regs { + u32 c45_data; + u32 io_data; + u32 port_mask_low; ++ /* additional registers for high port count models RTL839x/RTL931x */ ++ u32 port_mask_high; ++ u32 broadcast; ++ u32 ext_page; + }; + + struct otto_emdio_priv { +@@ -164,6 +168,22 @@ static int otto_emdio_run_cmd(struct mii + return ret; + + /* Fill all registers. Hardware will read only the needed bits depending on command */ ++ if (info->cmd_regs.port_mask_high) { ++ /* Fill extra registers for high port count models */ ++ ret = regmap_write(priv->regmap, info->cmd_regs.broadcast, cmd_data->broadcast); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(priv->regmap, info->cmd_regs.ext_page, cmd_data->ext_page); ++ if (ret) ++ return ret; ++ ++ ret = regmap_write(priv->regmap, ++ info->cmd_regs.port_mask_high, cmd_data->port_mask_high); ++ if (ret) ++ return ret; ++ } ++ + ret = regmap_write(priv->regmap, info->cmd_regs.port_mask_low, cmd_data->port_mask_low); + if (ret) + return ret; diff --git a/target/linux/realtek/patches-6.18/031-24-v7.2-net-mdio-realtek-rtl9300-Add-support-for-RTL931x.patch b/target/linux/realtek/patches-6.18/031-24-v7.2-net-mdio-realtek-rtl9300-Add-support-for-RTL931x.patch new file mode 100644 index 00000000000..acb9e90a580 --- /dev/null +++ b/target/linux/realtek/patches-6.18/031-24-v7.2-net-mdio-realtek-rtl9300-Add-support-for-RTL931x.patch @@ -0,0 +1,187 @@ +From 390dfbbd1ead27523853a21fd587b1285006a4ef Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Sun, 7 Jun 2026 10:09:44 +0200 +Subject: [PATCH 07/15] net: mdio: realtek-rtl9300: Add support for RTL931x + +The MDIO driver has been prepared for multiple device support. Add all +required bits for the RTL931x (aka mango) series. This is straightforward +but some things are worth to be mentioned. + +- In contrast to RTL930x the I/O register has the input/output fields + swapped. Upper 16 bits are for read/outputs, and the lower 16 bits + are for write/inputs. +- The supported "pages" are 8192 and thus the raw page is 8191 +- The devices support up to 56 ports. Thus the MAX_PORTS definition + is increased by this commit. +- There are multiple global SMI controller registers with a different + layout from RTL930x devices. Therefore a separate setup_controller() + callback is added. + +Reviewed-by: Andrew Lunn +Signed-off-by: Markus Stockhausen +--- + drivers/net/mdio/mdio-realtek-rtl9300.c | 123 +++++++++++++++++++++++- + 1 file changed, 122 insertions(+), 1 deletion(-) + +--- a/drivers/net/mdio/mdio-realtek-rtl9300.c ++++ b/drivers/net/mdio/mdio-realtek-rtl9300.c +@@ -73,6 +73,31 @@ + #define RTL9300_SMI_ACCESS_PHY_CTRL_3 0xcb7c + #define RTL9300_SMI_PORT0_5_ADDR_CTRL 0xcb80 + ++#define RTL9310_NUM_BUSES 4 ++#define RTL9310_NUM_PAGES 8192 ++#define RTL9310_NUM_PORTS 56 ++#define RTL9310_SMI_GLB_CTRL1 0x0cbc ++#define RTL9310_SMI_GLB_FMT_SEL_C45(intf) BIT((intf) * 2 + 1) ++#define RTL9310_SMI_INDRT_ACCESS_CTRL_0 0x0c00 ++#define RTL9310_PHY_CTRL_REG_ADDR GENMASK(10, 6) ++#define RTL9310_PHY_CTRL_MAIN_PAGE GENMASK(23, 11) ++#define RTL9310_PHY_CTRL_READ 0 ++#define RTL9310_PHY_CTRL_WRITE BIT(4) ++#define RTL9310_PHY_CTRL_TYPE_C45 BIT(3) ++#define RTL9310_PHY_CTRL_TYPE_C22 0 ++#define RTL9310_PHY_CTRL_FAIL BIT(1) ++#define RTL9310_SMI_INDRT_ACCESS_BC_PHYID_CTRL 0x0c14 ++#define RTL9310_BC_PORT_ID GENMASK(10, 5) ++#define RTL9310_SMI_INDRT_ACCESS_CTRL_1 0x0c04 ++#define RTL9310_SMI_INDRT_ACCESS_CTRL_2_LOW 0x0c08 ++#define RTL9310_SMI_INDRT_ACCESS_CTRL_2_HIGH 0x0c0c ++#define RTL9310_SMI_INDRT_ACCESS_CTRL_3 0x0c10 /* I/O fields flipped */ ++#define RTL9310_PHY_CTRL_DATA GENMASK(31, 16) ++#define RTL9310_PHY_CTRL_INDATA GENMASK(15, 0) ++#define RTL9310_SMI_INDRT_ACCESS_MMD_CTRL 0x0c18 ++#define RTL9310_SMI_PORT_ADDR_CTRL 0x0c74 ++#define RTL9310_SMI_PORT_POLLING_SEL 0x0c9c ++ + #define PHY_CTRL_CMD BIT(0) + #define PHY_CTRL_MMD_DEVAD GENMASK(20, 16) + #define PHY_CTRL_MMD_REG GENMASK(15, 0) +@@ -81,7 +106,7 @@ + #define MAP_BITS_PER_ADDR 5 + #define MAP_BITS_PER_BUS 2 + #define MAP_BUSES_PER_REG 16 +-#define MAX_PORTS 28 ++#define MAX_PORTS 56 + #define MAX_SMI_BUSSES 4 + #define RAW_PAGE(priv) ((priv)->info->num_pages - 1) + +@@ -294,6 +319,60 @@ static int otto_emdio_9300_write_c45(str + return otto_emdio_write_cmd(bus, RTL9300_PHY_CTRL_TYPE_C45, &cmd_data); + } + ++static int otto_emdio_9310_read_c22(struct mii_bus *bus, int port, int regnum, u32 *value) ++{ ++ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus); ++ struct otto_emdio_cmd_regs cmd_data = { ++ .broadcast = FIELD_PREP(RTL9310_BC_PORT_ID, port), ++ .c22_data = FIELD_PREP(RTL9310_PHY_CTRL_REG_ADDR, regnum) | ++ FIELD_PREP(RTL9310_PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)), ++ }; ++ ++ return otto_emdio_read_cmd(bus, RTL9310_PHY_CTRL_TYPE_C22, &cmd_data, ++ RTL9310_PHY_CTRL_DATA, value); ++} ++ ++static int otto_emdio_9310_write_c22(struct mii_bus *bus, int port, int regnum, u16 value) ++{ ++ struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus); ++ struct otto_emdio_cmd_regs cmd_data = { ++ .c22_data = FIELD_PREP(RTL9310_PHY_CTRL_REG_ADDR, regnum) | ++ FIELD_PREP(RTL9310_PHY_CTRL_MAIN_PAGE, RAW_PAGE(priv)), ++ .io_data = FIELD_PREP(RTL9310_PHY_CTRL_INDATA, value), ++ .port_mask_high = (u32)(BIT_ULL(port) >> 32), ++ .port_mask_low = (u32)(BIT_ULL(port)), ++ }; ++ ++ return otto_emdio_write_cmd(bus, RTL9310_PHY_CTRL_TYPE_C22, &cmd_data); ++} ++ ++static int otto_emdio_9310_read_c45(struct mii_bus *bus, int port, ++ int dev_addr, int regnum, u32 *value) ++{ ++ struct otto_emdio_cmd_regs cmd_data = { ++ .broadcast = FIELD_PREP(RTL9310_BC_PORT_ID, port), ++ .c45_data = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) | ++ FIELD_PREP(PHY_CTRL_MMD_REG, regnum), ++ }; ++ ++ return otto_emdio_read_cmd(bus, RTL9310_PHY_CTRL_TYPE_C45, &cmd_data, ++ RTL9310_PHY_CTRL_DATA, value); ++} ++ ++static int otto_emdio_9310_write_c45(struct mii_bus *bus, int port, ++ int dev_addr, int regnum, u16 value) ++{ ++ struct otto_emdio_cmd_regs cmd_data = { ++ .c45_data = FIELD_PREP(PHY_CTRL_MMD_DEVAD, dev_addr) | ++ FIELD_PREP(PHY_CTRL_MMD_REG, regnum), ++ .io_data = FIELD_PREP(RTL9310_PHY_CTRL_INDATA, value), ++ .port_mask_high = (u32)(BIT_ULL(port) >> 32), ++ .port_mask_low = (u32)(BIT_ULL(port)), ++ }; ++ ++ return otto_emdio_write_cmd(bus, RTL9310_PHY_CTRL_TYPE_C45, &cmd_data); ++} ++ + static int otto_emdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) + { + struct otto_emdio_priv *priv = otto_emdio_bus_to_priv(bus); +@@ -413,6 +492,22 @@ static int otto_emdio_9300_setup_control + return 0; + } + ++static int otto_emdio_9310_setup_controller(struct otto_emdio_priv *priv) ++{ ++ int i, err; ++ ++ /* Put the interfaces into C45 mode if required */ ++ for (i = 0; i < priv->info->num_buses; i++) { ++ err = regmap_assign_bits(priv->regmap, RTL9310_SMI_GLB_CTRL1, ++ RTL9310_SMI_GLB_FMT_SEL_C45(i), ++ priv->smi_bus_is_c45[i]); ++ if (err) ++ return err; ++ } ++ ++ return 0; ++} ++ + static int otto_emdio_probe_one(struct device *dev, struct otto_emdio_priv *priv, + struct fwnode_handle *node) + { +@@ -624,8 +719,34 @@ static const struct otto_emdio_info otto + .write_c45 = otto_emdio_9300_write_c45, + }; + ++static const struct otto_emdio_info otto_emdio_9310_info = { ++ .addr_map_base = RTL9310_SMI_PORT_ADDR_CTRL, ++ .bus_map_base = RTL9310_SMI_PORT_POLLING_SEL, ++ .cmd_fail = RTL9310_PHY_CTRL_FAIL, ++ .cmd_read = RTL9310_PHY_CTRL_READ, ++ .cmd_write = RTL9310_PHY_CTRL_WRITE, ++ .cmd_regs = { ++ .broadcast = RTL9310_SMI_INDRT_ACCESS_BC_PHYID_CTRL, ++ .c22_data = RTL9310_SMI_INDRT_ACCESS_CTRL_0, ++ .c45_data = RTL9310_SMI_INDRT_ACCESS_MMD_CTRL, ++ .ext_page = RTL9310_SMI_INDRT_ACCESS_CTRL_1, ++ .io_data = RTL9310_SMI_INDRT_ACCESS_CTRL_3, ++ .port_mask_low = RTL9310_SMI_INDRT_ACCESS_CTRL_2_LOW, ++ .port_mask_high = RTL9310_SMI_INDRT_ACCESS_CTRL_2_HIGH, ++ }, ++ .num_buses = RTL9310_NUM_BUSES, ++ .num_pages = RTL9310_NUM_PAGES, ++ .num_ports = RTL9310_NUM_PORTS, ++ .setup_controller = otto_emdio_9310_setup_controller, ++ .read_c22 = otto_emdio_9310_read_c22, ++ .read_c45 = otto_emdio_9310_read_c45, ++ .write_c22 = otto_emdio_9310_write_c22, ++ .write_c45 = otto_emdio_9310_write_c45, ++}; ++ + static const struct of_device_id otto_emdio_ids[] = { + { .compatible = "realtek,rtl9301-mdio", .data = &otto_emdio_9300_info }, ++ { .compatible = "realtek,rtl9311-mdio", .data = &otto_emdio_9310_info }, + {} + }; + MODULE_DEVICE_TABLE(of, otto_emdio_ids);