]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: mdio: realtek-rtl9300: Add support for RTL931x
authorMarkus Stockhausen <markus.stockhausen@gmx.de>
Wed, 10 Jun 2026 19:41:45 +0000 (21:41 +0200)
committerJakub Kicinski <kuba@kernel.org>
Sat, 13 Jun 2026 00:24:11 +0000 (17:24 -0700)
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 <andrew@lunn.ch>
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
Link: https://patch.msgid.link/20260610194145.4153668-6-markus.stockhausen@gmx.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/mdio/mdio-realtek-rtl9300.c

index 1cdf2049cfa52b6f2bfbee1750e2db108082d45d..892ed3780a6572f77633797f8f3d8325ffd8723d 100644 (file)
 #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)
 #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(struct mii_bus *bus, int port,
        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_controller(struct otto_emdio_priv *priv)
        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_emdio_9300_info = {
        .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);