#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)
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);
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)
{
.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);