[PATCH RFC 3/9] net: stmmac: qcom-ethqos: fix RGMII_ID mode to use DLL bypass
Mohd Ayaan Anwar
mohd.anwar at oss.qualcomm.com
Thu Jun 11 11:36:59 PDT 2026
When "rgmii-id" is selected the PHY supplies both TX and RX delays, so
the MAC must not add its own. The driver currently falls through to the
generic DLL initialisation path which programs it to add a delay.
Power down the DLL and set DDR bypass mode for RGMII_ID, then program
the IO_MACRO via a new ethqos_rgmii_id_macro_init() helper. Also fix
ethqos_set_clk_tx_rate() to not double the clock rate in bypass mode at
100M/10M, and remove RGMII_ID from the phase-shift suppression in
ethqos_rgmii_macro_init() since RGMII_ID no longer reaches that path.
Signed-off-by: Mohd Ayaan Anwar <mohd.anwar at oss.qualcomm.com>
---
.../ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c | 65 +++++++++++++++++++++-
1 file changed, 62 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
index 44270c25d874f72e7f971757fec659d36468c315..bec08f1eb8cb41484ba3c91c77393e163e7fd071 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
@@ -67,6 +67,9 @@
/* SDC4_STATUS bits */
#define SDC4_STATUS_DLL_LOCK BIT(7)
+/* SDCC_USR_CTL bits */
+#define SDCC_USR_CTL_DDR_BYPASS BIT(30)
+
/* RGMII_IO_MACRO_CONFIG2 fields */
#define RGMII_CONFIG2_RSVD_CONFIG15 GENMASK(31, 17)
#define RGMII_CONFIG2_RGMII_CLK_SEL_CFG BIT(16)
@@ -183,7 +186,15 @@ static int ethqos_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i,
if (rate < 0)
return rate;
- return clk_set_rate(ethqos->link_clk, rate * 2);
+ /* Clock Rate Requirements:
+ * MAC added delay: 250/50/5 Mhz for 1G/100M/10M
+ * No MAC delay (DLL bypass): 250/25/2.5 Mhz for 1G/100M/10M
+ */
+ if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII ||
+ speed == SPEED_1000)
+ rate *= 2;
+
+ return clk_set_rate(ethqos->link_clk, rate);
}
static void
@@ -405,8 +416,7 @@ static void ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed)
RGMII_IO_MACRO_CONFIG2);
/* Determine if the PHY adds a 2 ns TX delay or the MAC handles it */
- if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_ID ||
- ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID)
+ if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_TXID)
phase_shift = 0;
else
phase_shift = RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN;
@@ -475,6 +485,40 @@ static void ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed)
RGMII_IO_MACRO_CONFIG);
}
+static void ethqos_rgmii_id_macro_init(struct qcom_ethqos *ethqos, int speed)
+{
+ rgmii_clrmask(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN,
+ RGMII_IO_MACRO_CONFIG2);
+
+ if (speed == SPEED_1000)
+ rgmii_setmask(ethqos, RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG);
+ else
+ rgmii_clrmask(ethqos, RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG);
+ rgmii_setmask(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, RGMII_IO_MACRO_CONFIG);
+ rgmii_clrmask(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, RGMII_IO_MACRO_CONFIG);
+ rgmii_clrmask(ethqos, RGMII_CONFIG_PROG_SWAP, RGMII_IO_MACRO_CONFIG);
+
+ if (ethqos->has_emac_ge_3)
+ rgmii_clrmask(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL,
+ RGMII_IO_MACRO_CONFIG2);
+ else
+ rgmii_setmask(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL,
+ RGMII_IO_MACRO_CONFIG2);
+
+ rgmii_clrmask(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN,
+ RGMII_IO_MACRO_CONFIG2);
+
+ if (speed == SPEED_1000)
+ rgmii_clrmask(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, RGMII_IO_MACRO_CONFIG2);
+ else
+ rgmii_setmask(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, RGMII_IO_MACRO_CONFIG2);
+
+ if (!ethqos->rgmii_config_loopback_en)
+ rgmii_clrmask(ethqos, RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG);
+
+ rgmii_setmask(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_IO_MACRO_CONFIG2);
+}
+
static void ethqos_fix_mac_speed_rgmii(void *bsp_priv,
phy_interface_t interface, int speed,
unsigned int mode)
@@ -493,6 +537,21 @@ static void ethqos_fix_mac_speed_rgmii(void *bsp_priv,
ethqos_set_func_clk_en(ethqos);
+ /* For rgmii-id mode, the PHY should add the required delays.
+ * Therefore, power down the DLL and program it in bypass mode.
+ * Program the IO_MACRO as per the settings recommended by the
+ * programming guide for bypass mode. This will ensure that the
+ * MAC core doesn't add any additional delays.
+ */
+ if (ethqos->phy_mode == PHY_INTERFACE_MODE_RGMII_ID) {
+ rgmii_setmask(ethqos, SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG);
+ rgmii_setmask(ethqos, SDCC_USR_CTL_DDR_BYPASS, SDCC_USR_CTL);
+
+ ethqos_rgmii_id_macro_init(ethqos, speed);
+
+ return;
+ }
+
/* Initialize the DLL first */
/* Set DLL_RST */
--
2.34.1
More information about the linux-arm-kernel
mailing list