]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: rtl931x: wire up RX calibration for PHY-attached ports
authorJonas Jelonek <jelonek.jonas@gmail.com>
Tue, 28 Jul 2026 22:09:39 +0000 (22:09 +0000)
committerJonas Jelonek <jelonek.jonas@gmail.com>
Tue, 4 Aug 2026 07:51:27 +0000 (09:51 +0200)
Add post_config, run after activate() like on RTL930x, dispatching RX
calibration by attachment. Port the vendor SDK's _phy_rtl9310_leq_adapt()
as rtpcs_931x_sds_rxcal_leq_adapt() for the PHY-attached case, built on
new rxeq_leq_set_coef()/rxeq_leq_set_adapt() setters and the
existing but unused rx_reset().

Add rtpcs_931x_sds_dfe_disable_5g() for the one-shot operation the SDK
issues before calibrating PHY-attached and PCB-adapt ports. Presumably,
this quiesces DFE auto-adapt on the 5G companion analog block to prevent
it from interfering with DFE adaption during calibration.

Fiber and DAC attachments remain a TODO in post_config's dispatch.

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

index 3ab24fc4a8f50607f77c96201ca24bb52dff5eb5..e26836b27dcacfe9320c3797b9e3bece4a5c1f05 100644 (file)
@@ -3120,6 +3120,16 @@ static void rtpcs_931x_sds_clear_symerr(struct rtpcs_serdes *sds,
        }
 }
 
+static int rtpcs_931x_sds_rxeq_leq_set_adapt(struct rtpcs_serdes *sds, bool enable)
+{
+       return rtpcs_sds_write_bits(sds, PAGE_ANA_10G, 0xd, 7, 7, enable ? 0x0 : 0x1);
+}
+
+static int rtpcs_931x_sds_rxeq_leq_set_coef(struct rtpcs_serdes *sds, unsigned int gain)
+{
+       return rtpcs_sds_write_bits(sds, PAGE_ANA_10G, 0xd, 6, 2, gain);
+}
+
 /**
  * rtpcs_931x_sds_reset_leq_dfe() - Reset LEQ + DFE to a baseline.
  *
@@ -3151,6 +3161,16 @@ static int rtpcs_931x_sds_reset_leq_dfe(struct rtpcs_serdes *sds)
        return 0;
 }
 
+/*
+ * Disable DFE auto-adapt on the companion 5G analog block before
+ * calibrating this lane's 10G LEQ/DFE. Used by the vendor SDK's
+ * PHY-attached and PCB-adapt calibration paths.
+ */
+static int rtpcs_931x_sds_dfe_disable_5g(struct rtpcs_serdes *sds)
+{
+       return rtpcs_sds_write_bits(sds, PAGE_ANA_5G0, 0xf, 12, 6, 0x7f);
+}
+
 static int rtpcs_931x_sds_power(struct rtpcs_serdes *sds, bool power_on)
 {
        u32 en_val = power_on ? 0 : BIT(sds->id);
@@ -3210,7 +3230,6 @@ static int rtpcs_931x_sds_activate(struct rtpcs_serdes *sds)
        return rtpcs_931x_sds_power(sds, true);
 }
 
-__maybe_unused
 static void rtpcs_931x_sds_rx_reset(struct rtpcs_serdes *sds)
 {
        if (sds->type != RTPCS_SDS_TYPE_10G)
@@ -3229,6 +3248,29 @@ static void rtpcs_931x_sds_rx_reset(struct rtpcs_serdes *sds)
        msleep(50);
 }
 
+/*
+ * rtpcs_931x_sds_rxcal_leq_adapt() - RX calibration for PHY-attached ports.
+ *
+ * Vendor SDK: _phy_rtl9310_leq_adapt(). Used whenever the port has an
+ * external PHY attached, regardless of hw_mode - the PHY performs its own
+ * equalization, so this only resets LEQ and releases it back into
+ * auto-adapt. No TAP/VTH involvement.
+ */
+static void rtpcs_931x_sds_rxcal_leq_adapt(struct rtpcs_serdes *sds)
+{
+       rtpcs_931x_sds_rxeq_leq_set_coef(sds, 0);
+       rtpcs_sds_write_bits(sds, PAGE_ANA_10G, 0xd, 1, 0, 0x0);   /* undocumented */
+       rtpcs_sds_write_bits(sds, PAGE_ANA_10G, 0xd, 13, 13, 0x0); /* undocumented */
+
+       rtpcs_931x_sds_dfe_disable_5g(sds);
+
+       rtpcs_931x_sds_rxeq_leq_set_adapt(sds, false);
+       rtpcs_931x_sds_rx_reset(sds);
+       msleep(10);
+       rtpcs_931x_sds_rxeq_leq_set_adapt(sds, true);
+       msleep(100);
+}
+
 static int rtpcs_931x_sds_get_pll_select(struct rtpcs_serdes *sds, enum rtpcs_sds_pll_type *pll)
 {
        int cmu_page, pll_sel;
@@ -3580,6 +3622,30 @@ static int rtpcs_931x_sds_config_attachment(struct rtpcs_serdes *sds,
        return 0;
 }
 
+/*
+ * rtpcs_931x_sds_post_config() - RX calibration, run after power-up.
+ *
+ * Vendor SDK: _phy_rtl9310_rxCali(). Dispatches by attachment, mirroring
+ * the SDK's own split into separate calibration paths per attachment.
+ */
+static int rtpcs_931x_sds_post_config(struct rtpcs_serdes *sds, enum rtpcs_sds_mode hw_mode)
+{
+       if (sds->type != RTPCS_SDS_TYPE_10G)
+               return 0;
+
+       switch (sds->attachment) {
+       case RTPCS_SDS_ATTACH_PHY:
+               rtpcs_931x_sds_rxcal_leq_adapt(sds);
+               break;
+
+       default:
+               /* TODO: fiber/DAC RX calibration */
+               break;
+       }
+
+       return 0;
+}
+
 static int rtpcs_931x_sds_config_hw_mode(struct rtpcs_serdes *sds,
                                         enum rtpcs_sds_mode hw_mode)
 {
@@ -4284,6 +4350,7 @@ static const struct rtpcs_sds_ops rtpcs_931x_sds_ops = {
        .config_hw_mode         = rtpcs_931x_sds_config_hw_mode,
        .set_hw_mode            = rtpcs_931x_sds_set_mode,
        .config_attachment      = rtpcs_931x_sds_config_attachment,
+       .post_config            = rtpcs_931x_sds_post_config,
 };
 
 static const struct rtpcs_config rtpcs_931x_cfg = {