[PATCH v2 2/3] clk: socfpga: agilex5: register the SP timer clocks early

From: Adrian Ng Ho Yin

Date: Fri Oct 02 2026 - 06:35:29 EST


The DW APB timers are probed through TIMER_OF_DECLARE() from time_init()
and cannot defer, but the clock manager is a platform driver registered
at core_initcall(). The timer's clk_get() therefore fails and the timer
is never brought up.

Register only l4_sp_clk and its parents (boot_clk, main_pll, periph_pll,
main_pll_c3, peri_pll_c1 and noc_free_clk) from of_clk_init() using
CLK_OF_DECLARE_DRIVER(), with every other clock left as -EPROBE_DEFER.
The remaining clocks are still registered when the platform driver
probes, which reuses the early provider.

Signed-off-by: Adrian Ng Ho Yin <adrian.ho.yin.ng@xxxxxxxxxx>
---
drivers/clk/socfpga/clk-agilex5.c | 138 +++++++++++++++++++++++-------
1 file changed, 109 insertions(+), 29 deletions(-)

diff --git a/drivers/clk/socfpga/clk-agilex5.c b/drivers/clk/socfpga/clk-agilex5.c
index f7f0ad884f64..e439950dd6da 100644
--- a/drivers/clk/socfpga/clk-agilex5.c
+++ b/drivers/clk/socfpga/clk-agilex5.c
@@ -5,7 +5,9 @@
*/
#include <linux/slab.h>
#include <linux/clk-provider.h>
+#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/intel,agilex5-clkmgr.h>
#include "stratix10-clk.h"
@@ -233,7 +235,29 @@ static const struct agilex5_pll_clock agilex5_pll_clks[] = {
},
};

-/* Main PLL C0, C1, C2, C3 and Peri PLL C0, C1, C2, C3. With ping-pong counter. */
+/*
+ * The SP timers are probed from time_init() and cannot defer, so their
+ * l4_sp_clk and its parents are registered from of_clk_init(). Everything
+ * else is registered when the platform driver probes.
+ */
+static const struct stratix10_perip_c_clock agilex5_early_perip_c_clks[] = {
+ { AGILEX5_MAIN_PLL_C3_CLK, "main_pll_c3", "main_pll", NULL, 1, 0,
+ 0x68 },
+ { AGILEX5_PERIPH_PLL_C1_CLK, "peri_pll_c1", "periph_pll", NULL, 1, 0,
+ 0xB4 },
+};
+
+static const struct agilex5_perip_cnt_clock agilex5_early_perip_cnt_clks[] = {
+ { AGILEX5_NOC_FREE_CLK, "noc_free_clk", noc_free_mux,
+ ARRAY_SIZE(noc_free_mux), 0, 0x40, 0, 0, 0 },
+};
+
+static const struct agilex5_gate_clock agilex5_early_gate_clks[] = {
+ { AGILEX5_L4_SP_CLK, "l4_sp_clk", noc_mux, ARRAY_SIZE(noc_mux),
+ CLK_IS_CRITICAL, 0x24, 3, 0x44, 6, 2, 0x30, 1, 0 },
+};
+
+/* Main PLL C0, C1, C2 and Peri PLL C0, C2, C3. With ping-pong counter. */
static const struct stratix10_perip_c_clock agilex5_main_perip_c_clks[] = {
{ AGILEX5_MAIN_PLL_C0_CLK, "main_pll_c0", "main_pll", NULL, 1, 0,
0x5C },
@@ -241,12 +265,8 @@ static const struct stratix10_perip_c_clock agilex5_main_perip_c_clks[] = {
0x60 },
{ AGILEX5_MAIN_PLL_C2_CLK, "main_pll_c2", "main_pll", NULL, 1, 0,
0x64 },
- { AGILEX5_MAIN_PLL_C3_CLK, "main_pll_c3", "main_pll", NULL, 1, 0,
- 0x68 },
{ AGILEX5_PERIPH_PLL_C0_CLK, "peri_pll_c0", "periph_pll", NULL, 1, 0,
0xB0 },
- { AGILEX5_PERIPH_PLL_C1_CLK, "peri_pll_c1", "periph_pll", NULL, 1, 0,
- 0xB4 },
{ AGILEX5_PERIPH_PLL_C2_CLK, "peri_pll_c2", "periph_pll", NULL, 1, 0,
0xB8 },
{ AGILEX5_PERIPH_PLL_C3_CLK, "peri_pll_c3", "periph_pll", NULL, 1, 0,
@@ -265,8 +285,6 @@ static const struct agilex5_perip_cnt_clock agilex5_main_perip_cnt_clks[] = {
ARRAY_SIZE(core3_free_mux), 0, 0x0110, 0, 0, 0},
{ AGILEX5_DSU_FREE_CLK, "dsu_free_clk", dsu_free_mux,
ARRAY_SIZE(dsu_free_mux), 0, 0xfc, 0, 0, 0},
- { AGILEX5_NOC_FREE_CLK, "noc_free_clk", noc_free_mux,
- ARRAY_SIZE(noc_free_mux), 0, 0x40, 0, 0, 0 },
{ AGILEX5_EMAC_A_FREE_CLK, "emaca_free_clk", emaca_free_mux,
ARRAY_SIZE(emaca_free_mux), 0, 0xD4, 0, 0x88, 0 },
{ AGILEX5_EMAC_B_FREE_CLK, "emacb_free_clk", emacb_free_mux,
@@ -313,8 +331,6 @@ static const struct agilex5_gate_clock agilex5_gate_clks[] = {
0x24, 2, 0x44, 4, 2, 0x30, 1, 0 },
{ AGILEX5_L4_SYS_FREE_CLK, "l4_sys_free_clk", noc_mux,
ARRAY_SIZE(noc_mux), 0, 0, 0, 0x44, 2, 2, 0x30, 1, 0 },
- { AGILEX5_L4_SP_CLK, "l4_sp_clk", noc_mux, ARRAY_SIZE(noc_mux),
- CLK_IS_CRITICAL, 0x24, 3, 0x44, 6, 2, 0x30, 1, 0 },

/* Core sight clocks*/
{ AGILEX5_CS_AT_CLK, "cs_at_clk", noc_mux, ARRAY_SIZE(noc_mux), 0,
@@ -486,35 +502,92 @@ static int agilex5_clk_register_pll(const struct agilex5_pll_clock *clks,
return 0;
}

-static int agilex5_clkmgr_init(struct platform_device *pdev)
+static struct stratix10_clock_data *agilex5_clk_data;
+
+static struct stratix10_clock_data *agilex5_clk_data_alloc(void __iomem *base)
{
- struct device_node *np = pdev->dev.of_node;
- struct device *dev = &pdev->dev;
struct stratix10_clock_data *clk_data;
- void __iomem *base;
- int i, num_clks;
-
- base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- num_clks = AGILEX5_NUM_CLKS;
+ int i;

- clk_data = devm_kzalloc(dev, struct_size(clk_data, clk_data.hws,
- num_clks), GFP_KERNEL);
+ clk_data = kzalloc(struct_size(clk_data, clk_data.hws, AGILEX5_NUM_CLKS),
+ GFP_KERNEL);
if (!clk_data)
- return -ENOMEM;
+ return NULL;

clk_data->base = base;
- clk_data->clk_data.num = num_clks;
+ clk_data->clk_data.num = AGILEX5_NUM_CLKS;
+
+ for (i = 0; i < AGILEX5_NUM_CLKS; i++)
+ clk_data->clk_data.hws[i] = ERR_PTR(-EPROBE_DEFER);

- for (i = 0; i < num_clks; i++)
- clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT);
+ return clk_data;
+}

+static void agilex5_clk_register_early(struct stratix10_clock_data *clk_data)
+{
agilex5_clk_register_pll(agilex5_pll_clks, ARRAY_SIZE(agilex5_pll_clks),
clk_data);

- /* mainPLL C0, C1, C2, C3 and periph PLL C0, C1, C2, C3*/
+ agilex5_clk_register_c_perip(agilex5_early_perip_c_clks,
+ ARRAY_SIZE(agilex5_early_perip_c_clks),
+ clk_data);
+
+ agilex5_clk_register_cnt_perip(agilex5_early_perip_cnt_clks,
+ ARRAY_SIZE(agilex5_early_perip_cnt_clks),
+ clk_data);
+
+ agilex5_clk_register_gate(agilex5_early_gate_clks,
+ ARRAY_SIZE(agilex5_early_gate_clks), clk_data);
+}
+
+static void __init agilex5_clkmgr_early_init(struct device_node *np)
+{
+ struct stratix10_clock_data *clk_data;
+ void __iomem *base;
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("%s: failed to map clock registers\n", __func__);
+ return;
+ }
+
+ clk_data = agilex5_clk_data_alloc(base);
+ if (!clk_data) {
+ iounmap(base);
+ return;
+ }
+
+ agilex5_clk_register_early(clk_data);
+
+ if (of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data->clk_data)) {
+ pr_err("%s: failed to add clock provider\n", __func__);
+ return;
+ }
+
+ agilex5_clk_data = clk_data;
+}
+
+CLK_OF_DECLARE_DRIVER(agilex5_clkmgr, "intel,agilex5-clkmgr",
+ agilex5_clkmgr_early_init);
+
+static int agilex5_clkmgr_init(struct platform_device *pdev)
+{
+ struct stratix10_clock_data *clk_data = agilex5_clk_data;
+ void __iomem *base;
+ int i;
+
+ if (!clk_data) {
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ clk_data = agilex5_clk_data_alloc(base);
+ if (!clk_data)
+ return -ENOMEM;
+
+ agilex5_clk_register_early(clk_data);
+ }
+
agilex5_clk_register_c_perip(agilex5_main_perip_c_clks,
ARRAY_SIZE(agilex5_main_perip_c_clks),
clk_data);
@@ -526,8 +599,15 @@ static int agilex5_clkmgr_init(struct platform_device *pdev)
agilex5_clk_register_gate(agilex5_gate_clks,
ARRAY_SIZE(agilex5_gate_clks), clk_data);

- of_clk_add_hw_provider(np, of_clk_hw_onecell_get, &clk_data->clk_data);
- return 0;
+ for (i = 0; i < AGILEX5_NUM_CLKS; i++)
+ if (clk_data->clk_data.hws[i] == ERR_PTR(-EPROBE_DEFER))
+ clk_data->clk_data.hws[i] = ERR_PTR(-ENOENT);
+
+ if (clk_data == agilex5_clk_data)
+ return 0;
+
+ return of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
+ &clk_data->clk_data);
}

static int agilex5_clkmgr_probe(struct platform_device *pdev)
--
2.49.GIT