[openwrt/openwrt] realtek: support configuring SerDes auto-negotiation on RTL93xx

LEDE Commits lede-commits at lists.infradead.org
Thu Sep 25 02:27:48 PDT 2025


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/6790e1a564699557a54e2bbf43d42a49ff7437a2

commit 6790e1a564699557a54e2bbf43d42a49ff7437a2
Author: Jan Hoffmann <jan at 3e8.eu>
AuthorDate: Thu Jul 24 19:39:28 2025 +0200

    realtek: support configuring SerDes auto-negotiation on RTL93xx
    
    There are SFP modules which only work if auto-negotiation is disabled,
    like some "OEM SFP-2.5G-T" modules. This also seems to be necessary for
    RTL8226/RTL8221B PHYs when using 2500Base-X.
    
    However, currently, it is always enabled, so add support for configuring
    it to make these SFP modules and PHYs work.
    
    This also adds locking which should be useful for future extension of
    the PCS driver.
    
    Signed-off-by: Jan Hoffmann <jan at 3e8.eu>
    Link: https://github.com/openwrt/openwrt/pull/19518
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 .../files-6.12/drivers/net/pcs/pcs-rtl-otto.c      | 64 +++++++++++++++++-----
 1 file changed, 51 insertions(+), 13 deletions(-)

diff --git a/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c b/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c
index b23e177f86..6a88b8c766 100644
--- a/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c
+++ b/target/linux/realtek/files-6.12/drivers/net/pcs/pcs-rtl-otto.c
@@ -52,23 +52,13 @@
 
 #define RTPCS_93XX_MAC_LINK_SPD_BITS		4
 
-struct rtpcs_config {
-	int cpu_port;
-	int mac_link_dup_sts;
-	int mac_link_spd_bits;
-	int mac_link_spd_sts;
-	int mac_link_sts;
-	int mac_rx_pause_sts;
-	int mac_tx_pause_sts;
-	const struct phylink_pcs_ops *pcs_ops;
-};
-
 struct rtpcs_ctrl {
 	struct device *dev;
 	struct regmap *map;
 	struct mii_bus *bus;
 	const struct rtpcs_config *cfg;
 	struct rtpcs_link *link[RTPCS_PORT_CNT];
+	struct mutex lock;
 };
 
 struct rtpcs_link {
@@ -78,6 +68,18 @@ struct rtpcs_link {
 	int port;
 };
 
+struct rtpcs_config {
+	int cpu_port;
+	int mac_link_dup_sts;
+	int mac_link_spd_bits;
+	int mac_link_spd_sts;
+	int mac_link_sts;
+	int mac_rx_pause_sts;
+	int mac_tx_pause_sts;
+	const struct phylink_pcs_ops *pcs_ops;
+	int (*set_autoneg)(struct rtpcs_ctrl *ctrl, int sds, unsigned int neg_mode);
+};
+
 static int rtpcs_sds_to_mmd(int sds_page, int sds_regnum)
 {
 	return (sds_page << 8) + sds_regnum;
@@ -101,6 +103,15 @@ static int rtpcs_sds_read(struct rtpcs_ctrl *ctrl, int sds, int page, int regnum
  * }
  */
 
+static int rtpcs_sds_modify(struct rtpcs_ctrl *ctrl, int sds, int page, int regnum,
+			    u16 mask, u16 set)
+{
+	int mmd_regnum = rtpcs_sds_to_mmd(page, regnum);
+
+	return mdiobus_c45_modify(ctrl->bus, sds, MDIO_MMD_VEND1, mmd_regnum,
+				  mask, set);
+}
+
 static int rtpcs_regmap_read_bits(struct rtpcs_ctrl *ctrl, int base, int bithigh, int bitlow)
 {
 	int offset = base + (bitlow / 32) * 4;
@@ -195,6 +206,10 @@ static int rtpcs_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
 {
 	struct rtpcs_link *link = rtpcs_phylink_pcs_to_link(pcs);
 	struct rtpcs_ctrl *ctrl = link->ctrl;
+	int ret = 0;
+
+	if (link->sds < 0)
+		return 0;
 
 	/*
 	 * TODO: This (or copies of this) will be the central function for configuring the
@@ -202,10 +217,21 @@ static int rtpcs_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
 	 * all the other Realtek drivers. Maybe some day this will live up to the expectations.
 	 */
 
-	dev_warn(ctrl->dev, "pcs_config(%s) for port %d and sds %d not yet implemented\n",
+	dev_warn(ctrl->dev, "pcs_config(%s) for port %d and sds %d not yet fully implemented\n",
 		 phy_modes(interface), link->port, link->sds);
 
-	return 0;
+	mutex_lock(&ctrl->lock);
+
+	if (ctrl->cfg->set_autoneg) {
+		ret = ctrl->cfg->set_autoneg(ctrl, link->sds, neg_mode);
+		if (ret < 0)
+			goto out;
+	}
+
+out:
+	mutex_unlock(&ctrl->lock);
+
+	return ret;
 }
 
 struct phylink_pcs *rtpcs_create(struct device *dev, struct device_node *np, int port);
@@ -318,6 +344,8 @@ static int rtpcs_probe(struct platform_device *pdev)
 	if (!ctrl)
 		return -ENOMEM;
 
+	mutex_init(&ctrl->lock);
+
 	ctrl->dev = dev;
 	ctrl->cfg = (const struct rtpcs_config *)device_get_match_data(ctrl->dev);
 	ctrl->map = syscon_node_to_regmap(np->parent);
@@ -338,6 +366,14 @@ static int rtpcs_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static int rtpcs_93xx_set_autoneg(struct rtpcs_ctrl *ctrl, int sds,
+				  unsigned int neg_mode)
+{
+	u16 bmcr = neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED ? BMCR_ANENABLE : 0;
+
+	return rtpcs_sds_modify(ctrl, sds, 2, MII_BMCR, BMCR_ANENABLE, bmcr);
+}
+
 static const struct phylink_pcs_ops rtpcs_838x_pcs_ops = {
 	.pcs_an_restart		= rtpcs_pcs_an_restart,
 	.pcs_config		= rtpcs_pcs_config,
@@ -387,6 +423,7 @@ static const struct rtpcs_config rtpcs_930x_cfg = {
 	.mac_rx_pause_sts	= RTPCS_930X_MAC_RX_PAUSE_STS,
 	.mac_tx_pause_sts	= RTPCS_930X_MAC_TX_PAUSE_STS,
 	.pcs_ops		= &rtpcs_930x_pcs_ops,
+	.set_autoneg		= rtpcs_93xx_set_autoneg,
 };
 
 static const struct phylink_pcs_ops rtpcs_931x_pcs_ops = {
@@ -404,6 +441,7 @@ static const struct rtpcs_config rtpcs_931x_cfg = {
 	.mac_rx_pause_sts	= RTPCS_931X_MAC_RX_PAUSE_STS,
 	.mac_tx_pause_sts	= RTPCS_931X_MAC_TX_PAUSE_STS,
 	.pcs_ops		= &rtpcs_931x_pcs_ops,
+	.set_autoneg		= rtpcs_93xx_set_autoneg,
 };
 
 static const struct of_device_id rtpcs_of_match[] = {




More information about the lede-commits mailing list