]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: switch SerDes polarity to {rx,tx}-polarity 23044/head
authorJonas Jelonek <jelonek.jonas@gmail.com>
Wed, 22 Apr 2026 08:33:56 +0000 (08:33 +0000)
committerRobert Marko <robimarko@gmail.com>
Fri, 24 Apr 2026 08:13:38 +0000 (10:13 +0200)
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 = <PHY_POL_INVERT>` 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 <jelonek.jonas@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/23044
Signed-off-by: Robert Marko <robimarko@gmail.com>
target/linux/realtek/dts/rtl9311_linksys_lgs352c.dts
target/linux/realtek/dts/rtl9313_xikestor_sks8300-12x-v1.dts
target/linux/realtek/dts/rtl9313_zyxel_xs1930-10.dts
target/linux/realtek/dts/rtl9313_zyxel_xs1930-12f.dts
target/linux/realtek/dts/rtl9313_zyxel_xs1930-12hp.dts
target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c
target/linux/realtek/patches-6.18/730-add-pcs-rtl-otto.patch

index 7e039e0582d2d79083be6aa11f628923e29bc790..f7e3e21f19a6942109908fd1f0a98a2f79b65b68 100644 (file)
@@ -4,6 +4,8 @@
 #include "rtl931x.dtsi"
 #include "rtl93xx_linksys_lgs3xxc_nand_common.dtsi"
 
+#include <dt-bindings/phy/phy.h>
+
 / {
        compatible = "linksys,lgs352c", "realtek,rtl9311-soc";
        model = "Linksys LGS352C";
 };
 
 &serdes8 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes9 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes10 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes11 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
index abe2e672978527bf54eac5f710770e658b302adb..d3b46c73d8cd3b645ae6845a814c54a8dffcd77a 100644 (file)
@@ -5,6 +5,7 @@
 #include <dt-bindings/input/input.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/leds/common.h>
+#include <dt-bindings/phy/phy.h>
 
 / {
        compatible = "xikestor,sks8300-12x-v1", "realtek,rtl9313-soc";
 };
 
 &serdes2 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes3 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes4 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes5 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes6 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes7 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes8 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes9 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes10 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes11 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes12 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes13 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
index 1f560bd03c1185e382f1068d5a8261526663cfe3..69a4b1e492d7d3f8ccda8eab2701aeb29fbe7219 100644 (file)
@@ -7,6 +7,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/mux/mux.h>
+#include <dt-bindings/phy/phy.h>
 
 / {
        compatible = "zyxel,xs1930-10", "realtek,rtl9313-soc";
 };
 
 &serdes6 {
-       realtek,pnswap-rx;
-       realtek,pnswap-tx;
+       rx-polarity = <PHY_POL_INVERT>;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes7 {
-       realtek,pnswap-rx;
-       realtek,pnswap-tx;
+       rx-polarity = <PHY_POL_INVERT>;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes8 {
-       realtek,pnswap-rx;
-       realtek,pnswap-tx;
+       rx-polarity = <PHY_POL_INVERT>;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes9 {
-       realtek,pnswap-rx;
-       realtek,pnswap-tx;
+       rx-polarity = <PHY_POL_INVERT>;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes12 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes13 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
index 1c5989f7e8196b40d70387556641724fe62c45d4..2a5afafb054a80e5ccd21a6284c7dbf383d8aaf9 100644 (file)
@@ -7,6 +7,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/mux/mux.h>
+#include <dt-bindings/phy/phy.h>
 
 / {
        compatible = "zyxel,xs1930-12f", "realtek,rtl9313-soc";
 };
 
 &serdes2 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes3 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes4 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes5 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes6 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes7 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes8 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes9 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes10 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes11 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
index 1eab2398ea4181c680cb72af8f1d7d608adef0f9..5ce41110de20ac26774bd07bfb3af30b4e513c01 100644 (file)
@@ -7,6 +7,7 @@
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/leds/common.h>
 #include <dt-bindings/mux/mux.h>
+#include <dt-bindings/phy/phy.h>
 
 / {
        compatible = "zyxel,xs1930-12hp", "realtek,rtl9313-soc";
 };
 
 &serdes6 {
-       realtek,pnswap-rx;
-       realtek,pnswap-tx;
+       rx-polarity = <PHY_POL_INVERT>;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes7 {
-       realtek,pnswap-rx;
-       realtek,pnswap-tx;
+       rx-polarity = <PHY_POL_INVERT>;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes8 {
-       realtek,pnswap-rx;
-       realtek,pnswap-tx;
+       rx-polarity = <PHY_POL_INVERT>;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes9 {
-       realtek,pnswap-rx;
-       realtek,pnswap-tx;
+       rx-polarity = <PHY_POL_INVERT>;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes10 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes11 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes12 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
 
 &serdes13 {
-       realtek,pnswap-tx;
+       tx-polarity = <PHY_POL_INVERT>;
 };
index c8429b45961be0bad24e8245ba7ec0620fddf486..2c6fa8bf2c8134a76da6c5cd5830d3d93810fddc 100644 (file)
@@ -6,8 +6,9 @@
 #include <linux/of_mdio.h>
 #include <linux/of_platform.h>
 #include <linux/phy.h>
-#include <linux/platform_device.h>
+#include <linux/phy/phy-common-props.h>
 #include <linux/phylink.h>
+#include <linux/platform_device.h>
 #include <linux/regmap.h>
 
 #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 = {
index 6fee82688478f885ae04bf8798c49ff0b9c9e217..dc242c495da3b9871fab93761b39b99cd3d18d76 100644 (file)
@@ -11,13 +11,14 @@ Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
 ---
 --- 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