]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: pcs: add XSG write operations 21592/head
authorJonas Jelonek <jelonek.jonas@gmail.com>
Fri, 16 Jan 2026 09:32:52 +0000 (09:32 +0000)
committerRobert Marko <robimarko@gmail.com>
Wed, 28 Jan 2026 20:10:42 +0000 (21:10 +0100)
There is some special logic used for certain writes to digital pages for
RTL93xx SerDes, especially when configuring the XSGMII mode. For
RTL930x this applies to SerDes 2 and 3, for RTL93xx to more. In this case,
a dual-read/write to SDS and SDS + 1 is done. While the corresponding
mapping from front to back SDS for RTL931x is currently covered in the
SerDes MDIO driver, it isn't for RTL930x.

To cover these special cases and provide a clear interface on that,
introduce an XSG write SerDes operation. All these dual-read/write cases
can be expressed with such an XSG operation whose internal semantics are
defined for each switchcore family.

This could be done just with plain dual read/write calls however this
isn't a clean approach and may be confusing while comparing our
functionality with the SDK, especially for RTL930x.

In practice, if this isn't handled correctly, only half of the ports of an
XSGMII-connected RTL8218D do work because some required values aren't
applied for the background SerDes 3.

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

index 31b40038f4f7c00dc36343acf66546227de104ea..24b94a4952a3bbecd1e2649fc4cecedb1843f8cb 100644 (file)
@@ -159,6 +159,10 @@ struct rtpcs_serdes_ops {
        int (*read)(struct rtpcs_serdes *sds, int page, int regnum, int bithigh, int bitlow);
        int (*write)(struct rtpcs_serdes *sds, int page, int regnum, int bithigh, int bitlow,
                     u16 value);
+
+       /* optional */
+       int (*xsg_write)(struct rtpcs_serdes *sds, int page, int regnum, int bithigh, int bitlow,
+                        u16 value);
 };
 
 struct rtpcs_serdes {
@@ -297,6 +301,25 @@ static int rtpcs_sds_write(struct rtpcs_serdes *sds, int page, int regnum, u16 v
        return sds->ops->write(sds, page, regnum, 15, 0, value);
 }
 
+__maybe_unused
+static int rtpcs_sds_xsg_write_bits(struct rtpcs_serdes *sds, int page, int regnum, int bithigh,
+                                   int bitlow, u16 value)
+{
+       if (!sds->ops->xsg_write)
+               return -ENOTSUPP;
+
+       return sds->ops->xsg_write(sds, page, regnum, bithigh, bitlow, value);
+}
+
+__maybe_unused
+static int rtpcs_sds_xsg_write(struct rtpcs_serdes *sds, int page, int regnum, u16 value)
+{
+       if (!sds->ops->xsg_write)
+               return -ENOTSUPP;
+
+       return sds->ops->xsg_write(sds, page, regnum, 15, 0, value);
+}
+
 /* Other helpers */
 
 static int rtpcs_sds_modify(struct rtpcs_serdes *sds, int page, int regnum,
@@ -960,6 +983,39 @@ static int rtpcs_930x_sds_op_write(struct rtpcs_serdes *sds, int page, int regnu
        return __rtpcs_sds_write_raw(sds->ctrl, sds_id, page, regnum, bithigh, bitlow, value);
 }
 
+/*
+ * Realtek uses some nasty logic for digital parts of SerDes 2 and 3.
+ *
+ * This implements 'dal_longan_sds_xsg_field_write' and a combination of
+ * '_rtl9300_serdes_index_to_physical' and '_rtl9300_serdes_reg_write' from the SDK.
+ */
+static int rtpcs_930x_sds_op_xsg_write(struct rtpcs_serdes *sds, int page, int regnum,
+                                      int bithigh, int bitlow, u16 value)
+{
+       int phys_sds_id, ret;
+
+       switch (sds->id) {
+       case 2:
+               phys_sds_id = 2;
+               break;
+       case 3:
+               phys_sds_id = 10;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       if (page >= 4)
+               return sds->ops->write(sds, page, regnum, bithigh, bitlow, value);
+
+       ret = __rtpcs_sds_write_raw(sds->ctrl, phys_sds_id, page, regnum, bithigh, bitlow, value);
+       if (ret)
+               return ret;
+
+       return __rtpcs_sds_write_raw(sds->ctrl, phys_sds_id + 1, page, regnum, bithigh, bitlow,
+                                    value);
+}
+
 static const u16 rtpcs_930x_sds_regs[] = {
        0x0194, 0x0194, 0x0194, 0x0194,         /* SDS_MODE_SEL_0 */
        0x02a0, 0x02a0, 0x02a0, 0x02a0,         /* SDS_MODE_SEL_1 */
@@ -2742,6 +2798,29 @@ static int rtpcs_930x_setup_serdes(struct rtpcs_serdes *sds,
 
 /* RTL931X */
 
+/*
+ * The SerDes MDIO driver maps page regions to different background SerDes.
+ * 0x00 - 0x3f analog SDS
+ * 0x40 - 0x7f digital SDS 1
+ * 0x80 - 0xbf digital SDS 2
+ *
+ * An XSG write operates on digital SDS 1 and digital SDS 2. Map that to the
+ * page ranges accordingly.
+ */
+static int rtpcs_931x_sds_op_xsg_write(struct rtpcs_serdes *sds, int page, int regnum,
+                                       int bithigh, int bitlow, u16 value)
+{
+        int ret;
+
+        ret = __rtpcs_sds_write_raw(sds->ctrl, sds->id, page + 0x40, regnum, bithigh, bitlow,
+                                   value);
+        if (ret)
+                return ret;
+
+        return __rtpcs_sds_write_raw(sds->ctrl, sds->id, page + 0x80, regnum, bithigh, bitlow,
+                                    value);
+}
+
 __maybe_unused
 static int rtpcs_931x_sds_fiber_get_symerr(struct rtpcs_serdes *sds,
                                           enum rtpcs_sds_mode hw_mode)
@@ -3887,6 +3966,7 @@ static const struct phylink_pcs_ops rtpcs_930x_pcs_ops = {
 static const struct rtpcs_serdes_ops rtpcs_930x_sds_ops = {
        .read                   = rtpcs_930x_sds_op_read,
        .write                  = rtpcs_930x_sds_op_write,
+       .xsg_write              = rtpcs_930x_sds_op_xsg_write,
 };
 
 static const struct rtpcs_config rtpcs_930x_cfg = {
@@ -3913,6 +3993,7 @@ static const struct phylink_pcs_ops rtpcs_931x_pcs_ops = {
 static const struct rtpcs_serdes_ops rtpcs_931x_sds_ops = {
        .read                   = rtpcs_generic_sds_op_read,
        .write                  = rtpcs_generic_sds_op_write,
+       .xsg_write              = rtpcs_931x_sds_op_xsg_write,
 };
 
 static const struct rtpcs_config rtpcs_931x_cfg = {