net: stmmac: thead: Enable TX clock before MAC initialization
authorYao Zi <ziyao@disroot.org>
Fri, 15 Aug 2025 10:48:03 +0000 (10:48 +0000)
committerJakub Kicinski <kuba@kernel.org>
Wed, 20 Aug 2025 01:15:53 +0000 (18:15 -0700)
The clk_tx_i clock must be supplied to the MAC for successful
initialization. On TH1520 SoC, the clock is provided by an internal
divider configured through GMAC_PLLCLK_DIV register when using RGMII
interface. However, currently we don't setup the divider before
initialization of the MAC, resulting in DMA reset failures if the
bootloader/firmware doesn't enable the divider,

[    7.839601] thead-dwmac ffe7060000.ethernet eth0: Register MEM_TYPE_PAGE_POOL RxQ-0
[    7.938338] thead-dwmac ffe7060000.ethernet eth0: PHY [stmmac-0:02] driver [RTL8211F Gigabit Ethernet] (irq=POLL)
[    8.160746] thead-dwmac ffe7060000.ethernet eth0: Failed to reset the dma
[    8.170118] thead-dwmac ffe7060000.ethernet eth0: stmmac_hw_setup: DMA engine initialization failed
[    8.179384] thead-dwmac ffe7060000.ethernet eth0: __stmmac_open: Hw setup failed

Let's simply write GMAC_PLLCLK_DIV_EN to GMAC_PLLCLK_DIV to enable the
divider before MAC initialization. Note that for reconfiguring the
divisor, the divider must be disabled first and re-enabled later to make
sure the new divisor take effect.

The exact clock rate doesn't affect MAC's initialization according to my
test. It's set to the speed required by RGMII when the linkspeed is
1Gbps and could be reclocked later after link is up if necessary.

Fixes: 33a1a01e3afa ("net: stmmac: Add glue layer for T-HEAD TH1520 SoC")
Signed-off-by: Yao Zi <ziyao@disroot.org>
Reviewed-by: Drew Fustini <fustini@kernel.org>
Link: https://patch.msgid.link/20250815104803.55294-1-ziyao@disroot.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c

index f2946bea0bc2685bf22827abe6a51c33d88e0f0d..6c6c49e4b66fae853c67c79aa8957fe4bfb14ffa 100644 (file)
@@ -152,7 +152,7 @@ static int thead_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i,
 static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat)
 {
        struct thead_dwmac *dwmac = plat->bsp_priv;
-       u32 reg;
+       u32 reg, div;
 
        switch (plat->mac_interface) {
        case PHY_INTERFACE_MODE_MII:
@@ -164,6 +164,13 @@ static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat)
        case PHY_INTERFACE_MODE_RGMII_RXID:
        case PHY_INTERFACE_MODE_RGMII_TXID:
                /* use pll */
+               div = clk_get_rate(plat->stmmac_clk) / rgmii_clock(SPEED_1000);
+               reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) |
+                     FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div);
+
+               writel(0, dwmac->apb_base + GMAC_PLLCLK_DIV);
+               writel(reg, dwmac->apb_base + GMAC_PLLCLK_DIV);
+
                writel(GMAC_GTXCLK_SEL_PLL, dwmac->apb_base + GMAC_GTXCLK_SEL);
                reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN |
                      GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN;