From fe27cce1ecb78d3f26137d44d8a20845a18af3ec Mon Sep 17 00:00:00 2001 From: Markus Stockhausen Date: Wed, 17 Sep 2025 14:22:25 -0400 Subject: [PATCH] realtek: add SerDes PCS driver Until now the the SerDes configuration is realized with helper functions scattered around the DSA and PHY driver. Give them a new home as a PCS driver. The target design is as follows: - dsa driver manages switch - pcs driver manages SerDes on high level (this commit) - mdio driver manages SerDes on low level This driver adds the high level SerDes access via PCS. It makes use of the low level mdio SerDes driver to access the registers. Remark: This initial version provides exactly all phylink_pcs_ops that are currently part of the DSA driver. So this can be swapped in one of the next commits as a drop in replacement. To make use of it something like this is needed: ... ports = of_get_child_by_name(node, "ethernet-ports"); if (!ports) return -EINVAL; for_each_available_child_of_node(ports, port) { pcs_node = of_parse_phandle(port, "pcs-handle", 0); of_property_read_u32(port, "reg", &port_nr)) { priv->pcs[port_nr] = rtpcs_create(dev, pcs_node, port_nr); } ... Signed-off-by: Markus Stockhausen Link: https://github.com/openwrt/openwrt/pull/20075 Signed-off-by: Robert Marko --- target/linux/realtek/dts/rtl838x.dtsi | 25 + target/linux/realtek/dts/rtl839x.dtsi | 49 ++ target/linux/realtek/dts/rtl930x.dtsi | 43 ++ target/linux/realtek/dts/rtl931x.dtsi | 48 ++ .../files-6.12/drivers/net/pcs/pcs-rtl-otto.c | 440 ++++++++++++++++++ .../patches-6.12/730-add-pcs-rtl-otto.patch | 37 ++ target/linux/realtek/rtl838x/config-6.12 | 1 + target/linux/realtek/rtl839x/config-6.12 | 1 + target/linux/realtek/rtl930x/config-6.12 | 1 + target/linux/realtek/rtl930x_nand/config-6.12 | 1 + target/linux/realtek/rtl931x/config-6.12 | 1 + target/linux/realtek/rtl931x_nand/config-6.12 | 1 + 12 files changed, 648 insertions(+) create mode 100644 target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c create mode 100644 target/linux/realtek/patches-6.12/730-add-pcs-rtl-otto.patch diff --git a/target/linux/realtek/dts/rtl838x.dtsi b/target/linux/realtek/dts/rtl838x.dtsi index ab81c49f8ab..6a872bcb0f8 100644 --- a/target/linux/realtek/dts/rtl838x.dtsi +++ b/target/linux/realtek/dts/rtl838x.dtsi @@ -232,6 +232,31 @@ compatible = "realtek,rtl8380-serdes-mdio", "realtek,otto-serdes-mdio"; }; + pcs { + compatible = "realtek,rtl8380-pcs", "realtek,otto-pcs"; + #address-cells = <1>; + #size-cells = <0>; + + serdes0: serdes@0 { + reg = <0>; + }; + serdes1: serdes@1 { + reg = <1>; + }; + serdes2: serdes@2 { + reg = <2>; + }; + serdes3: serdes@3 { + reg = <3>; + }; + serdes4: serdes@4 { + reg = <4>; + }; + serdes5: serdes@5 { + reg = <5>; + }; + }; + 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 6b4f4821a2b..5e92c5071dc 100644 --- a/target/linux/realtek/dts/rtl839x.dtsi +++ b/target/linux/realtek/dts/rtl839x.dtsi @@ -240,6 +240,55 @@ compatible = "realtek,rtl8392-serdes-mdio", "realtek,otto-serdes-mdio"; }; + pcs { + compatible = "realtek,rtl8392-pcs", "realtek,otto-pcs"; + #address-cells = <1>; + #size-cells = <0>; + + serdes0: serdes@0 { + reg = <0>; + }; + serdes1: serdes@1 { + reg = <1>; + }; + serdes2: serdes@2 { + reg = <2>; + }; + serdes3: serdes@3 { + reg = <3>; + }; + serdes4: serdes@4 { + reg = <4>; + }; + serdes5: serdes@5 { + reg = <5>; + }; + serdes6: serdes@6 { + reg = <6>; + }; + serdes7: serdes@7 { + reg = <7>; + }; + serdes8: serdes@8 { + reg = <8>; + }; + serdes9: serdes@9 { + reg = <9>; + }; + serdes10: serdes@10 { + reg = <10>; + }; + serdes11: serdes@11 { + reg = <11>; + }; + serdes12: serdes@12 { + reg = <12>; + }; + serdes13: serdes@13 { + reg = <13>; + }; + }; + 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 ad06cef6cdf..d3c6a2dd6c4 100644 --- a/target/linux/realtek/dts/rtl930x.dtsi +++ b/target/linux/realtek/dts/rtl930x.dtsi @@ -207,6 +207,49 @@ compatible = "realtek,rtl9301-serdes-mdio", "realtek,otto-serdes-mdio"; }; + pcs { + compatible = "realtek,rtl9301-pcs", "realtek,otto-pcs"; + #address-cells = <1>; + #size-cells = <0>; + + serdes0: serdes@0 { + reg = <0>; + }; + serdes1: serdes@1 { + reg = <1>; + }; + serdes2: serdes@2 { + reg = <2>; + }; + serdes3: serdes@3 { + reg = <3>; + }; + serdes4: serdes@4 { + reg = <4>; + }; + serdes5: serdes@5 { + reg = <5>; + }; + serdes6: serdes@6 { + reg = <6>; + }; + serdes7: serdes@7 { + reg = <7>; + }; + serdes8: serdes@8 { + reg = <8>; + }; + serdes9: serdes@9 { + reg = <9>; + }; + serdes10: serdes@10 { + reg = <10>; + }; + serdes11: serdes@11 { + reg = <11>; + }; + }; + 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 d7b789b9bb4..58121bea2eb 100644 --- a/target/linux/realtek/dts/rtl931x.dtsi +++ b/target/linux/realtek/dts/rtl931x.dtsi @@ -239,6 +239,54 @@ compatible = "realtek,rtl9311-serdes-mdio", "realtek,otto-serdes-mdio"; }; + pcs { + compatible = "realtek,rtl9311-pcs", "realtek,otto-pcs"; + #address-cells = <1>; + #size-cells = <0>; + + serdes0: serdes@0 { + reg = <0>; + }; + serdes1: serdes@1 { + reg = <1>; + }; + serdes2: serdes@2 { + reg = <2>; + }; + serdes3: serdes@3 { + reg = <3>; + }; + serdes4: serdes@4 { + reg = <4>; + }; + serdes5: serdes@5 { + reg = <5>; + }; + serdes6: serdes@6 { + reg = <6>; + }; + serdes7: serdes@7 { + reg = <7>; + }; + serdes8: serdes@8 { + reg = <8>; + }; + serdes9: serdes@9 { + reg = <9>; + }; + serdes10: serdes@10 { + reg = <10>; + }; + serdes11: serdes@11 { + reg = <11>; + }; + serdes12: serdes@12 { + reg = <12>; + }; + serdes13: serdes@13 { + reg = <13>; + }; + }; }; pinmux@1b001358 { diff --git a/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c b/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c new file mode 100644 index 00000000000..ceedf209f51 --- /dev/null +++ b/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c @@ -0,0 +1,440 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTPCS_PORT_CNT 57 + +#define RTPCS_SPEED_10 0 +#define RTPCS_SPEED_100 1 +#define RTPCS_SPEED_1000 2 +#define RTPCS_SPEED_10000_LEGACY 3 +#define RTPCS_SPEED_10000 4 +#define RTPCS_SPEED_2500 5 +#define RTPCS_SPEED_5000 6 + +#define RTPCS_838X_CPU_PORT 28 +#define RTPCS_838X_MAC_LINK_DUP_STS 0xa19c +#define RTPCS_838X_MAC_LINK_SPD_STS 0xa190 +#define RTPCS_838X_MAC_LINK_STS 0xa188 +#define RTPCS_838X_MAC_RX_PAUSE_STS 0xa1a4 +#define RTPCS_838X_MAC_TX_PAUSE_STS 0xa1a0 + +#define RTPCS_839X_CPU_PORT 52 +#define RTPCS_839X_MAC_LINK_DUP_STS 0x03b0 +#define RTPCS_839X_MAC_LINK_SPD_STS 0x03a0 +#define RTPCS_839X_MAC_LINK_STS 0x0390 +#define RTPCS_839X_MAC_RX_PAUSE_STS 0x03c0 +#define RTPCS_839X_MAC_TX_PAUSE_STS 0x03b8 + +#define RTPCS_83XX_MAC_LINK_SPD_BITS 2 + +#define RTPCS_930X_CPU_PORT 28 +#define RTPCS_930X_MAC_LINK_DUP_STS 0xcb28 +#define RTPCS_930X_MAC_LINK_SPD_STS 0xcb18 +#define RTPCS_930X_MAC_LINK_STS 0xcb10 +#define RTPCS_930X_MAC_RX_PAUSE_STS 0xcb30 +#define RTPCS_930X_MAC_TX_PAUSE_STS 0xcb2c + +#define RTPCS_931X_CPU_PORT 56 +#define RTPCS_931X_MAC_LINK_DUP_STS 0x0ef0 +#define RTPCS_931X_MAC_LINK_SPD_STS 0x0ed0 +#define RTPCS_931X_MAC_LINK_STS 0x0ec0 +#define RTPCS_931X_MAC_RX_PAUSE_STS 0x0f00 +#define RTPCS_931X_MAC_TX_PAUSE_STS 0x0ef8 + +#define RTPCS_93XX_MAC_LINK_SPD_BITS 4 + +struct rtpcs_config { + int cpu_port; + int mac_link_dup_sts; + int mac_link_spd_bits; + int mac_link_spd_sts; + int mac_link_sts; + int mac_rx_pause_sts; + int mac_tx_pause_sts; + const struct phylink_pcs_ops *pcs_ops; +}; + +struct rtpcs_ctrl { + struct device *dev; + struct regmap *map; + struct mii_bus *bus; + const struct rtpcs_config *cfg; + struct rtpcs_link *link[RTPCS_PORT_CNT]; +}; + +struct rtpcs_link { + struct rtpcs_ctrl *ctrl; + struct phylink_pcs pcs; + int sds; + int port; +}; + +static int rtpcs_sds_to_mmd(int sds_page, int sds_regnum) +{ + return (sds_page << 8) + sds_regnum; +} + +static int rtpcs_sds_read(struct rtpcs_ctrl *ctrl, int sds, int page, int regnum) +{ + int mmd_regnum = rtpcs_sds_to_mmd(page, regnum); + + return mdiobus_c45_read(ctrl->bus, sds, MDIO_MMD_VEND1, mmd_regnum); +} + +/* + * For later use, when the SerDes registers need to be written ... + * + * static int rtpcs_sds_write(struct rtpcs_ctrl *ctrl, int sds, int page, int regnum, u16 value) + * { + * int mmd_regnum = rtpcs_sds_to_mmd(page, regnum); + * + * return mdiobus_c45_write(ctrl->bus, sds, MDIO_MMD_VEND1, mmd_regnum, value); + * } + */ + +static int rtpcs_regmap_read_bits(struct rtpcs_ctrl *ctrl, int base, int bithigh, int bitlow) +{ + int offset = base + (bitlow / 32) * 4; + int bits = bithigh + 1 - bitlow; + int shift = bitlow % 32; + int value; + + regmap_read(ctrl->map, offset, &value); + value = (value >> shift) & (BIT(bits) - 1); + + return value; +} + +static struct rtpcs_link *rtpcs_phylink_pcs_to_link(struct phylink_pcs *pcs) +{ + return container_of(pcs, struct rtpcs_link, pcs); +} + +static void rtpcs_pcs_get_state(struct phylink_pcs *pcs, struct phylink_link_state *state) +{ + struct rtpcs_link *link = rtpcs_phylink_pcs_to_link(pcs); + struct rtpcs_ctrl *ctrl = link->ctrl; + int port = link->port; + int linkup, speed; + + state->link = 0; + state->speed = SPEED_UNKNOWN; + state->duplex = DUPLEX_UNKNOWN; + state->pause &= ~(MLO_PAUSE_RX | MLO_PAUSE_TX); + + /* Read MAC side link twice */ + for (int i = 0; i < 2; i++) + linkup = rtpcs_regmap_read_bits(ctrl, ctrl->cfg->mac_link_sts, port, port); + + if (!linkup) + return; + + state->link = 1; + state->duplex = rtpcs_regmap_read_bits(ctrl, ctrl->cfg->mac_link_dup_sts, port, port); + + speed = rtpcs_regmap_read_bits(ctrl, ctrl->cfg->mac_link_spd_sts, + ctrl->cfg->mac_link_spd_bits * (port + 1) - 1, + ctrl->cfg->mac_link_spd_bits * port); + switch (speed) { + case RTPCS_SPEED_10: + state->speed = SPEED_10; + break; + case RTPCS_SPEED_100: + state->speed = SPEED_100; + break; + case RTPCS_SPEED_1000: + state->speed = SPEED_1000; + break; + case RTPCS_SPEED_10000: + case RTPCS_SPEED_10000_LEGACY: + /* + * The legacy mode is ok so far with minor inconsistencies. On RTL838x this flag + * is either 500M or 2G. It might be that MAC_GLITE_STS register tells more. On + * RTL839x this is either 500M or 10G. More info might be in MAC_LINK_500M_STS. + * Without support for the 500M modes simply resolve to 10G. + */ + state->speed = SPEED_10000; + break; + case RTPCS_SPEED_2500: + state->speed = SPEED_2500; + break; + case RTPCS_SPEED_5000: + state->speed = SPEED_5000; + break; + default: + dev_err(ctrl->dev, "unknown speed %d\n", speed); + } + + if (rtpcs_regmap_read_bits(ctrl, ctrl->cfg->mac_rx_pause_sts, port, port)) + state->pause |= MLO_PAUSE_RX; + if (rtpcs_regmap_read_bits(ctrl, ctrl->cfg->mac_tx_pause_sts, port, port)) + state->pause |= MLO_PAUSE_TX; +} + +static void rtpcs_pcs_an_restart(struct phylink_pcs *pcs) +{ + struct rtpcs_link *link = rtpcs_phylink_pcs_to_link(pcs); + struct rtpcs_ctrl *ctrl = link->ctrl; + + dev_warn(ctrl->dev, "an_restart() for port %d and sds %d not yet implemented\n", + link->port, link->sds); +} + +static int rtpcs_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, + phy_interface_t interface, const unsigned long *advertising, + bool permit_pause_to_mac) +{ + struct rtpcs_link *link = rtpcs_phylink_pcs_to_link(pcs); + struct rtpcs_ctrl *ctrl = link->ctrl; + + /* + * TODO: This (or copies of this) will be the central function for configuring the + * link between PHY and SerDes. As of now a lot of the code is scattered throughout + * all the other Realtek drivers. Maybe some day this will live up to the expectations. + */ + + dev_warn(ctrl->dev, "pcs_config(%s) for port %d and sds %d not yet implemented\n", + phy_modes(interface), link->port, link->sds); + + return 0; +} + +struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int port); +struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int port) +{ + struct platform_device *pdev; + struct device_node *pcs_np; + struct rtpcs_ctrl *ctrl; + struct rtpcs_link *link; + int sds; + + /* + * RTL838x devices have a built-in octa port RTL8218B PHY that is not attached via + * a SerDes. Allow to be called with an empty SerDes device node. In this case lookup + * the parent/driver node directly. + */ + if (np) { + if (!of_device_is_available(np)) + return ERR_PTR(-ENODEV); + + if (of_property_read_u32(np, "reg", &sds)) + return ERR_PTR(-EINVAL); + + pcs_np = of_get_parent(np); + } else { + pcs_np = of_find_compatible_node(NULL, NULL, "realtek,otto-pcs"); + sds = -1; + } + + if (!pcs_np) + return ERR_PTR(-ENODEV); + + if (!of_device_is_available(pcs_np)) { + of_node_put(pcs_np); + return ERR_PTR(-ENODEV); + } + + pdev = of_find_device_by_node(pcs_np); + of_node_put(pcs_np); + if (!pdev) + return ERR_PTR(-EPROBE_DEFER); + + ctrl = platform_get_drvdata(pdev); + if (!ctrl) { + put_device(&pdev->dev); + return ERR_PTR(-EPROBE_DEFER); + } + + if (port < 0 || port > ctrl->cfg->cpu_port) + return ERR_PTR(-EINVAL); + + if (sds !=-1 && rtpcs_sds_read(ctrl, sds, 0 , 0) < 0) + return ERR_PTR(-EINVAL); + + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (!link) { + put_device(&pdev->dev); + return ERR_PTR(-ENOMEM); + } + + device_link_add(dev, ctrl->dev, DL_FLAG_AUTOREMOVE_CONSUMER); + + link->ctrl = ctrl; + link->port = port; + link->sds = sds; + link->pcs.ops = ctrl->cfg->pcs_ops; + + ctrl->link[port] = link; + + dev_dbg(ctrl->dev, "phylink_pcs created, port %d, sds %d\n", port, sds); + + return &link->pcs; +} +EXPORT_SYMBOL(rtpcs_create); + +static struct mii_bus *rtpcs_probe_serdes_bus(struct rtpcs_ctrl *ctrl) +{ + struct device_node *np; + struct mii_bus *bus; + + np = of_find_compatible_node(NULL, NULL, "realtek,otto-serdes-mdio"); + if (!np) { + dev_err(ctrl->dev, "SerDes mdio bus not found in DT"); + return ERR_PTR(-ENODEV); + } + + bus = of_mdio_find_bus(np); + of_node_put(np); + if (!bus) { + dev_warn(ctrl->dev, "SerDes mdio bus not (yet) active"); + return ERR_PTR(-EPROBE_DEFER); + } + + if (!of_device_is_available(np)) { + dev_err(ctrl->dev, "SerDes mdio bus not usable"); + return ERR_PTR(-ENODEV); + } + + return bus; +} + +static int rtpcs_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct rtpcs_ctrl *ctrl; + + ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); + if (!ctrl) + return -ENOMEM; + + ctrl->dev = dev; + ctrl->cfg = (const struct rtpcs_config *)device_get_match_data(ctrl->dev); + ctrl->map = syscon_node_to_regmap(np->parent); + if (IS_ERR(ctrl->map)) + return PTR_ERR(ctrl->map); + + ctrl->bus = rtpcs_probe_serdes_bus(ctrl); + if (IS_ERR(ctrl->bus)) + return PTR_ERR(ctrl->bus); + /* + * rtpcs_create() relies on that fact that data is attached to the platform device to + * determine if the driver is ready. Do this after everything is initialized properly. + */ + platform_set_drvdata(pdev, ctrl); + + dev_info(dev, "Realtek PCS driver initialized\n"); + + return 0; +} + +static const struct phylink_pcs_ops rtpcs_838x_pcs_ops = { + .pcs_an_restart = rtpcs_pcs_an_restart, + .pcs_config = rtpcs_pcs_config, + .pcs_get_state = rtpcs_pcs_get_state, +}; + +static const struct rtpcs_config rtpcs_838x_cfg = { + .cpu_port = RTPCS_838X_CPU_PORT, + .mac_link_dup_sts = RTPCS_838X_MAC_LINK_DUP_STS, + .mac_link_spd_sts = RTPCS_838X_MAC_LINK_SPD_STS, + .mac_link_spd_bits = RTPCS_83XX_MAC_LINK_SPD_BITS, + .mac_link_sts = RTPCS_838X_MAC_LINK_STS, + .mac_rx_pause_sts = RTPCS_838X_MAC_RX_PAUSE_STS, + .mac_tx_pause_sts = RTPCS_838X_MAC_TX_PAUSE_STS, + .pcs_ops = &rtpcs_838x_pcs_ops, +}; + +static const struct phylink_pcs_ops rtpcs_839x_pcs_ops = { + .pcs_an_restart = rtpcs_pcs_an_restart, + .pcs_config = rtpcs_pcs_config, + .pcs_get_state = rtpcs_pcs_get_state, +}; + +static const struct rtpcs_config rtpcs_839x_cfg = { + .cpu_port = RTPCS_839X_CPU_PORT, + .mac_link_dup_sts = RTPCS_839X_MAC_LINK_DUP_STS, + .mac_link_spd_sts = RTPCS_839X_MAC_LINK_SPD_STS, + .mac_link_spd_bits = RTPCS_83XX_MAC_LINK_SPD_BITS, + .mac_link_sts = RTPCS_839X_MAC_LINK_STS, + .mac_rx_pause_sts = RTPCS_839X_MAC_RX_PAUSE_STS, + .mac_tx_pause_sts = RTPCS_839X_MAC_TX_PAUSE_STS, + .pcs_ops = &rtpcs_839x_pcs_ops, +}; + +static const struct phylink_pcs_ops rtpcs_930x_pcs_ops = { + .pcs_an_restart = rtpcs_pcs_an_restart, + .pcs_config = rtpcs_pcs_config, + .pcs_get_state = rtpcs_pcs_get_state, +}; + +static const struct rtpcs_config rtpcs_930x_cfg = { + .cpu_port = RTPCS_930X_CPU_PORT, + .mac_link_dup_sts = RTPCS_930X_MAC_LINK_DUP_STS, + .mac_link_spd_sts = RTPCS_930X_MAC_LINK_SPD_STS, + .mac_link_spd_bits = RTPCS_93XX_MAC_LINK_SPD_BITS, + .mac_link_sts = RTPCS_930X_MAC_LINK_STS, + .mac_rx_pause_sts = RTPCS_930X_MAC_RX_PAUSE_STS, + .mac_tx_pause_sts = RTPCS_930X_MAC_TX_PAUSE_STS, + .pcs_ops = &rtpcs_930x_pcs_ops, +}; + +static const struct phylink_pcs_ops rtpcs_931x_pcs_ops = { + .pcs_an_restart = rtpcs_pcs_an_restart, + .pcs_config = rtpcs_pcs_config, + .pcs_get_state = rtpcs_pcs_get_state, +}; + +static const struct rtpcs_config rtpcs_931x_cfg = { + .cpu_port = RTPCS_931X_CPU_PORT, + .mac_link_dup_sts = RTPCS_931X_MAC_LINK_DUP_STS, + .mac_link_spd_sts = RTPCS_931X_MAC_LINK_SPD_STS, + .mac_link_spd_bits = RTPCS_93XX_MAC_LINK_SPD_BITS, + .mac_link_sts = RTPCS_931X_MAC_LINK_STS, + .mac_rx_pause_sts = RTPCS_931X_MAC_RX_PAUSE_STS, + .mac_tx_pause_sts = RTPCS_931X_MAC_TX_PAUSE_STS, + .pcs_ops = &rtpcs_931x_pcs_ops, +}; + +static const struct of_device_id rtpcs_of_match[] = { + { + .compatible = "realtek,rtl8380-pcs", + .data = &rtpcs_838x_cfg, + }, + { + .compatible = "realtek,rtl8392-pcs", + .data = &rtpcs_839x_cfg, + }, + { + .compatible = "realtek,rtl9301-pcs", + .data = &rtpcs_930x_cfg, + }, + { + .compatible = "realtek,rtl9311-pcs", + .data = &rtpcs_931x_cfg, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rtpcs_of_match); + +static struct platform_driver rtpcs_driver = { + .driver = { + .name = "realtek-otto-pcs", + .of_match_table = rtpcs_of_match + }, + .probe = rtpcs_probe, +}; +module_platform_driver(rtpcs_driver); + +MODULE_AUTHOR("Markus Stockhausen "); +MODULE_DESCRIPTION("Realtek Otto SerDes PCS driver"); +MODULE_LICENSE("GPL v2"); \ No newline at end of file diff --git a/target/linux/realtek/patches-6.12/730-add-pcs-rtl-otto.patch b/target/linux/realtek/patches-6.12/730-add-pcs-rtl-otto.patch new file mode 100644 index 00000000000..27927bd8919 --- /dev/null +++ b/target/linux/realtek/patches-6.12/730-add-pcs-rtl-otto.patch @@ -0,0 +1,37 @@ +From ad75da9aaa8765b2115e7b40ee4f6dbcd60c3321 Mon Sep 17 00:00:00 2001 +From: Markus Stockhausen +Date: Weg, 17 Sep 2025 20:23:31 +0200 +Subject: [PATCH] net: pcs: 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 PCS driver +to configure them. + +Signed-off-by: Markus Stockhausen +--- +--- a/drivers/net/pcs/Kconfig ++++ b/drivers/net/pcs/Kconfig +@@ -36,6 +36,14 @@ config PCS_MTK_USXGMII + 1000Base-X, 2500Base-X and Cisco SGMII are supported on the same + differential pairs via an embedded LynxI PHY. + ++config PCS_RTL_OTTO ++ tristate "Realtek Otto SerDes PCS" ++ depends on MACH_REALTEK_RTL || COMPILE_TEST ++ select PHYLINK ++ select REGMAP ++ help ++ This module provides a driver for the Realtek SerDes PCS ++ + config PCS_RZN1_MIIC + tristate "Renesas RZ/N1 MII converter" + depends on OF && (ARCH_RZN1 || COMPILE_TEST) +--- a/drivers/net/pcs/Makefile ++++ b/drivers/net/pcs/Makefile +@@ -7,5 +7,6 @@ pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs. + obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o + obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o + obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o ++obj-$(CONFIG_PCS_RTL_OTTO) += pcs-rtl-otto.o + obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o + obj-$(CONFIG_PCS_MTK_USXGMII) += pcs-mtk-usxgmii.o diff --git a/target/linux/realtek/rtl838x/config-6.12 b/target/linux/realtek/rtl838x/config-6.12 index d156ce1a175..8afd239b3b2 100644 --- a/target/linux/realtek/rtl838x/config-6.12 +++ b/target/linux/realtek/rtl838x/config-6.12 @@ -193,6 +193,7 @@ CONFIG_PAGE_POOL=y CONFIG_PAGE_SIZE_LESS_THAN_256KB=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y CONFIG_PCI_DRIVERS_LEGACY=y +CONFIG_PCS_RTL_OTTO=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y diff --git a/target/linux/realtek/rtl839x/config-6.12 b/target/linux/realtek/rtl839x/config-6.12 index 56ae0bfe77f..022cafea463 100644 --- a/target/linux/realtek/rtl839x/config-6.12 +++ b/target/linux/realtek/rtl839x/config-6.12 @@ -199,6 +199,7 @@ CONFIG_PAGE_POOL=y CONFIG_PAGE_SIZE_LESS_THAN_256KB=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y CONFIG_PCI_DRIVERS_LEGACY=y +CONFIG_PCS_RTL_OTTO=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y diff --git a/target/linux/realtek/rtl930x/config-6.12 b/target/linux/realtek/rtl930x/config-6.12 index e160b060ac0..5b3b4260190 100644 --- a/target/linux/realtek/rtl930x/config-6.12 +++ b/target/linux/realtek/rtl930x/config-6.12 @@ -182,6 +182,7 @@ CONFIG_PAGE_POOL=y CONFIG_PAGE_SIZE_LESS_THAN_256KB=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y CONFIG_PCI_DRIVERS_LEGACY=y +CONFIG_PCS_RTL_OTTO=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y diff --git a/target/linux/realtek/rtl930x_nand/config-6.12 b/target/linux/realtek/rtl930x_nand/config-6.12 index 075b06f3626..c4a2806421d 100644 --- a/target/linux/realtek/rtl930x_nand/config-6.12 +++ b/target/linux/realtek/rtl930x_nand/config-6.12 @@ -185,6 +185,7 @@ CONFIG_PAGE_POOL=y CONFIG_PAGE_SIZE_LESS_THAN_256KB=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y CONFIG_PCI_DRIVERS_LEGACY=y +CONFIG_PCS_RTL_OTTO=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y diff --git a/target/linux/realtek/rtl931x/config-6.12 b/target/linux/realtek/rtl931x/config-6.12 index 9c64303ec2e..ee51cdb2566 100644 --- a/target/linux/realtek/rtl931x/config-6.12 +++ b/target/linux/realtek/rtl931x/config-6.12 @@ -193,6 +193,7 @@ CONFIG_PAGE_POOL=y CONFIG_PAGE_SIZE_LESS_THAN_256KB=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y CONFIG_PCI_DRIVERS_LEGACY=y +CONFIG_PCS_RTL_OTTO=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y diff --git a/target/linux/realtek/rtl931x_nand/config-6.12 b/target/linux/realtek/rtl931x_nand/config-6.12 index 25e8b8ff4fc..529739d7acb 100644 --- a/target/linux/realtek/rtl931x_nand/config-6.12 +++ b/target/linux/realtek/rtl931x_nand/config-6.12 @@ -197,6 +197,7 @@ CONFIG_PAGE_POOL=y CONFIG_PAGE_SIZE_LESS_THAN_256KB=y CONFIG_PAGE_SIZE_LESS_THAN_64KB=y CONFIG_PCI_DRIVERS_LEGACY=y +CONFIG_PCS_RTL_OTTO=y CONFIG_PERF_USE_VMALLOC=y CONFIG_PGTABLE_LEVELS=2 CONFIG_PHYLIB=y -- 2.47.3