realtek: dsa: rtl931x: configure phy ability source
authorJonas Jelonek <jelonek.jonas@gmail.com>
Thu, 1 Jan 2026 20:11:17 +0000 (20:11 +0000)
committerHauke Mehrtens <hauke@hauke-m.de>
Fri, 2 Jan 2026 20:35:28 +0000 (21:35 +0100)
The MAC can get PHY abilities, link status, etc. via different ways. In
RTL931x, the corresponding register needs to be setup properly. By
default, all ports use out-of-band MDIO polling to retrieve that
information. Thus, PHY-backed ports usually work with the default
setting.

For SFP ports, there is no MDIO polling available. Instead, the SerDes
ability bus needs to be used to retrieve the link information.

So far, the bootloader (e.g. U-boot) had to properly initialize that
setting. Instead of relying on that, do that properly during MAC setup.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/21351
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c

index 5ddff2a1b497c4e3a1c1fbef05a3846e908bf1b1..b9c7cda60c59889139992a5d66c3e559768c3204 100644 (file)
@@ -614,6 +614,10 @@ static int rtl93xx_setup(struct dsa_switch *ds)
        }
        priv->r->traffic_set(priv->cpu_port, BIT_ULL(priv->cpu_port));
 
+       /* Configure how MAC gets PHY ability for each port */
+       if (priv->family_id == RTL9310_FAMILY_ID)
+               rtldsa_931x_config_phy_ability_source(priv);
+
        if (priv->family_id == RTL9300_FAMILY_ID)
                rtl930x_print_matrix();
        else if (priv->family_id == RTL9310_FAMILY_ID)
index a3cb62ceb7ff2263eedb5a2c2fb074555b3206fe..38a8f94ef8f8d49a4b3e20cd42d3d7aa65cbdab5 100644 (file)
@@ -182,6 +182,7 @@ void rtl930x_print_matrix(void);
 /* RTL931x-specific */
 irqreturn_t rtl931x_switch_irq(int irq, void *dev_id);
 void rtl931x_print_matrix(void);
+void rtldsa_931x_config_phy_ability_source(struct rtl838x_switch_priv *priv);
 
 int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_lag_upper_info *info);
 int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port);
index bb51c6e7e802c504830a06f1e7c543d9826cee52..e6e42a4bc19fbb35371e9a85e71e81d13100f6b0 100644 (file)
 #define RTL931X_VLAN_PORT_TAG_ITPID_IDX_MASK                   GENMASK(2, 1)
 #define RTL931X_VLAN_PORT_TAG_ITPID_KEEP_MASK                  GENMASK(0, 0)
 
+#define RTLDSA_931X_SMI_PHY_ABLTY_GET_SEL                      0x0cac
+#define  RTLDSA_931X_PHY_ABLTY_OUTBAND_MDIO                    0x0
+#define  RTLDSA_931X_PHY_ABLTY_INBAND_SDS_POLL                 0x1
+#define  RTLDSA_931X_PHY_ABLTY_SDS_ABLTY_BUS                   0x2
+
 /* Definition of the RTL931X-specific template field IDs as used in the PIE */
 enum template_field_id {
        TEMPLATE_FIELD_SPM0 = 1,
@@ -1764,6 +1769,30 @@ static void rtldsa_931x_qos_init(struct rtl838x_switch_priv *priv)
        rtldsa_931x_qos_set_scheduling_queue_weights(priv);
 }
 
+void rtldsa_931x_config_phy_ability_source(struct rtl838x_switch_priv *priv)
+{
+       u32 phy_ablty_sel[4] = {0};
+
+       for (int port = 0; port < priv->cpu_port; port++) {
+               u32 val = RTLDSA_931X_PHY_ABLTY_OUTBAND_MDIO;
+
+               /* port driven by SerDes */
+               if (!priv->ports[port].phy && priv->pcs[port])
+                       val = RTLDSA_931X_PHY_ABLTY_SDS_ABLTY_BUS;
+
+               phy_ablty_sel[port / 16] |= (val & 0x3) << ((port % 16) * 2);
+       }
+
+       pr_debug("%s: phy_ablty_sel [0] %x [1] %x [2] %x [3] %x\n", __func__,
+                phy_ablty_sel[0], phy_ablty_sel[1], phy_ablty_sel[2],
+                phy_ablty_sel[3]);
+
+       sw_w32(phy_ablty_sel[0], RTLDSA_931X_SMI_PHY_ABLTY_GET_SEL);
+       sw_w32(phy_ablty_sel[1], RTLDSA_931X_SMI_PHY_ABLTY_GET_SEL + 0x4);
+       sw_w32(phy_ablty_sel[2], RTLDSA_931X_SMI_PHY_ABLTY_GET_SEL + 0x8);
+       sw_w32(phy_ablty_sel[3], RTLDSA_931X_SMI_PHY_ABLTY_GET_SEL + 0xc);
+}
+
 const struct rtl838x_reg rtl931x_reg = {
        .mask_port_reg_be = rtl839x_mask_port_reg_be,
        .set_port_reg_be = rtl839x_set_port_reg_be,