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 = <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>
This commit is contained in:
Jonas Jelonek
2026-04-22 08:33:56 +00:00
committed by Robert Marko
parent 3271071579
commit 90c0a37ddc
7 changed files with 120 additions and 70 deletions
@@ -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";
@@ -238,17 +240,17 @@
};
&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>;
};
@@ -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";
@@ -488,50 +489,50 @@
};
&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>;
};
@@ -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";
@@ -220,29 +221,29 @@
};
&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>;
};
@@ -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";
@@ -303,42 +304,42 @@
};
&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>;
};
@@ -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";
@@ -266,37 +267,37 @@
};
&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>;
};
@@ -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 = {
@@ -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