]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: rtl930x: split pll config
authorJonas Jelonek <jelonek.jonas@gmail.com>
Tue, 24 Feb 2026 00:14:12 +0000 (00:14 +0000)
committerHauke Mehrtens <hauke@hauke-m.de>
Sat, 14 Mar 2026 19:24:32 +0000 (20:24 +0100)
Split up PLL configuration of RTL930x in the two distinct actions of
configuring the PLL itself (aka setting its speed, etc.) and selecting
which PLL is used by a SerDes.

It was found that for both RTL930x and RTL931x, PLL configuration can be
combined while selecting the PLL a SerDes uses differs and needs to be
implemented variant-specific.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/22198
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c

index f3796c984a74e7bb646ab6a4fa769977f8a97930..80d4d46bd5dae012f8252dad0d53d5780ecc9f54 100644 (file)
@@ -1239,36 +1239,56 @@ static void rtpcs_930x_sds_rx_reset(struct rtpcs_serdes *sds,
        rtpcs_sds_write_bits(sds, page, 0x15, 4, 4, 0x0);
 }
 
-static void rtpcs_930x_sds_get_pll_data(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type *pll,
+static int rtpcs_930x_sds_get_pll_select(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type *pll)
+{
+       struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
+       int pbit = (sds == even_sds) ? 4 : 6;
+       int pll_sel;
+
+       pll_sel = rtpcs_sds_read_bits(even_sds, 0x20, 0x12, pbit + 1, pbit);
+       if (pll_sel < 0)
+               return pll_sel;
+
+       /* bit 0 is force-bit, bit 1 is PLL selector */
+       *pll = (enum rtpcs_sds_pll_type)(pll_sel >> 1);
+       return 0;
+}
+
+static void rtpcs_930x_sds_get_pll_data(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll,
                                        enum rtpcs_sds_pll_speed *speed)
 {
        struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
-       int sbit, pbit = (sds == even_sds) ? 4 : 6;
-       int pll_val, speed_val;
+       int sbit, speed_val;
 
        /*
         * PLL data is shared between adjacent SerDes in the even lane. Each SerDes defines
         * what PLL it needs (ring or LC) while the PLL itself stores the current speed.
         */
 
-       pll_val = rtpcs_sds_read_bits(even_sds, 0x20, 0x12, pbit + 1, pbit);
-
-       /* bit 0 is force-bit, bit 1 is PLL selector */
-       *pll = (enum rtpcs_sds_pll_type)(pll_val >> 1);
-
-       sbit = *pll == RTPCS_SDS_PLL_TYPE_LC ? 8 : 12;
+       sbit = pll == RTPCS_SDS_PLL_TYPE_LC ? 8 : 12;
        speed_val = rtpcs_sds_read_bits(even_sds, 0x20, 0x12, sbit + 3, sbit);
 
        /* bit 0 is force-bit, bits [3:1] are speed selector */
        *speed = (enum rtpcs_sds_pll_speed)(speed_val >> 1);
 }
 
+static int rtpcs_930x_sds_set_pll_select(struct rtpcs_serdes *sds, enum rtpcs_sds_mode hw_mode,
+                                        enum rtpcs_sds_pll_type pll)
+{
+       struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
+       int pbit = (sds == even_sds) ? 4 : 6;
+
+       /* Selecting the PLL a SerDes is done in the even lane register */
+
+       /* bit 0 is force-bit, bit 1 is PLL selector */
+       return rtpcs_sds_write_bits(even_sds, 0x20, 0x12, pbit + 1, pbit, (pll << 1) | BIT(0));
+}
+
 static int rtpcs_930x_sds_set_pll_data(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll,
                                       enum rtpcs_sds_pll_speed speed)
 {
        struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
        int sbit = pll == RTPCS_SDS_PLL_TYPE_LC ? 8 : 12;
-       int pbit = (sds == even_sds) ? 4 : 6;
 
        if (speed >= RTPCS_SDS_PLL_SPD_END)
                return -EINVAL;
@@ -1287,9 +1307,6 @@ static int rtpcs_930x_sds_set_pll_data(struct rtpcs_serdes *sds, enum rtpcs_sds_
 
        rtpcs_sds_write_bits(even_sds, 0x20, 0x12, 3, 0, 0xf);
 
-       /* bit 0 is force-bit, bit 1 is PLL selector */
-       rtpcs_sds_write_bits(even_sds, 0x20, 0x12, pbit + 1, pbit, (pll << 1) | BIT(0));
-
        /* bit 0 is force-bit, bits [3:1] are speed selector */
        rtpcs_sds_write_bits(even_sds, 0x20, 0x12, sbit + 3, sbit, (speed << 1) | BIT(0));
 
@@ -1300,9 +1317,8 @@ static void rtpcs_930x_sds_reset_cmu(struct rtpcs_serdes *sds)
 {
        struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
        int reset_sequence[4] = { 3, 2, 3, 1 };
-       enum rtpcs_sds_pll_speed speed;
        enum rtpcs_sds_pll_type pll;
-       int i, bit;
+       int ret, i, bit;
 
        /*
         * After the PLL speed has changed, the CMU must take over the new values. The models
@@ -1310,7 +1326,10 @@ static void rtpcs_930x_sds_reset_cmu(struct rtpcs_serdes *sds)
         * to flipping two bits in a special sequence.
         */
 
-       rtpcs_930x_sds_get_pll_data(sds, &pll, &speed);
+       ret = rtpcs_930x_sds_get_pll_select(sds, &pll);
+       if (ret < 0)
+               return;
+
        bit = pll == RTPCS_SDS_PLL_TYPE_LC ? 2 : 0;
 
        for (i = 0; i < ARRAY_SIZE(reset_sequence); i++)
@@ -1366,11 +1385,16 @@ static void rtpcs_930x_sds_set_power(struct rtpcs_serdes *sds, bool on)
 static void rtpcs_930x_sds_reconfigure_pll(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type pll)
 {
        enum rtpcs_sds_pll_speed speed;
-       enum rtpcs_sds_pll_type tmp;
-       int mode;
+       enum rtpcs_sds_pll_type old_pll;
+       int mode, ret;
 
        mode = __rtpcs_930x_sds_get_ip_mode(sds);
-       rtpcs_930x_sds_get_pll_data(sds, &tmp, &speed);
+
+       ret = rtpcs_930x_sds_get_pll_select(sds, &old_pll);
+       if (ret < 0)
+               return;
+
+       rtpcs_930x_sds_get_pll_data(sds, old_pll, &speed);
 
        rtpcs_930x_sds_set_power(sds, false);
        __rtpcs_930x_sds_set_ip_mode(sds, RTPCS_930X_SDS_OFF);
@@ -1378,6 +1402,10 @@ static void rtpcs_930x_sds_reconfigure_pll(struct rtpcs_serdes *sds, enum rtpcs_
        rtpcs_930x_sds_set_pll_data(sds, pll, speed);
        rtpcs_930x_sds_reset_cmu(sds);
 
+       ret = rtpcs_930x_sds_set_pll_select(sds, sds->hw_mode, pll);
+       if (ret < 0)
+               return;
+
        __rtpcs_930x_sds_set_ip_mode(sds, mode);
        if (rtpcs_930x_sds_wait_clock_ready(sds))
                pr_err("%s: SDS %d could not sync clock\n", __func__, sds->id);
@@ -1392,7 +1420,7 @@ static int rtpcs_930x_sds_config_pll(struct rtpcs_serdes *sds,
        enum rtpcs_sds_pll_speed speed, neighbor_speed;
        enum rtpcs_sds_pll_type pll, neighbor_pll;
        bool speed_changed = true;
-       int neighbor_mode;
+       int neighbor_mode, ret;
 
        /*
         * A SerDes pair on the RTL930x is driven by two PLLs. A low speed ring PLL can generate
@@ -1414,7 +1442,12 @@ static int rtpcs_930x_sds_config_pll(struct rtpcs_serdes *sds,
         */
 
        neighbor_mode = __rtpcs_930x_sds_get_ip_mode(nb_sds);
-       rtpcs_930x_sds_get_pll_data(nb_sds, &neighbor_pll, &neighbor_speed);
+
+       ret = rtpcs_930x_sds_get_pll_select(sds, &neighbor_pll);
+       if (ret < 0)
+               return ret;
+
+       rtpcs_930x_sds_get_pll_data(nb_sds, neighbor_pll, &neighbor_speed);
 
        if ((hw_mode == RTPCS_SDS_MODE_1000BASEX) ||
            (hw_mode == RTPCS_SDS_MODE_SGMII))
@@ -1447,6 +1480,10 @@ static int rtpcs_930x_sds_config_pll(struct rtpcs_serdes *sds,
        if (speed_changed)
                rtpcs_930x_sds_reset_cmu(sds);
 
+       ret = rtpcs_930x_sds_set_pll_select(sds, hw_mode, pll);
+       if (ret < 0)
+               return ret;
+
        pr_info("%s: SDS %d using %s PLL for mode %d\n", __func__, sds->id,
                pll == RTPCS_SDS_PLL_TYPE_LC ? "LC" : "ring", hw_mode);