]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: rtl931x: demystify some setup magic
authorJonas Jelonek <jelonek.jonas@gmail.com>
Wed, 4 Feb 2026 20:19:55 +0000 (20:19 +0000)
committerRobert Marko <robimarko@gmail.com>
Tue, 14 Apr 2026 09:50:55 +0000 (11:50 +0200)
Shed some light into the darkness by giving a part of the setup a
dedicated name. This applies to the magic data blocks in the generic
setup entrypoint and some writes in the media handling. This was just
copied from the SDK which doesn't annotate this properly with
information. But we can clearly connect this with some other functions
of the SDK and extract meaningful information.

The mentioned magic blocks and register writes set coefficients of three
amplifiers in the TX path, a pre-amp, a main-amp and a post-amp. They
are used to tune the signal for different kinds of media. Generic values
are applied for all SerDes and further special values for different media
types depending on the needs.

Provide a dedicated function that sets these amplifier coefficients.
Replace the mystic register writes with the function call so one can see
at a glance what's happening. Also replace the magic TX values with the
coefficients organized into a separate struct. This might be extended
further and is also applicable for RTL930x.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/22814
Signed-off-by: Robert Marko <robimarko@gmail.com>
target/linux/realtek/files-6.18/drivers/net/pcs/pcs-rtl-otto.c

index 41f2fe088f2276a8334338aa66e94bf2e1b69d60..b54a4f880ec55c5c8c8816937dd15039cc36bf58 100644 (file)
 #define RTPCS_931X_MAC_SERDES_MODE_CTRL(sds)   (0x136C + (((sds) << 2)))
 #define RTPCS_931X_ISR_SERDES_RXIDLE           (0x12f8)
 
+#define RTPCS_931X_SDS_PRE_AMP_MASK            GENMASK(4, 0)
+#define RTPCS_931X_SDS_MAIN_AMP_MASK           GENMASK(9, 5)
+#define RTPCS_931X_SDS_POST_AMP_MASK           GENMASK(14, 10)
+
 enum rtpcs_sds_mode {
        RTPCS_SDS_MODE_OFF = 0,
 
@@ -248,6 +252,12 @@ struct rtpcs_sds_config {
        u16 data;
 };
 
+struct rtpcs_sds_tx_config {
+       u8 pre_amp;
+       u8 main_amp;
+       u8 post_amp;
+};
+
 static int rtpcs_sds_to_mmd(int sds_page, int sds_regnum)
 {
        return (sds_page << 8) + sds_regnum;
@@ -3490,6 +3500,36 @@ static int rtpcs_931x_sds_set_polarity(struct rtpcs_serdes *sds,
        return rtpcs_sds_write_bits(sds, 0x80, 0x0, 9, 8, val);
 }
 
+/**
+ * rtpcs_931x_sds_config_tx_amps - Configure SerDes TX amplifiers
+ *
+ * A SerDes has three amplifiers (pre, main, post) in the TX path that allow to tune the signal,
+ * usually based on eye diagrams. This is needed to account for different tx media, i.e. PCB
+ * trace, fiber, DAC. Using the amplifier coefficients, one can precondition the signal in such
+ * a way so that it arrives "clean" at the partner.
+ */
+static int rtpcs_931x_sds_config_tx_amps(struct rtpcs_serdes *sds, u8 pre_amp, u8 main_amp,
+                                        u8 post_amp)
+{
+       u16 cfg_val, en_val = 0;
+       int ret;
+
+       cfg_val = FIELD_PREP(RTPCS_931X_SDS_PRE_AMP_MASK, pre_amp) |
+                 FIELD_PREP(RTPCS_931X_SDS_MAIN_AMP_MASK, main_amp) |
+                 FIELD_PREP(RTPCS_931X_SDS_POST_AMP_MASK, post_amp);
+       ret = rtpcs_sds_write(sds, 0x2e, 0x1, cfg_val);
+       if (ret < 0)
+               return ret;
+
+       /* enable/disable pre + post amp, main amp has no enable bit so seems always active */
+       if (post_amp)
+               en_val |= BIT(0);
+       if (pre_amp)
+               en_val |= BIT(1);
+
+       return rtpcs_sds_write_bits(sds, 0x2e, 0x0, 1, 0, en_val);
+}
+
 static int rtpcs_931x_sds_set_media(struct rtpcs_serdes *sds, enum rtpcs_sds_media sds_media,
                                    enum rtpcs_sds_mode hw_mode)
 {
@@ -3535,13 +3575,13 @@ static int rtpcs_931x_sds_set_media(struct rtpcs_serdes *sds, enum rtpcs_sds_med
 
        switch (sds_media) {
        case RTPCS_SDS_MEDIA_DAC_SHORT:
-               rtpcs_sds_write_bits(sds, 0x2e, 0x1, 15, 0, 0x1340);
+               rtpcs_931x_sds_config_tx_amps(sds, 0x0, 0x1a, 0x4);
                rtpcs_sds_write(sds, 0x21, 0x19, 0xf0a5);       /* from XS1930-10 SDK */
                rtpcs_sds_write(even_sds, 0x2e, 0x8, 0x02a0);   /* [10:7] impedance */
                break;
 
        case RTPCS_SDS_MEDIA_DAC_LONG:
-               rtpcs_sds_write_bits(sds, 0x2e, 0x1, 15, 0, 0x5200);
+               rtpcs_931x_sds_config_tx_amps(sds, 0x0, 0x10, 0x14);
                rtpcs_sds_write(sds, 0x21, 0x19, 0xf0a5);       /* from XS1930-10 SDK */
                rtpcs_sds_write(even_sds, 0x2e, 0x8, 0x02a0);   /* [10:7] impedance */
                break;
@@ -3667,15 +3707,36 @@ static int rtpcs_931x_sds_config_hw_mode(struct rtpcs_serdes *sds,
 static int rtpcs_931x_setup_serdes(struct rtpcs_serdes *sds,
                                   enum rtpcs_sds_mode hw_mode)
 {
-       u32 board_sds_tx[] = {
-               0x1a00, 0x1a00, 0x0200, 0x0200, 0x0200, 0x0200,
-               0x01a3, 0x01a3, 0x01a3, 0x01a3, 0x01e3, 0x01e3
+       const struct rtpcs_sds_tx_config tx_cfg_v1[] = {
+               { .pre_amp = 0x00, .main_amp = 0x10, .post_amp = 0x06 },
+               { .pre_amp = 0x00, .main_amp = 0x10, .post_amp = 0x06 },
+               { .pre_amp = 0x00, .main_amp = 0x10 },
+               { .pre_amp = 0x00, .main_amp = 0x10 },
+               { .pre_amp = 0x00, .main_amp = 0x10 },
+               { .pre_amp = 0x00, .main_amp = 0x10 },
+               { .pre_amp = 0x03, .main_amp = 0x0d },
+               { .pre_amp = 0x03, .main_amp = 0x0d },
+               { .pre_amp = 0x03, .main_amp = 0x0d },
+               { .pre_amp = 0x03, .main_amp = 0x0d },
+               { .pre_amp = 0x03, .main_amp = 0x0f },
+               { .pre_amp = 0x03, .main_amp = 0x0f },
        };
-       u32 board_sds_tx2[] = {
-               0x0dc0, 0x01c0, 0x0200, 0x0180, 0x0160, 0x0123,
-               0x0123, 0x0163, 0x01a3, 0x01a0, 0x01c3, 0x09c3,
+       const struct rtpcs_sds_tx_config tx_cfg_v2[] = {
+               { .pre_amp = 0x00, .main_amp = 0x0e, .post_amp = 0x03 },
+               { .pre_amp = 0x00, .main_amp = 0x0e },
+               { .pre_amp = 0x00, .main_amp = 0x10 },
+               { .pre_amp = 0x00, .main_amp = 0x0c },
+               { .pre_amp = 0x00, .main_amp = 0x0b },
+               { .pre_amp = 0x03, .main_amp = 0x09 },
+               { .pre_amp = 0x03, .main_amp = 0x09 },
+               { .pre_amp = 0x03, .main_amp = 0x0b },
+               { .pre_amp = 0x03, .main_amp = 0x0d },
+               { .pre_amp = 0x00, .main_amp = 0x0d },
+               { .pre_amp = 0x03, .main_amp = 0x0e },
+               { .pre_amp = 0x03, .main_amp = 0x0e, .post_amp = 0x02 },
        };
        struct rtpcs_serdes *even_sds = rtpcs_sds_get_even(sds);
+       const struct rtpcs_sds_tx_config *tx_cfg;
        struct rtpcs_ctrl *ctrl = sds->ctrl;
        u32 sds_id = sds->id;
        u32 val;
@@ -3738,11 +3799,11 @@ static int rtpcs_931x_setup_serdes(struct rtpcs_serdes *sds,
        }
 
        if (sds_id >= 2) {
-               if (ctrl->chip_version == RTPCS_CHIP_V2)
-                       /* consider 9311 etc. RTL9313_CHIP_ID == HWP_CHIP_ID(unit)) */
-                       rtpcs_sds_write(sds, 0x2E, 0x1, board_sds_tx2[sds_id - 2]);
-               else
-                       rtpcs_sds_write(sds, 0x2E, 0x1, board_sds_tx[sds_id - 2]);
+               /* consider 9311 etc. RTL9313_CHIP_ID == HWP_CHIP_ID(unit)) */
+               tx_cfg = (ctrl->chip_version == RTPCS_CHIP_V2) ? &tx_cfg_v2[sds_id - 2]
+                                                              : &tx_cfg_v1[sds_id - 2];
+               rtpcs_931x_sds_config_tx_amps(sds, tx_cfg->pre_amp, tx_cfg->main_amp,
+                                             tx_cfg->post_amp);
        }
 
        rtpcs_931x_sds_set_polarity(sds, sds->tx_pol_inv, sds->rx_pol_inv);