]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: stmmac: eswin: fix HSP CSR init ordering after clock enable
authorZhi Li <lizhi2@eswincomputing.com>
Mon, 18 May 2026 02:20:55 +0000 (10:20 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 21 May 2026 09:58:16 +0000 (11:58 +0200)
Fix the initialization ordering of the HSP CSR configuration in the
EIC7700 DWMAC glue driver.

The HSP CSR registers control MAC-side RGMII delay behavior and must
only be accessed after the corresponding clocks are enabled. The
previous implementation could trigger register access before clock
enablement, leading to undefined behavior depending on boot state.

Move the HSP CSR configuration into the post-clock-enable initialization
path to ensure all register accesses occur under valid clock domains.

This change ensures deterministic initialization and prevents
clock-dependent register access failures during probe or resume.

Fixes: ea77dbbdbc4e ("net: stmmac: add Eswin EIC7700 glue driver")
Signed-off-by: Zhi Li <lizhi2@eswincomputing.com>
Link: https://patch.msgid.link/20260518022055.444-1-lizhi2@eswincomputing.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c

index bcb8e000e720b78f5a0aaf3fc067aa7d4e7ac475..63001c4acdb7ae91211e4ead370e09078433e4b8 100644 (file)
@@ -42,6 +42,11 @@ static const char * const eic7700_clk_names[] = {
 
 struct eic7700_qos_priv {
        struct plat_stmmacenet_data *plat_dat;
+       struct regmap *eic7700_hsp_regmap;
+       u32 eth_axi_lp_ctrl_offset;
+       u32 eth_phy_ctrl_offset;
+       u32 eth_clk_offset;
+       u32 eth_clk_dly_param;
 };
 
 static int eic7700_clks_config(void *priv, bool enabled)
@@ -61,8 +66,28 @@ static int eic7700_clks_config(void *priv, bool enabled)
 static int eic7700_dwmac_init(struct device *dev, void *priv)
 {
        struct eic7700_qos_priv *dwc = priv;
+       int ret;
+
+       ret = eic7700_clks_config(dwc, true);
+       if (ret)
+               return ret;
+
+       ret = regmap_set_bits(dwc->eic7700_hsp_regmap,
+                             dwc->eth_phy_ctrl_offset,
+                             EIC7700_ETH_TX_CLK_SEL |
+                             EIC7700_ETH_PHY_INTF_SELI);
+       if (ret) {
+               eic7700_clks_config(dwc, false);
+               return ret;
+       }
+
+       regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_axi_lp_ctrl_offset,
+                    EIC7700_ETH_CSYSREQ_VAL);
 
-       return eic7700_clks_config(dwc, true);
+       regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_clk_offset,
+                    dwc->eth_clk_dly_param);
+
+       return 0;
 }
 
 static void eic7700_dwmac_exit(struct device *dev, void *priv)
@@ -93,12 +118,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
        struct plat_stmmacenet_data *plat_dat;
        struct stmmac_resources stmmac_res;
        struct eic7700_qos_priv *dwc_priv;
-       struct regmap *eic7700_hsp_regmap;
-       u32 eth_axi_lp_ctrl_offset;
-       u32 eth_phy_ctrl_offset;
-       u32 eth_phy_ctrl_regset;
-       u32 eth_rxd_dly_offset;
-       u32 eth_dly_param = 0;
        u32 delay_ps;
        int i, ret;
 
@@ -121,8 +140,9 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
                                  "rx-internal-delay-ps", &delay_ps)) {
                u32 val = min(delay_ps / 100, EIC7700_MAX_DELAY_UNIT);
 
-               eth_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
-               eth_dly_param |= FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
+               dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
+               dwc_priv->eth_clk_dly_param |=
+                                FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
        } else {
                return dev_err_probe(&pdev->dev, -EINVAL,
                        "missing required property rx-internal-delay-ps\n");
@@ -133,53 +153,42 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
                                  "tx-internal-delay-ps", &delay_ps)) {
                u32 val = min(delay_ps / 100, EIC7700_MAX_DELAY_UNIT);
 
-               eth_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
-               eth_dly_param |= FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val);
+               dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
+               dwc_priv->eth_clk_dly_param |=
+                                FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val);
        } else {
                return dev_err_probe(&pdev->dev, -EINVAL,
                        "missing required property tx-internal-delay-ps\n");
        }
 
-       eic7700_hsp_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
-                                                            "eswin,hsp-sp-csr");
-       if (IS_ERR(eic7700_hsp_regmap))
+       dwc_priv->eic7700_hsp_regmap =
+                       syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                       "eswin,hsp-sp-csr");
+       if (IS_ERR(dwc_priv->eic7700_hsp_regmap))
                return dev_err_probe(&pdev->dev,
-                               PTR_ERR(eic7700_hsp_regmap),
+                               PTR_ERR(dwc_priv->eic7700_hsp_regmap),
                                "Failed to get hsp-sp-csr regmap\n");
 
        ret = of_property_read_u32_index(pdev->dev.of_node,
                                         "eswin,hsp-sp-csr",
-                                        1, &eth_phy_ctrl_offset);
+                                        1, &dwc_priv->eth_phy_ctrl_offset);
        if (ret)
                return dev_err_probe(&pdev->dev, ret,
                                     "can't get eth_phy_ctrl_offset\n");
 
-       regmap_read(eic7700_hsp_regmap, eth_phy_ctrl_offset,
-                   &eth_phy_ctrl_regset);
-       eth_phy_ctrl_regset |=
-               (EIC7700_ETH_TX_CLK_SEL | EIC7700_ETH_PHY_INTF_SELI);
-       regmap_write(eic7700_hsp_regmap, eth_phy_ctrl_offset,
-                    eth_phy_ctrl_regset);
-
        ret = of_property_read_u32_index(pdev->dev.of_node,
                                         "eswin,hsp-sp-csr",
-                                        2, &eth_axi_lp_ctrl_offset);
+                                        2, &dwc_priv->eth_axi_lp_ctrl_offset);
        if (ret)
                return dev_err_probe(&pdev->dev, ret,
                                     "can't get eth_axi_lp_ctrl_offset\n");
 
-       regmap_write(eic7700_hsp_regmap, eth_axi_lp_ctrl_offset,
-                    EIC7700_ETH_CSYSREQ_VAL);
-
        ret = of_property_read_u32_index(pdev->dev.of_node,
                                         "eswin,hsp-sp-csr",
-                                        3, &eth_rxd_dly_offset);
+                                        3, &dwc_priv->eth_clk_offset);
        if (ret)
                return dev_err_probe(&pdev->dev, ret,
-                                    "can't get eth_rxd_dly_offset\n");
-
-       regmap_write(eic7700_hsp_regmap, eth_rxd_dly_offset,
-                    eth_dly_param);
+                                    "can't get eth_clk_offset\n");
 
        plat_dat->num_clks = ARRAY_SIZE(eic7700_clk_names);
        plat_dat->clks = devm_kcalloc(&pdev->dev,