diff --git a/target/linux/realtek/dts/rtl838x.dtsi b/target/linux/realtek/dts/rtl838x.dtsi index f4b629033b..3b17c66c0b 100644 --- a/target/linux/realtek/dts/rtl838x.dtsi +++ b/target/linux/realtek/dts/rtl838x.dtsi @@ -226,6 +226,10 @@ pinctrl-0 = <&mdio_aux_mdx>, <&aux_mode_mdio>; }; + mdio_serdes: mdio-serdes { + compatible = "realtek,rtl8380-serdes-mdio", "realtek,otto-serdes-mdio"; + }; + soc_thermal: thermal { compatible = "realtek,rtl8380-thermal"; #thermal-sensor-cells = <0>; diff --git a/target/linux/realtek/dts/rtl839x.dtsi b/target/linux/realtek/dts/rtl839x.dtsi index 256ee0bc30..9eb4be8af8 100644 --- a/target/linux/realtek/dts/rtl839x.dtsi +++ b/target/linux/realtek/dts/rtl839x.dtsi @@ -234,6 +234,10 @@ pinctrl-0 = <&mdio_aux_mdx>; }; + mdio_serdes: mdio-serdes { + compatible = "realtek,rtl8392-serdes-mdio", "realtek,otto-serdes-mdio"; + }; + soc_thermal: thermal { compatible = "realtek,rtl8390-thermal"; #thermal-sensor-cells = <0>; diff --git a/target/linux/realtek/dts/rtl930x.dtsi b/target/linux/realtek/dts/rtl930x.dtsi index 13c6fad5a1..97bf6abe5d 100644 --- a/target/linux/realtek/dts/rtl930x.dtsi +++ b/target/linux/realtek/dts/rtl930x.dtsi @@ -201,6 +201,10 @@ status = "disabled"; }; + mdio_serdes: mdio-serdes { + compatible = "realtek,rtl9301-serdes-mdio", "realtek,otto-serdes-mdio"; + }; + soc_thermal: thermal { compatible = "realtek,rtl9300-thermal"; #thermal-sensor-cells = <0>; diff --git a/target/linux/realtek/dts/rtl931x.dtsi b/target/linux/realtek/dts/rtl931x.dtsi index 27f12df2b8..352e9547f0 100644 --- a/target/linux/realtek/dts/rtl931x.dtsi +++ b/target/linux/realtek/dts/rtl931x.dtsi @@ -232,6 +232,11 @@ status = "disabled"; }; + + mdio_serdes: mdio-serdes { + compatible = "realtek,rtl9311-serdes-mdio", "realtek,otto-serdes-mdio"; + }; + }; pinmux@1b001358 { diff --git a/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto-serdes.c b/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto-serdes.c new file mode 100644 index 0000000000..6296d1b6fe --- /dev/null +++ b/target/linux/realtek/files-6.12/drivers/net/mdio/mdio-realtek-otto-serdes.c @@ -0,0 +1,532 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTSDS_REG_CNT 32 +#define RTSDS_VAL_MASK GENMASK(15, 0) +#define RTSDS_SUBPAGE(page) (page % 64) + +#define RTSDS_MMD_PAGE_MASK GENMASK(15, 8) +#define RTSDS_MMD_REG_MASK GENMASK(7, 0) + +#define RTSDS_838X_SDS_CNT 6 +#define RTSDS_838X_PAGE_CNT 4 +#define RTSDS_838X_BASE 0xe780 + +#define RTSDS_839X_SDS_CNT 14 +#define RTSDS_839X_PAGE_CNT 12 +#define RTSDS_839X_BASE 0xa000 + +#define RTSDS_930X_SDS_CNT 12 +#define RTSDS_930X_PAGE_CNT 64 +#define RTSDS_930X_BASE 0x03b0 + +#define RTSDS_931X_SDS_CNT 14 +#define RTSDS_931X_PAGE_CNT 192 +#define RTSDS_931X_BASE 0x5638 + +#define RTSDS_93XX_CMD_READ 0 +#define RTSDS_93XX_CMD_WRITE BIT(1) +#define RTSDS_93XX_CMD_BUSY BIT(0) +#define RTSDS_93XX_CMD_SDS_MASK GENMASK(6, 2) +#define RTSDS_93XX_CMD_PAGE_MASK GENMASK(12, 7) +#define RTSDS_93XX_CMD_REG_MASK GENMASK(17, 13) + +struct rtsds_ctrl { + struct device *dev; + struct regmap *map; + struct mii_bus *bus; + const struct rtsds_config *cfg; +}; + +struct rtsds_config { + int sds_cnt; + int page_cnt; + int base; + int (*read)(struct rtsds_ctrl *ctrl, int sds, int page, int regnum); + int (*write)(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, u16 value); + int (*backing_sds)(int sds, int page); +}; + +static bool rtsds_mmd_to_sds(struct rtsds_ctrl *ctrl, int addr, int devad, int mmd_regnum, + int *sds_page, int *sds_regnum) +{ + *sds_page = FIELD_GET(RTSDS_MMD_PAGE_MASK, mmd_regnum); + *sds_regnum = FIELD_GET(RTSDS_MMD_REG_MASK, mmd_regnum); + + return !(addr < 0 || addr >= ctrl->cfg->sds_cnt || + *sds_page < 0 || *sds_page >= ctrl->cfg->page_cnt || + *sds_regnum < 0 || *sds_regnum >= RTSDS_REG_CNT || + devad != MDIO_MMD_VEND1); +} + +static int rtsds_sds_to_mmd(int sds_page, int sds_regnum) +{ + return FIELD_PREP(RTSDS_MMD_PAGE_MASK, sds_page) | + FIELD_PREP(RTSDS_MMD_REG_MASK, sds_regnum); +} + +static int rtsds_get_backing_sds(int sds, int page) +{ + /* non RTL931x devices have 1:1 frontend/backend mapping */ + return sds; +} + +#ifdef CONFIG_DEBUG_FS + +/* + * The SerDes offer a lot of magic that sill needs to be uncovered. Getting this info manually + * with mdio command line tools can be time consuming. Provide a convenient register dump. + */ + +#define RTSDS_DBG_PAGE_NAMES 48 +#define RTSDS_DBG_ROOT_DIR "realtek_otto_serdes" + +struct rtsds_debug_info { + struct rtsds_ctrl *ctrl; + int sds; +}; + +static const char * const rtsds_page_name[RTSDS_DBG_PAGE_NAMES] = { + [0] = "SDS", [1] = "SDS_EXT", + [2] = "FIB", [3] = "FIB_EXT", + [4] = "DTE", [5] = "DTE_EXT", + [6] = "TGX", [7] = "TGX_EXT", + [8] = "ANA_RG", [9] = "ANA_RG_EXT", + [10] = "ANA_TG", [11] = "ANA_TG_EXT", + [31] = "ANA_WDIG", + [32] = "ANA_MISC", [33] = "ANA_COM", + [34] = "ANA_SP", [35] = "ANA_SP_EXT", + [36] = "ANA_1G", [37] = "ANA_1G_EXT", + [38] = "ANA_2G", [39] = "ANA_2G_EXT", + [40] = "ANA_3G", [41] = "ANA_3G_EXT", + [42] = "ANA_5G", [43] = "ANA_5G_EXT", + [44] = "ANA_6G", [45] = "ANA_6G_EXT", + [46] = "ANA_10G", [47] = "ANA_10G_EXT", +}; + +static int rtsds_dbg_registers_show(struct seq_file *seqf, void *unused) +{ + struct rtsds_debug_info *dbg_info = seqf->private; + struct rtsds_ctrl *ctrl = dbg_info->ctrl; + struct mii_bus *bus = ctrl->bus; + int sds = dbg_info->sds; + int regnum, page = 0; + int subpage; + + do { + subpage = RTSDS_SUBPAGE(page); + if (!subpage) { + seq_printf(seqf, "Back SDS %02d:", ctrl->cfg->backing_sds(sds, page)); + for (regnum = 0; regnum < RTSDS_REG_CNT; regnum++) + seq_printf(seqf, " %02X", regnum); + seq_puts(seqf, "\n"); + } + + if (subpage < RTSDS_DBG_PAGE_NAMES && rtsds_page_name[subpage]) + seq_printf(seqf, "%*s: ", -11, rtsds_page_name[subpage]); + else + seq_printf(seqf, "PAGE %02X : ", page); + + for (regnum = 0; regnum < RTSDS_REG_CNT; regnum++) + seq_printf(seqf, "%04X ", + mdiobus_c45_read(bus, sds, MDIO_MMD_VEND1, + rtsds_sds_to_mmd(page, regnum))); + seq_puts(seqf, "\n"); + } while (++page < ctrl->cfg->page_cnt); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(rtsds_dbg_registers); + +static int rtsds_debug_init(struct rtsds_ctrl *ctrl, u32 sds) +{ + struct rtsds_debug_info *dbg_info; + struct dentry *dir, *root; + char dirname[32]; + + dbg_info = kzalloc(sizeof(*dbg_info), GFP_KERNEL); + if (!dbg_info) + return -ENOMEM; + + dbg_info->ctrl = ctrl; + dbg_info->sds = sds; + + root = debugfs_lookup(RTSDS_DBG_ROOT_DIR, NULL); + if (!root) + root = debugfs_create_dir(RTSDS_DBG_ROOT_DIR, NULL); + + snprintf(dirname, sizeof(dirname), "serdes.%d", sds); + dir = debugfs_create_dir(dirname, root); + + debugfs_create_file("registers", 0600, dir, dbg_info, &rtsds_dbg_registers_fops); + + return 0; +} + +#endif /* CONFIG_DEBUG_FS */ + +/* + * The RTL838x has 6 SerDes. The 16 bit registers start at 0xbb00e780 and are mapped directly into + * 32 bit memory addresses. High 16 bits are always empty. A "lower" memory block serves pages 0/3 + * a "higher" memory block pages 1/2. + */ + +static int rtsds_838x_reg_offset(int sds, int page, int regnum) +{ + if (page == 0 || page == 3) + return (sds << 9) + (page << 7) + (regnum << 2); + + /* (page == 1 || page == 2) */ + return 0xb80 + (sds << 8) + (page << 7) + (regnum << 2); +} + +static int rtsds_838x_read(struct rtsds_ctrl *ctrl, int sds, int page, int regnum) +{ + int offset = rtsds_838x_reg_offset(sds, page, regnum); + int ret, value; + + ret = regmap_read(ctrl->map, ctrl->cfg->base + offset, &value); + + return ret ? ret : value & RTSDS_VAL_MASK; +} + +static int rtsds_838x_write(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, u16 value) +{ + int offset = rtsds_838x_reg_offset(sds, page, regnum); + + return regmap_write(ctrl->map, ctrl->cfg->base + offset, value); +} + +/* + * The RTL839x has 14 SerDes starting at 0xbb00a000. 0-7, 10, 11 are 5GBit, 8, 9, 12, 13 are + * 10 GBit. Two adjacent SerDes are tightly coupled and share a 1024 bytes register area. Per 32 + * bit address two registers are stored. The first register is stored in the lower 2 bytes ("on + * the right" due to big endian) and the second register in the upper 2 bytes. The following + * register areas are known: + * + * - XSG0 (4 pages @ offset 0x000): for even SerDes + * - XSG1 (4 pages @ offset 0x100): for odd SerDes + * - TGRX (4 pages @ offset 0x200): for even 10G SerDes + * - ANA_RG (2 pages @ offset 0x300): for even 5G SerDes + * - ANA_RG (2 pages @ offset 0x380): for odd 5G SerDes + * - ANA_TG (2 pages @ offset 0x300): for even 10G SerDes + * - ANA_TG (2 pages @ offset 0x380): for odd 10G SerDes + * + * The most consistent mapping that aligns to the RTL93xx devices is: + * + * even 5G SerDes odd 5G SerDes even 10G SerDes odd 10G SerDes + * Page 0: XSG0/0 XSG1/0 XSG0/0 XSG1/0 + * Page 1: XSG0/1 XSG1/1 XSG0/1 XSG1/1 + * Page 2: XSG0/2 XSG1/2 XSG0/2 XSG1/2 + * Page 3: XSG0/3 XSG1/3 XSG0/3 XSG1/3 + * Page 4: TGRX/0 + * Page 5: TGRX/1 + * Page 6: TGRX/2 + * Page 7: TGRX/3 + * Page 8: ANA_RG ANA_RG + * Page 9: ANA_RG_EXT ANA_RG_EXT + * Page 10: ANA_TG ANA_TG + * Page 11: ANA_TG_EXT ANA_TG_EXT + */ + +static int rtsds_839x_reg_offset(int sds, int page, int regnum) +{ + int offset = ((sds & 0xfe) << 9) + ((regnum & 0xfe) << 1) + (page << 6); + int sds5g = (GENMASK(11, 10) | GENMASK(7, 0)) & BIT(sds); + + if (page < 4) + return offset + ((sds & 1) << 8); + else if ((page & 4) && (sds == 8 || sds == 12)) + return offset + 0x100; + else if (page >= 8 && page <= 9 && sds5g) + return offset + 0x100 + ((sds & 1) << 7); + else if (page >= 10 && !sds5g) + return offset + 0x80 + ((sds & 1) << 7); + + return -EINVAL; /* hole */ +} + +static int rtsds_839x_read(struct rtsds_ctrl *ctrl, int sds, int page, int regnum) +{ + int offset = rtsds_839x_reg_offset(sds, page, regnum); + int shift = regnum & 1 ? 16 : 0; + int ret, value; + + if (offset < 0) + return 0; + + ret = regmap_read(ctrl->map, ctrl->cfg->base + offset, &value); + + return ret ? ret : (value >> shift) & RTSDS_VAL_MASK; +} + +static int rtsds_839x_write(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, u16 value) +{ + int offset = rtsds_839x_reg_offset(sds, page, regnum); + int write_value = value; + int neigh_value; + + if (offset < 0) + return 0; + + neigh_value = rtsds_839x_read(ctrl, sds, page, regnum ^ 1); + if (neigh_value < 0) + return neigh_value; + + if (regnum & 1) + write_value = (write_value << 16) + neigh_value; + else + write_value = (neigh_value << 16) + write_value; + + return regmap_write(ctrl->map, ctrl->cfg->base + offset, write_value); +} + +/* + * RTL93xx targets use a shared implementation. Their SerDes data is accessed through two IO + * registers which simulate commands to an internal MDIO bus. + * + * The RTL930x family has 12 SerDes of three types. + * + * - SerDes 0-1 exist on the RTL9301 and 9302B and are QSGMII capable + * - SerDes 2-9 are USXGMII capabable with either quad or single configuration + * - SerDes 10-11 are 10GBase-R capable + * + * The RTL931x family has 14 "frontend" SerDes that are cascaded. All operations (e.g. reset) work + * on this frontend view while their registers are distributed over a total of least 26 background + * SerDes with 64 pages and 32 registers. Three types of SerDes exist: + * + * - Serdes 0,1 are "simple" and work on one background serdes. + * - "Even" SerDes with numbers 2, 4, 6, 8, 10, 12 work on two background SerDes. One analog and + * one digital. + * - "Odd" SerDes with numbers 3, 5, 7, 9, 11, 13 work on a total of 3 background SerDes (one + * analog and two digital) + * + * This maps to: + * + * Frontend SerDes | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + * -----------------+------------------------------------------ + * Backend SerDes 1 | 0 1 2 3 6 7 10 11 14 15 18 19 22 23 + * Backend SerDes 2 | 0 1 2 4 6 8 10 12 14 16 18 20 22 24 + * Backend SerDes 3 | 0 1 3 5 7 9 11 13 15 17 19 21 23 25 + * + * Note: In Realtek proprietary XSGMII mode (10G pumped SGMII) the frontend SerDes works on the + * two digital SerDes while in all other modes it works on the analog and the first digital + * SerDes. Overlapping (e.g. backend SerDes 7 can be analog or digital 2) is avoided by the + * existing hardware designs. + * + * Align this for readability by simulating a total of 192 pages and mix them as follows. + * + * frontend page "even" frontend SerDes "odd" frontend SerDes + * page 0x00-0x3f (analog): page 0x00-0x3f back SDS page 0x00-0x3f back SDS + * page 0x40-0x7f (digi 1): page 0x00-0x3f back SDS page 0x00-0x3f back SDS+1 + * page 0x80-0xbf (digi 2): page 0x00-0x3f back SDS+1 page 0x00-0x3f back SDS+2 + */ + +static int rtsds_931x_get_backing_sds(int sds, int page) +{ + int map[] = { 0, 1, 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23 }; + int backsds = map[sds]; + + if (sds < 2) + return backsds; + else if (sds & 1) + backsds += (page >> 6); /* distribute "odd" to 3 background SerDes */ + else + backsds += (page >> 7); /* distribute "even" to 2 background SerDes */ + + return backsds; +} + +static int rtsds_rt93xx_io(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, int cmd) +{ + int ret, op, value; + + op = FIELD_PREP(RTSDS_93XX_CMD_SDS_MASK, sds) | + FIELD_PREP(RTSDS_93XX_CMD_PAGE_MASK, page) | + FIELD_PREP(RTSDS_93XX_CMD_REG_MASK, regnum) | + RTSDS_93XX_CMD_BUSY | cmd; + + regmap_write(ctrl->map, ctrl->cfg->base, op); + ret = regmap_read_poll_timeout(ctrl->map, ctrl->cfg->base, value, + !(value & RTSDS_93XX_CMD_BUSY), 30, 1000000); + + if (ret < 0) { + dev_err(ctrl->dev, "SerDes I/O timed out\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtsds_93xx_read(struct rtsds_ctrl *ctrl, int sds, int page, int regnum) +{ + int subpage = RTSDS_SUBPAGE(page); + int ret, backsds, value; + + backsds = ctrl->cfg->backing_sds(sds, page); + ret = rtsds_rt93xx_io(ctrl, backsds, subpage, regnum, RTSDS_93XX_CMD_READ); + if (ret) + return ret; + + ret = regmap_read(ctrl->map, ctrl->cfg->base + 4, &value); + + return ret ? ret : value & RTSDS_VAL_MASK; +} + +static int rtsds_93xx_write(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, u16 value) +{ + int subpage = RTSDS_SUBPAGE(page); + int ret, backsds; + + backsds = ctrl->cfg->backing_sds(sds, page); + ret = regmap_write(ctrl->map, ctrl->cfg->base + 4, value); + if (ret) + return ret; + + return rtsds_rt93xx_io(ctrl, backsds, subpage, regnum, RTSDS_93XX_CMD_WRITE); +} + +static int rtsds_read(struct mii_bus *bus, int addr, int devad, int regnum) +{ + struct rtsds_ctrl *ctrl = bus->priv; + int sds_page, sds_regnum; + + if (!rtsds_mmd_to_sds(ctrl, addr, devad, regnum, &sds_page, &sds_regnum)) + return -EINVAL; + + return ctrl->cfg->read(ctrl, addr, sds_page, sds_regnum); +} + +static int rtsds_write(struct mii_bus *bus, int addr, int devad, int regnum, u16 value) +{ + struct rtsds_ctrl *ctrl = bus->priv; + int sds_page, sds_regnum; + + if (!rtsds_mmd_to_sds(ctrl, addr, devad, regnum, &sds_page, &sds_regnum)) + return -EINVAL; + + return ctrl->cfg->write(ctrl, addr, sds_page, sds_regnum, value); +} + +static int rtsds_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct rtsds_ctrl *ctrl; + struct mii_bus *bus; + int ret; + + bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*ctrl)); + if (!bus) + return -ENOMEM; + + ctrl = bus->priv; + ctrl->map = syscon_node_to_regmap(np->parent); + if (IS_ERR(ctrl->map)) + return PTR_ERR(ctrl->map); + + ctrl->dev = dev; + ctrl->cfg = (const struct rtsds_config *)device_get_match_data(ctrl->dev); + ctrl->bus = bus; + + snprintf(bus->id, MII_BUS_ID_SIZE, "realtek-serdes-mdio") ; + bus->name = "Realtek SerDes MDIO bus"; + bus->parent = dev; + bus->read_c45 = rtsds_read; + bus->write_c45 = rtsds_write; + bus->phy_mask = ~0ULL; + + ret = devm_mdiobus_register(dev, bus); + if (ret) + return ret; + +#ifdef CONFIG_DEBUG_FS + for (int sds = 0; sds < ctrl->cfg->sds_cnt; sds++) + rtsds_debug_init(ctrl, sds); +#endif + + dev_info(dev, "Realtek SerDes mdio bus initialized. %d SerDes, %d pages, %d registers.", + ctrl->cfg->sds_cnt, ctrl->cfg->page_cnt, RTSDS_REG_CNT); + + return 0; +} + +static const struct rtsds_config rtsds_838x_cfg = { + .sds_cnt = RTSDS_838X_SDS_CNT, + .page_cnt = RTSDS_838X_PAGE_CNT, + .base = RTSDS_838X_BASE, + .read = rtsds_838x_read, + .write = rtsds_838x_write, + .backing_sds = rtsds_get_backing_sds, +}; + +static const struct rtsds_config rtsds_839x_cfg = { + .sds_cnt = RTSDS_839X_SDS_CNT, + .page_cnt = RTSDS_839X_PAGE_CNT, + .base = RTSDS_839X_BASE, + .read = rtsds_839x_read, + .write = rtsds_839x_write, + .backing_sds = rtsds_get_backing_sds, +}; + +static const struct rtsds_config rtsds_930x_cfg = { + .sds_cnt = RTSDS_930X_SDS_CNT, + .page_cnt = RTSDS_930X_PAGE_CNT, + .base = RTSDS_930X_BASE, + .read = rtsds_93xx_read, + .write = rtsds_93xx_write, + .backing_sds = rtsds_get_backing_sds, +}; + +static const struct rtsds_config rtsds_931x_cfg = { + .sds_cnt = RTSDS_931X_SDS_CNT, + .page_cnt = RTSDS_931X_PAGE_CNT, + .base = RTSDS_931X_BASE, + .read = rtsds_93xx_read, + .write = rtsds_93xx_write, + .backing_sds = rtsds_931x_get_backing_sds, +}; + +static const struct of_device_id rtsds_of_match[] = { + { + .compatible = "realtek,rtl8380-serdes-mdio", + .data = &rtsds_838x_cfg, + }, + { + .compatible = "realtek,rtl8392-serdes-mdio", + .data = &rtsds_839x_cfg, + }, + { + .compatible = "realtek,rtl9301-serdes-mdio", + .data = &rtsds_930x_cfg, + }, + { + .compatible = "realtek,rtl9311-serdes-mdio", + .data = &rtsds_931x_cfg, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtsds_mdio_of_match); + +static struct platform_driver rtsds_mdio_driver = { + .driver = { + .name = "realtek-otto-serdes-mdio", + .of_match_table = rtsds_of_match + }, + .probe = rtsds_probe, +}; +module_platform_driver(rtsds_mdio_driver); + +MODULE_AUTHOR("Markus Stockhausen "); +MODULE_DESCRIPTION("Realtek Otto SerDes MDIO bus"); +MODULE_LICENSE("GPL v2"); \ No newline at end of file diff --git a/target/linux/realtek/patches-6.12/808-add-serdes-mdio-driver.patch b/target/linux/realtek/patches-6.12/808-add-serdes-mdio-driver.patch new file mode 100644 index 0000000000..292683f846 --- /dev/null +++ b/target/linux/realtek/patches-6.12/808-add-serdes-mdio-driver.patch @@ -0,0 +1,37 @@ +From fc3eda9aa25765b2115e7427ee4f6dbcd60f8721 Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Mon, 15 Sep 2025 17:23:31 +0200 +Subject: [PATCH] net: mdio: Add Realtek Otto SerDes controller + +SoCs in Realtek's Otto platform such as the RTL83xx and RTL93xx +have multiple SerDes to drive the PHYs. Provide a mdio interface +to access their registers. + +Signed-off-by: Markus Stockhausen +--- +--- a/drivers/net/mdio/Makefile ++++ b/drivers/net/mdio/Makefile +@@ -22,6 +22,7 @@ obj-$(CONFIG_MDIO_OCTEON) += mdio-octeo + obj-$(CONFIG_MDIO_REGMAP) += mdio-regmap.o + obj-$(CONFIG_MDIO_REALTEK_OTTO) += mdio-realtek-otto.o + obj-$(CONFIG_MDIO_REALTEK_OTTO_AUX) += mdio-realtek-otto-aux.o ++obj-$(CONFIG_MDIO_REALTEK_OTTO_SERDES) += mdio-realtek-otto-serdes.o + obj-$(CONFIG_MDIO_SMBUS) += mdio-smbus.o + obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o + obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o +--- a/drivers/net/mdio/Kconfig ++++ b/drivers/net/mdio/Kconfig +@@ -224,6 +224,13 @@ config MDIO_REALTEK_OTTO_AUX + This driver supports the auxilairy MDIO bus on RTL838x SoCs. This bus + is typically used to attach RTL8231 GPIO extenders. + ++config MDIO_REALTEK_OTTO_SERDES ++ tristate "Realtek Otto MDIO SerDes interface support" ++ default MACH_REALTEK_RTL ++ depends on MACH_REALTEK_RTL || COMPILE_TEST ++ help ++ This driver provides MDIO access to the RTL83xx/RTL93xx SerDes. ++ + config MDIO_THUNDER + tristate "ThunderX SOCs MDIO buses" + depends on 64BIT diff --git a/target/linux/realtek/rtl838x/config-6.12 b/target/linux/realtek/rtl838x/config-6.12 index 287541feb2..d156ce1a17 100644 --- a/target/linux/realtek/rtl838x/config-6.12 +++ b/target/linux/realtek/rtl838x/config-6.12 @@ -136,6 +136,7 @@ CONFIG_MDIO_GPIO=y CONFIG_MDIO_I2C=y CONFIG_MDIO_REALTEK_OTTO=y CONFIG_MDIO_REALTEK_OTTO_AUX=y +CONFIG_MDIO_REALTEK_OTTO_SERDES=y CONFIG_MDIO_SMBUS=y CONFIG_MFD_CORE=y CONFIG_MFD_RTL8231=y diff --git a/target/linux/realtek/rtl839x/config-6.12 b/target/linux/realtek/rtl839x/config-6.12 index 51c0336710..56ae0bfe77 100644 --- a/target/linux/realtek/rtl839x/config-6.12 +++ b/target/linux/realtek/rtl839x/config-6.12 @@ -134,6 +134,7 @@ CONFIG_MDIO_DEVRES=y CONFIG_MDIO_I2C=y CONFIG_MDIO_REALTEK_OTTO=y CONFIG_MDIO_REALTEK_OTTO_AUX=y +CONFIG_MDIO_REALTEK_OTTO_SERDES=y CONFIG_MDIO_SMBUS=y CONFIG_MFD_CORE=y CONFIG_MFD_RTL8231=y diff --git a/target/linux/realtek/rtl930x/config-6.12 b/target/linux/realtek/rtl930x/config-6.12 index 82880f3a16..e160b060ac 100644 --- a/target/linux/realtek/rtl930x/config-6.12 +++ b/target/linux/realtek/rtl930x/config-6.12 @@ -118,6 +118,7 @@ CONFIG_MDIO_DEVRES=y CONFIG_MDIO_I2C=y CONFIG_MDIO_REALTEK_OTTO=y CONFIG_MDIO_REALTEK_OTTO_AUX=y +CONFIG_MDIO_REALTEK_OTTO_SERDES=y CONFIG_MDIO_SMBUS=y CONFIG_MFD_RTL8231=y CONFIG_MFD_SYSCON=y diff --git a/target/linux/realtek/rtl930x_nand/config-6.12 b/target/linux/realtek/rtl930x_nand/config-6.12 index 5ba7b2e613..075b06f362 100644 --- a/target/linux/realtek/rtl930x_nand/config-6.12 +++ b/target/linux/realtek/rtl930x_nand/config-6.12 @@ -118,6 +118,7 @@ CONFIG_MDIO_DEVRES=y CONFIG_MDIO_I2C=y CONFIG_MDIO_REALTEK_OTTO=y CONFIG_MDIO_REALTEK_OTTO_AUX=y +CONFIG_MDIO_REALTEK_OTTO_SERDES=y CONFIG_MDIO_SMBUS=y CONFIG_MFD_RTL8231=y CONFIG_MFD_SYSCON=y diff --git a/target/linux/realtek/rtl931x/config-6.12 b/target/linux/realtek/rtl931x/config-6.12 index f45a17fe7e..9c64303ec2 100644 --- a/target/linux/realtek/rtl931x/config-6.12 +++ b/target/linux/realtek/rtl931x/config-6.12 @@ -123,6 +123,7 @@ CONFIG_MDIO_DEVRES=y CONFIG_MDIO_I2C=y CONFIG_MDIO_REALTEK_OTTO=y CONFIG_MDIO_REALTEK_OTTO_AUX=y +CONFIG_MDIO_REALTEK_OTTO_SERDES=y CONFIG_MDIO_SMBUS=y CONFIG_MFD_RTL8231=y CONFIG_MFD_SYSCON=y diff --git a/target/linux/realtek/rtl931x_nand/config-6.12 b/target/linux/realtek/rtl931x_nand/config-6.12 index 5bf65a5b8b..25e8b8ff4f 100644 --- a/target/linux/realtek/rtl931x_nand/config-6.12 +++ b/target/linux/realtek/rtl931x_nand/config-6.12 @@ -123,6 +123,7 @@ CONFIG_MDIO_DEVRES=y CONFIG_MDIO_I2C=y CONFIG_MDIO_REALTEK_OTTO=y CONFIG_MDIO_REALTEK_OTTO_AUX=y +CONFIG_MDIO_REALTEK_OTTO_SERDES=y CONFIG_MDIO_SMBUS=y CONFIG_MFD_RTL8231=y CONFIG_MFD_SYSCON=y