From 90c0a37ddce63a27abbcea7191811ca2194c0a86 Mon Sep 17 00:00:00 2001 From: Jonas Jelonek Date: Wed, 22 Apr 2026 08:33:56 +0000 Subject: [PATCH] realtek: pcs: switch SerDes polarity to {rx,tx}-polarity With the recent backport of the common PHY properties infrastructure (phy-common-props and the phy_get_manual_{rx,tx}_polarity() helpers) to OpenWrt, the generic `{rx,tx}-polarity` device tree properties are now usable for the Realtek PCS driver. Switch the driver and all affected boards from the local vendor-specific `realtek,pnswap-{rx,tx}` booleans to the common properties. Add a `config_polarity` SerDes op (implemented by RTL930x and RTL931x; RTL838x/RTL839x polarity support not yet added) and a generic wrapper that resolves the requested polarity via phy_get_manual_{rx,tx}_polarity() and dispatches to the op. Variants without the op silently accept the default polarity but warn when a non-default polarity is requested, since that cannot be honored. Move the polarity programming out of the variant setup_serdes callbacks into rtpcs_pcs_config, so it runs before setup_serdes. This matches the ordering used by the vendor SDK, which configures polarity first. Update all board DTS files that previously used `realtek,pnswap-{rx,tx}` to the new `{rx,tx}-polarity = ` property, and select PHY_COMMON_PROPS from Kconfig. Each SerDes now retains its DT node for later polarity lookup. Use for_each_child_of_node_scoped for the iterator, and register a devm_add_action_or_reset for each stored reference so it is released on unbind or probe failure. Signed-off-by: Jonas Jelonek Link: https://github.com/openwrt/openwrt/pull/23044 Signed-off-by: Robert Marko --- .../realtek/dts/rtl9311_linksys_lgs352c.dts | 10 ++- .../dts/rtl9313_xikestor_sks8300-12x-v1.dts | 25 +++--- .../realtek/dts/rtl9313_zyxel_xs1930-10.dts | 21 ++--- .../realtek/dts/rtl9313_zyxel_xs1930-12f.dts | 21 ++--- .../realtek/dts/rtl9313_zyxel_xs1930-12hp.dts | 25 +++--- .../files-6.18/drivers/net/pcs/pcs-rtl-otto.c | 85 ++++++++++++++----- .../patches-6.18/730-add-pcs-rtl-otto.patch | 3 +- 7 files changed, 120 insertions(+), 70 deletions(-) diff --git a/target/linux/realtek/dts/rtl9311_linksys_lgs352c.dts b/target/linux/realtek/dts/rtl9311_linksys_lgs352c.dts index 7e039e0582d..f7e3e21f19a 100644 --- a/target/linux/realtek/dts/rtl9311_linksys_lgs352c.dts +++ b/target/linux/realtek/dts/rtl9311_linksys_lgs352c.dts @@ -4,6 +4,8 @@ #include "rtl931x.dtsi" #include "rtl93xx_linksys_lgs3xxc_nand_common.dtsi" +#include + / { compatible = "linksys,lgs352c", "realtek,rtl9311-soc"; model = "Linksys LGS352C"; @@ -238,17 +240,17 @@ }; &serdes8 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes9 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes10 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes11 { - realtek,pnswap-tx; + tx-polarity = ; }; diff --git a/target/linux/realtek/dts/rtl9313_xikestor_sks8300-12x-v1.dts b/target/linux/realtek/dts/rtl9313_xikestor_sks8300-12x-v1.dts index abe2e672978..d3b46c73d8c 100644 --- a/target/linux/realtek/dts/rtl9313_xikestor_sks8300-12x-v1.dts +++ b/target/linux/realtek/dts/rtl9313_xikestor_sks8300-12x-v1.dts @@ -5,6 +5,7 @@ #include #include #include +#include / { compatible = "xikestor,sks8300-12x-v1", "realtek,rtl9313-soc"; @@ -488,50 +489,50 @@ }; &serdes2 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes3 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes4 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes5 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes6 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes7 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes8 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes9 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes10 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes11 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes12 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes13 { - realtek,pnswap-tx; + tx-polarity = ; }; diff --git a/target/linux/realtek/dts/rtl9313_zyxel_xs1930-10.dts b/target/linux/realtek/dts/rtl9313_zyxel_xs1930-10.dts index 1f560bd03c1..69a4b1e492d 100644 --- a/target/linux/realtek/dts/rtl9313_zyxel_xs1930-10.dts +++ b/target/linux/realtek/dts/rtl9313_zyxel_xs1930-10.dts @@ -7,6 +7,7 @@ #include #include #include +#include / { compatible = "zyxel,xs1930-10", "realtek,rtl9313-soc"; @@ -220,29 +221,29 @@ }; &serdes6 { - realtek,pnswap-rx; - realtek,pnswap-tx; + rx-polarity = ; + tx-polarity = ; }; &serdes7 { - realtek,pnswap-rx; - realtek,pnswap-tx; + rx-polarity = ; + tx-polarity = ; }; &serdes8 { - realtek,pnswap-rx; - realtek,pnswap-tx; + rx-polarity = ; + tx-polarity = ; }; &serdes9 { - realtek,pnswap-rx; - realtek,pnswap-tx; + rx-polarity = ; + tx-polarity = ; }; &serdes12 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes13 { - realtek,pnswap-tx; + tx-polarity = ; }; diff --git a/target/linux/realtek/dts/rtl9313_zyxel_xs1930-12f.dts b/target/linux/realtek/dts/rtl9313_zyxel_xs1930-12f.dts index 1c5989f7e81..2a5afafb054 100644 --- a/target/linux/realtek/dts/rtl9313_zyxel_xs1930-12f.dts +++ b/target/linux/realtek/dts/rtl9313_zyxel_xs1930-12f.dts @@ -7,6 +7,7 @@ #include #include #include +#include / { compatible = "zyxel,xs1930-12f", "realtek,rtl9313-soc"; @@ -303,42 +304,42 @@ }; &serdes2 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes3 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes4 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes5 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes6 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes7 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes8 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes9 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes10 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes11 { - realtek,pnswap-tx; + tx-polarity = ; }; diff --git a/target/linux/realtek/dts/rtl9313_zyxel_xs1930-12hp.dts b/target/linux/realtek/dts/rtl9313_zyxel_xs1930-12hp.dts index 1eab2398ea4..5ce41110de2 100644 --- a/target/linux/realtek/dts/rtl9313_zyxel_xs1930-12hp.dts +++ b/target/linux/realtek/dts/rtl9313_zyxel_xs1930-12hp.dts @@ -7,6 +7,7 @@ #include #include #include +#include / { compatible = "zyxel,xs1930-12hp", "realtek,rtl9313-soc"; @@ -266,37 +267,37 @@ }; &serdes6 { - realtek,pnswap-rx; - realtek,pnswap-tx; + rx-polarity = ; + tx-polarity = ; }; &serdes7 { - realtek,pnswap-rx; - realtek,pnswap-tx; + rx-polarity = ; + tx-polarity = ; }; &serdes8 { - realtek,pnswap-rx; - realtek,pnswap-tx; + rx-polarity = ; + tx-polarity = ; }; &serdes9 { - realtek,pnswap-rx; - realtek,pnswap-tx; + rx-polarity = ; + tx-polarity = ; }; &serdes10 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes11 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes12 { - realtek,pnswap-tx; + tx-polarity = ; }; &serdes13 { - realtek,pnswap-tx; + tx-polarity = ; }; diff --git a/target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c b/target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c index c8429b45961..2c6fa8bf2c8 100644 --- a/target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c +++ b/target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c @@ -6,8 +6,9 @@ #include #include #include -#include +#include #include +#include #include #define RTPCS_SDS_CNT 14 @@ -188,6 +189,9 @@ struct rtpcs_sds_ops { int (*reset_cmu)(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll); /* online reconfiguration of a running SerDes to another PLL */ int (*reconfigure_to_pll)(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll); + + int (*config_polarity)(struct rtpcs_serdes *sds, unsigned int tx_pol, + unsigned int rx_pol); }; struct rtpcs_sds_reg_field { @@ -205,6 +209,7 @@ struct rtpcs_sds_regs { struct rtpcs_serdes { struct rtpcs_ctrl *ctrl; + struct device_node *of_node; const struct rtpcs_sds_ops *ops; const struct rtpcs_sds_regs *regs; enum rtpcs_sds_type type; @@ -212,9 +217,6 @@ struct rtpcs_serdes { u8 id; u8 num_of_links; bool first_start; - - bool rx_pol_inv; - bool tx_pol_inv; }; struct rtpcs_ctrl { @@ -2768,11 +2770,11 @@ static int rtpcs_930x_sds_10g_idle(struct rtpcs_serdes *sds) return -ETIMEDOUT; } -static int rtpcs_930x_sds_set_polarity(struct rtpcs_serdes *sds, - bool tx_inv, bool rx_inv) +static int rtpcs_930x_sds_config_polarity(struct rtpcs_serdes *sds, unsigned int tx_pol, + unsigned int rx_pol) { - u8 rx_val = rx_inv ? 1 : 0; - u8 tx_val = tx_inv ? 1 : 0; + u8 rx_val = (rx_pol == PHY_POL_INVERT) ? 1 : 0; + u8 tx_val = (tx_pol == PHY_POL_INVERT) ? 1 : 0; u32 val; int ret; @@ -3014,9 +3016,6 @@ static int rtpcs_930x_setup_serdes(struct rtpcs_serdes *sds, /* dal_longan_construct_serdesConfig_init */ /* Serdes Construct */ rtpcs_930x_phy_enable_10g_1g(sds); - /* Set SDS polarity */ - rtpcs_930x_sds_set_polarity(sds, sds->tx_pol_inv, sds->rx_pol_inv); - /* Enable SDS in desired mode */ ret = rtpcs_930x_sds_set_mode(sds, hw_mode); if (ret < 0) @@ -3526,11 +3525,11 @@ static int rtpcs_931x_sds_link_sts_get(struct rtpcs_serdes *sds) return sts1; } -static int rtpcs_931x_sds_set_polarity(struct rtpcs_serdes *sds, - bool tx_inv, bool rx_inv) +static int rtpcs_931x_sds_config_polarity(struct rtpcs_serdes *sds, unsigned int tx_pol, + unsigned int rx_pol) { - u8 rx_val = rx_inv ? 1 : 0; - u8 tx_val = tx_inv ? 1 : 0; + u8 rx_val = (rx_pol == PHY_POL_INVERT) ? 1 : 0; + u8 tx_val = (tx_pol == PHY_POL_INVERT) ? 1 : 0; u32 val; int ret; @@ -3901,8 +3900,6 @@ static int rtpcs_931x_setup_serdes(struct rtpcs_serdes *sds, return ret; } - rtpcs_931x_sds_set_polarity(sds, sds->tx_pol_inv, sds->rx_pol_inv); - rtpcs_931x_sds_power(sds, true); ret = rtpcs_931x_sds_set_mode(sds, hw_mode); @@ -3971,6 +3968,34 @@ static int rtpcs_931x_init(struct rtpcs_ctrl *ctrl) /* Common functions */ +static int rtpcs_sds_config_polarity(struct rtpcs_serdes *sds, phy_interface_t if_mode) +{ + unsigned int rx_pol, tx_pol; + int ret; + + if (!sds->of_node) + return 0; + + ret = phy_get_manual_rx_polarity(of_fwnode_handle(sds->of_node), phy_modes(if_mode), + &rx_pol); + if (ret < 0) + return ret; + + ret = phy_get_manual_tx_polarity(of_fwnode_handle(sds->of_node), phy_modes(if_mode), + &tx_pol); + if (ret < 0) + return ret; + + if (!sds->ops->config_polarity) { + if (tx_pol != PHY_POL_NORMAL || rx_pol != PHY_POL_NORMAL) + dev_warn(sds->ctrl->dev, + "Polarity change requested but not supported\n"); + return 0; + } + + return sds->ops->config_polarity(sds, tx_pol, rx_pol); +} + static void rtpcs_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode, struct phylink_link_state *state) { @@ -4067,6 +4092,13 @@ static int rtpcs_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, dev_info(ctrl->dev, "configure SerDes %u for mode %s\n", sds->id, phy_modes(interface)); + ret = rtpcs_sds_config_polarity(sds, interface); + if (ret < 0) { + dev_err(ctrl->dev, "failed to configure polarity of SerDes %u\n", + sds->id); + goto out; + } + ret = ctrl->cfg->setup_serdes(sds, hw_mode); if (ret < 0) goto out; @@ -4179,11 +4211,17 @@ static struct mii_bus *rtpcs_probe_serdes_bus(struct rtpcs_ctrl *ctrl) return bus; } +static void rtpcs_sds_put_of_node(void *data) +{ + struct rtpcs_serdes *sds = data; + + of_node_put(sds->of_node); +} + static int rtpcs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - struct device_node *child; struct rtpcs_serdes *sds; struct rtpcs_ctrl *ctrl; u32 sds_id; @@ -4219,16 +4257,19 @@ static int rtpcs_probe(struct platform_device *pdev) return ret; } - for_each_child_of_node(dev->of_node, child) { + for_each_child_of_node_scoped(dev->of_node, child) { ret = of_property_read_u32(child, "reg", &sds_id); if (ret) return ret; + if (sds_id >= ctrl->cfg->serdes_count) return -EINVAL; sds = &ctrl->serdes[sds_id]; - sds->rx_pol_inv = of_property_read_bool(child, "realtek,pnswap-rx"); - sds->tx_pol_inv = of_property_read_bool(child, "realtek,pnswap-tx"); + sds->of_node = of_node_get(child); + ret = devm_add_action_or_reset(dev, rtpcs_sds_put_of_node, sds); + if (ret) + return ret; } if (ctrl->cfg->init) { @@ -4336,6 +4377,7 @@ static const struct rtpcs_sds_ops rtpcs_930x_sds_ops = { .set_pll_select = rtpcs_930x_sds_set_pll_select, .reset_cmu = rtpcs_930x_sds_reset_cmu, .reconfigure_to_pll = rtpcs_930x_sds_reconfigure_to_pll, + .config_polarity = rtpcs_930x_sds_config_polarity, }; static const struct rtpcs_sds_regs rtpcs_930x_sds_regs = { @@ -4376,6 +4418,7 @@ static const struct rtpcs_sds_ops rtpcs_931x_sds_ops = { .get_pll_select = rtpcs_931x_sds_get_pll_select, .set_pll_select = rtpcs_931x_sds_set_pll_select, .reconfigure_to_pll = rtpcs_931x_sds_reconfigure_to_pll, + .config_polarity = rtpcs_931x_sds_config_polarity, }; static const struct rtpcs_sds_regs rtpcs_931x_sds_regs = { diff --git a/target/linux/realtek/patches-6.18/730-add-pcs-rtl-otto.patch b/target/linux/realtek/patches-6.18/730-add-pcs-rtl-otto.patch index 6fee8268847..dc242c495da 100644 --- a/target/linux/realtek/patches-6.18/730-add-pcs-rtl-otto.patch +++ b/target/linux/realtek/patches-6.18/730-add-pcs-rtl-otto.patch @@ -11,13 +11,14 @@ Signed-off-by: Markus Stockhausen --- --- a/drivers/net/pcs/Kconfig +++ b/drivers/net/pcs/Kconfig -@@ -45,6 +45,14 @@ config PCS_MTK_USXGMII +@@ -45,6 +45,15 @@ config PCS_MTK_USXGMII 1000Base-X, 2500Base-X and Cisco SGMII are supported on the same differential pairs via an embedded LynxI PCS. +config PCS_RTL_OTTO + tristate "Realtek Otto SerDes PCS" + depends on MACH_REALTEK_RTL || COMPILE_TEST ++ select PHY_COMMON_PROPS + select PHYLINK + select REGMAP + help -- 2.47.3