[openwrt/openwrt] realtek: pcs: rtl930x: reconfigure PLL of neighbor SerDes when needed
LEDE Commits
lede-commits at lists.infradead.org
Fri Nov 7 03:22:48 PST 2025
robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/23c01459631b2babffd5f408624d25a5e99f40ba
commit 23c01459631b2babffd5f408624d25a5e99f40ba
Author: Jan Hoffmann <jan at 3e8.eu>
AuthorDate: Mon Oct 27 18:50:57 2025 +0100
realtek: pcs: rtl930x: reconfigure PLL of neighbor SerDes when needed
On RTL930x, each SerDes pair shares a set of PLLs with different
capabilities (LC PLL: 1G/2.5G/10G, ring PLL: 1G/2.5G). In principle,
this allows any combination of speeds on a SerDes pair. However, it
creates a special case when trying to configure a SerDes for 10G while
the LC PLL is already in use at a slower speed for the neighbor SerDes.
The current implementation just gives up in that case. Instead, free up
the LC PLL by reconfiguring the neighbor SerDes to the ring PLL.
Signed-off-by: Jan Hoffmann <jan at 3e8.eu>
Link: https://github.com/openwrt/openwrt/pull/20568
Signed-off-by: Robert Marko <robimarko at gmail.com>
---
.../files-6.12/drivers/net/pcs/pcs-rtl-otto.c | 34 ++++++++++++++++++++--
1 file changed, 31 insertions(+), 3 deletions(-)
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
index bbc0167153..d26b4aab80 100644
--- 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
@@ -410,6 +410,26 @@ static void rtpcs_930x_sds_set_power(struct rtpcs_ctrl *ctrl, int sds, bool on)
rtpcs_sds_write_bits(ctrl, sds, 0x20, 0x00, 5, 4, rx_enable);
}
+static void rtpcs_930x_sds_reconfigure_pll(struct rtpcs_ctrl *ctrl, int sds, int pll)
+{
+ int mode, tmp, speed;
+
+ mode = rtpcs_930x_sds_get_internal_mode(ctrl, sds);
+ rtpcs_930x_sds_get_pll_data(ctrl, sds, &tmp, &speed);
+
+ rtpcs_930x_sds_set_power(ctrl, sds, false);
+ rtpcs_930x_sds_set_internal_mode(ctrl, sds, RTL930X_SDS_OFF);
+
+ rtpcs_930x_sds_set_pll_data(ctrl, sds, pll, speed);
+ rtpcs_930x_sds_reset_cmu(ctrl, sds);
+
+ rtpcs_930x_sds_set_internal_mode(ctrl, sds, mode);
+ if (rtpcs_930x_sds_wait_clock_ready(ctrl, sds))
+ pr_err("%s: SDS %d could not sync clock\n", __func__, sds);
+
+ rtpcs_930x_sds_set_power(ctrl, sds, true);
+}
+
static int rtpcs_930x_sds_config_pll(struct rtpcs_ctrl *ctrl, int sds,
phy_interface_t interface)
{
@@ -429,6 +449,11 @@ static int rtpcs_930x_sds_config_pll(struct rtpcs_ctrl *ctrl, int sds,
* - Use ring PLL for slow 1G speeds
* - Use LC PLL for fast 10G speeds
* - For 2.5G prefer ring over LC PLL
+ *
+ * However, when we want to configure 10G speed while the other SerDes is already using
+ * the LC PLL for a slower speed, there is no way to avoid reconfiguration. Note that
+ * this can even happen when the other SerDes is not actually in use, because changing
+ * the state of a SerDes back to RTL930X_SDS_OFF is not (yet) implemented.
*/
neighbor_mode = rtpcs_930x_sds_get_internal_mode(ctrl, neighbor);
@@ -451,9 +476,12 @@ static int rtpcs_930x_sds_config_pll(struct rtpcs_ctrl *ctrl, int sds,
pll = neighbor_pll;
} else if (neighbor_pll == RTSDS_930X_PLL_RING)
pll = RTSDS_930X_PLL_LC;
- else if (speed == RTSDS_930X_PLL_10000)
- return -ENOTSUPP; /* caller wants 10G but only ring PLL available */
- else
+ else if (speed == RTSDS_930X_PLL_10000) {
+ pr_info("%s: SDS %d needs LC PLL, reconfigure SDS %d to use ring PLL\n",
+ __func__, sds, neighbor);
+ rtpcs_930x_sds_reconfigure_pll(ctrl, neighbor, RTSDS_930X_PLL_RING);
+ pll = RTSDS_930X_PLL_LC;
+ } else
pll = RTSDS_930X_PLL_RING;
rtpcs_930x_sds_set_pll_data(ctrl, sds, pll, speed);
More information about the lede-commits
mailing list