From 98913d8b8dc64cb1af9a5937a578e8b7e884731c Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 24 Jul 2026 11:03:54 +0200 Subject: [PATCH 001/168] clk: renesas: Clean-up simple provider misuse of the consumer API Clock provider should not be using the consumer interface. In other words, a provider should not be dealing with struct clk. This change targets occurrences for which the provider uses the consumer interface and corresponding clk_hw interface exist. Reviewed-by: Brian Masney Signed-off-by: Jerome Brunet Reviewed-by: Thierry Reding Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260724-clk-provider-simple-clean-v2-3-56f306156d25@baylibre.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a06g032-clocks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c index 076f587dfd39..1da25e4fb4d7 100644 --- a/drivers/clk/renesas/r9a06g032-clocks.c +++ b/drivers/clk/renesas/r9a06g032-clocks.c @@ -1014,7 +1014,7 @@ r9a06g032_div_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) if (clk->index == R9A06G032_DIV_UART || clk->index == R9A06G032_DIV_P2_PG) { pr_devel("%s div uart hack!\n", __func__); - req->rate = clk_get_rate(hw->clk); + req->rate = clk_hw_get_rate(hw); return 0; } req->rate = DIV_ROUND_UP(req->best_parent_rate, div); From 3f6d270694aa1b6bda8af637f40ea4210911a57c Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 11 Aug 2026 19:27:14 +0100 Subject: [PATCH 002/168] clk: renesas: rzg2l: Add DSI divider clock support for RZ/G3L Add a new DSI divider clock type (CLK_TYPE_G3L_PLLDSI_DIV) for the RZ/G3L SoC, which requires a different divider implementation than the existing RZ/G2L DSI divider clock. The RZ/G3L DSI divider uses two cascaded dividers, DIV_DSI_A and DIV_DSI_B, where the effective divider is: rate = parent_rate / ((1 << div_a) * (div_b + 1)) DIV_DSI_A is a power-of-two divider with values in the range [0, 5], and DIV_DSI_B is a linear divider with values in the range [1, 16]. Introduce the g3l_dsi_div_hw_data structure, rzg3l_cpg_dsi_div_ops, and rzg3l_cpg_dsi_div_clk_register() to implement the new clock type, and add the DEF_G3L_PLLDSI_DIV() macro for use in clock table definitions. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260811182729.360959-2-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 126 ++++++++++++++++++++++++++++++++ drivers/clk/renesas/rzg2l-cpg.h | 5 ++ 2 files changed, 131 insertions(+) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index a899c37dd4cd..787e3a8990c9 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -67,6 +67,12 @@ #define CPG_PLL_MON_LOCK BIT(4) #define CPG_PLL_MON_RESETB BIT(0) +#define DIV_DSI_A_SET GENMASK(2, 0) +#define DIV_DSI_B_SET GENMASK(7, 4) + +#define RZG3L_SDIV_DIV_DSI_A_WEN BIT(16) +#define RZG3L_SDIV_DIV_DSI_B_WEN BIT(20) + #define CLK_ON_R(reg) (reg) #define CLK_MON_R(reg) (0x180 + (reg)) #define CLK_RST_R(reg) (reg) @@ -833,6 +839,123 @@ rzg2l_cpg_dsi_div_clk_register(const struct cpg_core_clk *core, return clk_hw->clk; } +struct g3l_dsi_div_hw_data { + struct clk_hw hw; + struct rzg2l_cpg_priv *priv; + unsigned long rate; + u32 off; + u8 div_a; + u8 div_b; +}; + +#define to_g3l_dsi_div_hw_data(_hw) container_of(_hw, struct g3l_dsi_div_hw_data, hw) + +static unsigned long rzg3l_cpg_dsi_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct g3l_dsi_div_hw_data *dsi_div = to_g3l_dsi_div_hw_data(hw); + struct rzg2l_cpg_priv *priv = dsi_div->priv; + int div_a, div_b, val; + + val = readl(priv->base + dsi_div->off); + div_a = FIELD_GET(DIV_DSI_A_SET, val); + div_b = FIELD_GET(DIV_DSI_B_SET, val); + + return DIV_ROUND_CLOSEST_ULL((u64)parent_rate, (div_b + 1) << div_a); +} + +static int rzg3l_cpg_dsi_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct g3l_dsi_div_hw_data *dsi_div = to_g3l_dsi_div_hw_data(hw); + struct rzg2l_cpg_priv *priv = dsi_div->priv; + unsigned int divider = dsi_div_ab_desired; + unsigned int div_b_max = dsi_div_target ? 15 : 0; + bool divider_found = false; + + for (unsigned int i = 0; i <= 5 && !divider_found; i++) { + unsigned int div_a = 5 - i; + + for (unsigned int div_b = 0; div_b <= div_b_max; div_b++) { + divider = (div_b + 1) << div_a; + if (divider == dsi_div_ab_desired) { + dsi_div->div_a = div_a; + dsi_div->div_b = div_b; + divider_found = true; + break; + } + } + } + + if (!divider_found) { + dev_err(priv->dev, "failed dsi div for: %u\n", divider); + return -EINVAL; + } + + req->best_parent_rate = req->rate * divider; + + return 0; +} + +static int rzg3l_cpg_dsi_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct g3l_dsi_div_hw_data *dsi_div = to_g3l_dsi_div_hw_data(hw); + struct rzg2l_cpg_priv *priv = dsi_div->priv; + + writel(RZG3L_SDIV_DIV_DSI_A_WEN | RZG3L_SDIV_DIV_DSI_B_WEN | + FIELD_PREP(DIV_DSI_A_SET, dsi_div->div_a) | + FIELD_PREP(DIV_DSI_B_SET, dsi_div->div_b), + priv->base + dsi_div->off); + + return 0; +} + +static const struct clk_ops rzg3l_cpg_dsi_div_ops = { + .recalc_rate = rzg3l_cpg_dsi_div_recalc_rate, + .determine_rate = rzg3l_cpg_dsi_div_determine_rate, + .set_rate = rzg3l_cpg_dsi_div_set_rate, +}; + +static struct clk * __init +rzg3l_cpg_dsi_div_clk_register(const struct cpg_core_clk *core, + struct rzg2l_cpg_priv *priv) +{ + struct g3l_dsi_div_hw_data *clk_hw_data; + const struct clk *parent; + const char *parent_name; + struct clk_init_data init; + struct clk_hw *clk_hw; + int ret; + + parent = priv->clks[core->parent]; + if (IS_ERR(parent)) + return ERR_CAST(parent); + + clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL); + if (!clk_hw_data) + return ERR_PTR(-ENOMEM); + + clk_hw_data->priv = priv; + clk_hw_data->off = core->conf; + + parent_name = __clk_get_name(parent); + init.name = core->name; + init.ops = &rzg3l_cpg_dsi_div_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = &parent_name; + init.num_parents = 1; + + clk_hw = &clk_hw_data->hw; + clk_hw->init = &init; + + ret = devm_clk_hw_register(priv->dev, clk_hw); + if (ret) + return ERR_PTR(ret); + + return clk_hw->clk; +} + struct pll5_mux_hw_data { struct clk_hw hw; u32 conf; @@ -1340,6 +1463,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, case CLK_TYPE_DSI_DIV: clk = rzg2l_cpg_dsi_div_clk_register(core, priv); break; + case CLK_TYPE_G3L_DSI_DIV: + clk = rzg3l_cpg_dsi_div_clk_register(core, priv); + break; default: goto fail; } diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index bd6169f62538..24642a089b6c 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -142,6 +142,8 @@ enum clk_types { /* Clock for DSI divider */ CLK_TYPE_DSI_DIV, + /* Clock for G3L DSI divider */ + CLK_TYPE_G3L_DSI_DIV, }; #define DEF_TYPE(_name, _id, _type...) \ @@ -201,6 +203,9 @@ enum clk_types { .num_parents = ARRAY_SIZE(_parent_names)) #define DEF_DSI_DIV(_name, _id, _parent, _flag) \ DEF_TYPE(_name, _id, CLK_TYPE_DSI_DIV, .parent = _parent, .flag = _flag) +#define DEF_G3L_DSI_DIV(_name, _id, _parent, _conf) \ + DEF_TYPE(_name, _id, CLK_TYPE_G3L_DSI_DIV, .parent = _parent, .conf = _conf, \ + .flag = CLK_SET_RATE_PARENT) /** * struct rzg2l_mod_clk - Module Clocks definitions From b330b829509e38665b6bb929238bfaa8b80b6996 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 11 Aug 2026 19:27:15 +0100 Subject: [PATCH 003/168] clk: renesas: rzg2l: Add PLL7 DSI clock support for RZ/G3L MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new fractional PLL clock type (CLK_TYPE_G3L_PLLDSI) for the RZ/G3L SoC's PLL7, which drives the DSI interface and requires a dedicated parameter calculation and programming sequence distinct from other PLLs in the RZ/G2L family. PLL7 output frequency is determined by the formula: Ffdco = (NIR + NFR / 4096) * (Fosc / MR) Ffout = Ffdco / (1 << PR) where: - Fosc = 24 MHz (oscillator input) - PR in [0, 4] (post divider, power-of-two) - MR in [1, 12] (input pre-divider) - NIR in [56, 375], NFR in [0, 4095] (integer and fractional parts) The FDCO must fall within one of two valid ranges: 900–2000 MHz (rangesel=0) or 2000–3000 MHz (rangesel=1). The parameter search in rzg3l_dsi_get_pll_parameters_values() iterates over all valid (MR, PR) combinations, filtering by the required FPFD range of 8–16 MHz, then delegates to rzg3l_dsi_compute_pll_parameters() to find the NIR/NFR pair that best approximates the requested rate. An exact match returns immediately; otherwise the combination with the smallest absolute frequency error is used. Computed parameters are cached in pll7_dsi_params within pll_clk to avoid redundant recalculation in determine_rate() when the requested rate has not changed. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260811182729.360959-3-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 231 ++++++++++++++++++++++++++++++++ drivers/clk/renesas/rzg2l-cpg.h | 5 + 2 files changed, 236 insertions(+) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 787e3a8990c9..cb4a7c3cd3aa 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -73,6 +73,11 @@ #define RZG3L_SDIV_DIV_DSI_A_WEN BIT(16) #define RZG3L_SDIV_DIV_DSI_B_WEN BIT(20) +#define CPG_PLL_CLK1_DIV_NF GENMASK(12, 1) +#define CPG_PLL_CLK1_DIV_NI GENMASK(21, 13) +#define CPG_PLL_CLK1_DIV_M GENMASK(25, 22) +#define CPG_PLL_CLK1_DIV_P GENMASK(28, 26) + #define CLK_ON_R(reg) (reg) #define CLK_MON_R(reg) (0x180 + (reg)) #define CLK_RST_R(reg) (reg) @@ -98,6 +103,26 @@ #define PLL5_HSCLK_MIN 10000000 #define PLL5_HSCLK_MAX 187500000 +#define RZG3L_OSC_CLK (24 * MEGA) +#define RZG3L_PLL7_FDCO_RANGE_0_MIN (900 * MEGA) +#define RZG3L_PLL7_FDCO_RANGE_0_MAX (2000 * MEGA) +#define RZG3L_PLL7_FDCO_RANGE_1_MIN (2000 * MEGA) +#define RZG3L_PLL7_FDCO_RANGE_1_MAX (3000ULL * MEGA) +#define RZG3L_PLL7_PR_MIN (0) +#define RZG3L_PLL7_PR_MAX (4) +#define RZG3L_PLL7_MR_MIN (0) +#define RZG3L_PLL7_MR_MAX (11) +#define RZG3L_PLL7_NIR_MIN (55) +#define RZG3L_PLL7_NIR_MAX (374) +#define RZG3L_PLL7_NFR_MIN (0) +#define RZG3L_PLL7_NFR_MAX (4095) +#define RZG3L_PLL7_NR_MIN (56250) /* Multiplied value 56.25 * 1000 */ +#define RZG3L_PLL7_NR_MAX (375000) /* Multiplied value 375 * 1000 */ +#define RZG3L_PLL7_MULT_MIN (293) /* Multiplied value 0.293 * 1000 */ +#define RZG3L_PLL7_MULT_MAX (375000) /* Multiplied value 375 * 1000 */ +#define RZG3L_PLL7_FSTD_DIV_MR_MIN (8 * MEGA) +#define RZG3L_PLL7_FSTD_DIV_MR_MAX (16 * MEGA) + /** * struct clk_hw_data - clock hardware data * @hw: clock hw @@ -1187,6 +1212,15 @@ rzg2l_cpg_sipll5_register(const struct cpg_core_clk *core, return clk_hw->clk; } +/* RZ/G3L PLL7 parameters */ +struct rzg3l_plldsi_parameters { + s64 error_millihz; + u64 freq_millihz; + u16 nir, nfr; + u8 rangesel; + u8 pr, mr; +}; + struct pll_clk { struct clk_hw hw; unsigned long default_rate; @@ -1194,6 +1228,7 @@ struct pll_clk { unsigned int type; void __iomem *base; struct rzg2l_cpg_priv *priv; + struct rzg3l_plldsi_parameters pll7_dsi_params; }; #define to_pll(_hw) container_of(_hw, struct pll_clk, hw) @@ -1353,6 +1388,199 @@ static const struct clk_ops rzg3l_cpg_pll_ops = { .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate, }; +static inline bool +rzg3l_dsi_compute_pll_parameters(struct rzg3l_plldsi_parameters *pars, + struct rzg3l_plldsi_parameters *p, + struct rzg3l_plldsi_parameters *best, + u64 freq_millihz, u32 fpfd, u32 pr) +{ + for (p->nir = RZG3L_PLL7_NIR_MIN; p->nir <= RZG3L_PLL7_NIR_MAX; p->nir++) { + u64 output_nir, output_nfr_range; + s64 nfr, output_nfr; + u64 fdco, output; + u64 nr_div_mr_pr; + + /* + * The frequency generated by the PLL is calculated as follows: + * + * With: + * Freq = Ffout = Ffdco / pr + * input frequency(fstd) = 24MHz + * fpfd = fstd / mr + * nr = nir + nfr / 4096 + * Ffdco = nr * fpfd + * Ffdco = (nir + (nfr / 4096)) * fpfd + * + * Freq can also be rewritten as: + * Freq = Ffdco / pr + * = (nir * fpfd) / pr + ((nfr / 4096) * fpfd) / pr + * = output_nir + output_nfr + * + * Every parameter has been determined at this point, but nfr. + * Considering that: + * 0 <= nfr <= 4095 + * Then: + * 0 <= (nfr / 4096) < 1 + * Therefore: + * 0 <= output_nfr < fpfd / pr + */ + + /* Compute output nir component (in mHz) */ + output_nir = DIV_ROUND_CLOSEST_ULL(mul_u32_u32((p->nir + 1) * MILLI, fpfd), pr); + /* Compute range for output nfr (in mHz) */ + output_nfr_range = DIV_ROUND_CLOSEST_ULL(mul_u32_u32(fpfd, MILLI), pr); + /* No point in continuing if we can't achieve the desired frequency */ + if (freq_millihz < output_nir || freq_millihz >= (output_nir + output_nfr_range)) + continue; + + /* + * Compute the nfr component + * + * Since: + * Freq = output_nir + output_nfr + * Then: + * output_nfr = Freq - output_nir + * = ((nfr / 4096) * fpfd) / pr + * Therefore: + * nfr = (output_nfr * 4096 * pr) / fpfd + */ + output_nfr = freq_millihz - output_nir; + nfr = div_s64(output_nfr * 4096 * pr, fpfd); + nfr = DIV_S64_ROUND_CLOSEST(nfr, 1000); + + /* Validate nfr value within allowed limits */ + if (nfr < RZG3L_PLL7_NFR_MIN || nfr > RZG3L_PLL7_NFR_MAX) + continue; + + p->nfr = nfr; + + /* Compute (Ffdco * 4096) */ + output = mul_u32_u32(p->nir + 1, 4096); + fdco = (output + p->nfr) * fpfd; + if (fdco < (RZG3L_PLL7_FDCO_RANGE_0_MIN * 4096ULL) || + fdco > (RZG3L_PLL7_FDCO_RANGE_1_MAX * 4096ULL)) + continue; + + if (fdco <= (RZG3L_PLL7_FDCO_RANGE_0_MAX * 4096ULL)) + p->rangesel = 0; + else + p->rangesel = 1; + + /* compute the nr and magnify by 1000 */ + output = mul_u32_u32(p->nir + 1, 4096); + output += p->nfr; + output *= 1000; + nr_div_mr_pr = div_u64(output, 4096); + if (nr_div_mr_pr < RZG3L_PLL7_NR_MIN || nr_div_mr_pr > RZG3L_PLL7_NR_MAX) + continue; + + /* compute the magnified multipier = nr(magnified)/(mr *pr) */ + nr_div_mr_pr = div_u64(nr_div_mr_pr, (p->mr + 1) * pr); + if (nr_div_mr_pr < RZG3L_PLL7_MULT_MIN || nr_div_mr_pr > RZG3L_PLL7_MULT_MAX) + continue; + + output *= RZG3L_OSC_CLK; + output = div_u64(output, (p->mr + 1) * pr * 4096); + + p->error_millihz = freq_millihz - output; + p->freq_millihz = output; + + /* If an exact match is found, return immediately */ + if (p->error_millihz == 0) { + *pars = *p; + return true; + } + + /* Update best match if error is smaller */ + if (abs(p->error_millihz) < abs(best->error_millihz)) + *best = *p; + } + + return false; +} + +static bool +rzg3l_dsi_get_pll_parameters_values(struct rzg3l_plldsi_parameters *pars, + u64 freq_millihz) +{ + struct rzg3l_plldsi_parameters p, best; + + /* Initialize best error to maximum possible value */ + best.error_millihz = S64_MAX; + p.error_millihz = S64_MAX; + for (p.mr = RZG3L_PLL7_MR_MIN; p.mr <= RZG3L_PLL7_MR_MAX; p.mr++) { + u32 fpfd = RZG3L_OSC_CLK / (p.mr + 1); + + if (fpfd > RZG3L_PLL7_FSTD_DIV_MR_MAX || fpfd < RZG3L_PLL7_FSTD_DIV_MR_MIN) + continue; + + for (p.pr = RZG3L_PLL7_PR_MIN; p.pr <= RZG3L_PLL7_PR_MAX; p.pr++) + if (rzg3l_dsi_compute_pll_parameters(pars, &p, &best, + freq_millihz, fpfd, 1 << p.pr)) + return true; + } + + /* If no valid parameters were found, return false */ + if (best.error_millihz == S64_MAX) + return false; + + *pars = best; + return true; +} + +static int rzg3l_cpg_plldsi_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + struct pll_clk *pll_clk = to_pll(hw); + struct rzg2l_cpg_priv *priv = pll_clk->priv; + struct rzg3l_plldsi_parameters *pll7_dsi_params = &pll_clk->pll7_dsi_params; + u64 rate_millihz; + + rate_millihz = mul_u32_u32(req->rate, MILLI); + if (rate_millihz == pll7_dsi_params->error_millihz + pll7_dsi_params->freq_millihz) + goto exit_determine_rate; + + if (!rzg3l_dsi_get_pll_parameters_values(pll7_dsi_params, rate_millihz)) { + dev_err(priv->dev, "failed %s for req->rate: %lu\n", __func__, req->rate); + return -EINVAL; + } + +exit_determine_rate: + req->rate = DIV_ROUND_CLOSEST_ULL(pll7_dsi_params->freq_millihz, MILLI); + return 0; +} + +static int rzg3l_cpg_plldsi_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct pll_clk *pll_clk = to_pll(hw); + struct rzg3l_plldsi_parameters *dsi_dividers = &pll_clk->pll7_dsi_params; + u32 val; + + /* Put PLL into standby mode */ + rzg3l_cpg_pll_clk_endisable(hw, false); + + /* Output clock setting 1 */ + val = FIELD_PREP(CPG_PLL_CLK1_DIV_P, dsi_dividers->pr) | + FIELD_PREP(CPG_PLL_CLK1_DIV_M, dsi_dividers->mr) | + FIELD_PREP(CPG_PLL_CLK1_DIV_NI, dsi_dividers->nir) | + FIELD_PREP(CPG_PLL_CLK1_DIV_NF, dsi_dividers->nfr) | + dsi_dividers->rangesel; + writel(val, pll_clk->base + CPG_PLL_CLK1_OFFSET(pll_clk->conf)); + + /* Put PLL to normal mode */ + rzg3l_cpg_pll_clk_endisable(hw, true); + + return 0; +}; + +static const struct clk_ops rzg3l_cpg_plldsi_ops = { + .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate, + .determine_rate = rzg3l_cpg_plldsi_determine_rate, + .set_rate = rzg3l_cpg_plldsi_set_rate, + .is_enabled = rzg3l_cpg_pll_clk_is_enabled, + .enable = rzg3l_cpg_pll_clk_enable, +}; + static struct clk *rzg2l_cpg_clk_src_twocell_get(struct of_phandle_args *clkspec, void *data) @@ -1466,6 +1694,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, case CLK_TYPE_G3L_DSI_DIV: clk = rzg3l_cpg_dsi_div_clk_register(core, priv); break; + case CLK_TYPE_G3L_PLLDSI: + clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg3l_cpg_plldsi_ops); + break; default: goto fail; } diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 24642a089b6c..41e8f389c566 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -142,6 +142,9 @@ enum clk_types { /* Clock for DSI divider */ CLK_TYPE_DSI_DIV, + /* Clock for G3L DSI PLL */ + CLK_TYPE_G3L_PLLDSI, + /* Clock for G3L DSI divider */ CLK_TYPE_G3L_DSI_DIV, }; @@ -206,6 +209,8 @@ enum clk_types { #define DEF_G3L_DSI_DIV(_name, _id, _parent, _conf) \ DEF_TYPE(_name, _id, CLK_TYPE_G3L_DSI_DIV, .parent = _parent, .conf = _conf, \ .flag = CLK_SET_RATE_PARENT) +#define DEF_G3L_PLLDSI(_name, _id, _parent, _conf) \ + DEF_TYPE(_name, _id, CLK_TYPE_G3L_PLLDSI, .parent = _parent, .conf = _conf) /** * struct rzg2l_mod_clk - Module Clocks definitions From 0871ed3a494f8c542d6b7509be3c25dc36abc0c1 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 11 Aug 2026 19:27:16 +0100 Subject: [PATCH 004/168] clk: renesas: rzg2l: Rename cpg_core_clk::flag to core_flags Rename the 'flag' member of struct cpg_core_clk to 'core_flags' for clarity and to better distinguish it from mux_flags. Update all users and DEF_* macros accordingly. No functional change. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260811182729.360959-4-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 10 +++++----- drivers/clk/renesas/rzg2l-cpg.h | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index cb4a7c3cd3aa..59a4d774f0cf 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -433,7 +433,7 @@ rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct rzg2l_cpg_pri return ERR_PTR(-ENOMEM); init.name = core->name; - init.flags = core->flag; + init.flags = core->core_flags; init.ops = &rzg3s_div_clk_ops; init.parent_names = &parent_name; init.num_parents = 1; @@ -491,7 +491,7 @@ rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, base + GET_REG_OFFSET(core->conf), GET_SHIFT(core->conf), GET_WIDTH(core->conf), - core->flag, + core->core_flags, core->dtable, &priv->rmw_lock); else @@ -500,7 +500,7 @@ rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, base + GET_REG_OFFSET(core->conf), GET_SHIFT(core->conf), GET_WIDTH(core->conf), - core->flag, &priv->rmw_lock); + core->core_flags, &priv->rmw_lock); if (IS_ERR(clk_hw)) return ERR_CAST(clk_hw); @@ -516,7 +516,7 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, clk_hw = devm_clk_hw_register_mux(priv->dev, core->name, core->parent_names, core->num_parents, - core->flag, + core->core_flags, priv->base + GET_REG_OFFSET(core->conf), GET_SHIFT(core->conf), GET_WIDTH(core->conf), @@ -595,7 +595,7 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, init.name = core->name; init.ops = &rzg2l_cpg_sd_clk_mux_ops; - init.flags = core->flag; + init.flags = core->core_flags; init.num_parents = core->num_parents; init.parent_names = core->parent_names; diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 41e8f389c566..38db209aabf9 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -110,7 +110,7 @@ struct cpg_core_clk { }; const char * const *parent_names; notifier_fn_t notifier; - u32 flag; + u32 core_flags; u32 mux_flags; int num_parents; }; @@ -168,24 +168,24 @@ enum clk_types { #define DEF_DIV(_name, _id, _parent, _conf, _dtable) \ DEF_TYPE(_name, _id, CLK_TYPE_DIV, .conf = _conf, \ .parent = _parent, .dtable = _dtable, \ - .flag = CLK_DIVIDER_HIWORD_MASK) + .core_flags = CLK_DIVIDER_HIWORD_MASK) #define DEF_DIV_RO(_name, _id, _parent, _conf, _dtable) \ DEF_TYPE(_name, _id, CLK_TYPE_DIV, .conf = _conf, \ .parent = _parent, .dtable = _dtable, \ - .flag = CLK_DIVIDER_READ_ONLY) + .core_flags = CLK_DIVIDER_READ_ONLY) #define DEF_G3S_DIV(_name, _id, _parent, _conf, _sconf, _dtable, _invalid_rate, \ _max_rate, _clk_flags, _notif) \ DEF_TYPE(_name, _id, CLK_TYPE_G3S_DIV, .conf = _conf, .sconf = _sconf, \ .parent = _parent, .dtable = _dtable, \ .invalid_rate = _invalid_rate, \ - .max_rate = _max_rate, .flag = (_clk_flags), \ + .max_rate = _max_rate, .core_flags = (_clk_flags), \ .notifier = _notif) -#define DEF_MUX_FLAGS(_name, _id, _conf, _parent_names, _flag) \ +#define DEF_MUX_FLAGS(_name, _id, _conf, _parent_names, _flags) \ DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = _conf, \ .parent_names = _parent_names, \ .num_parents = ARRAY_SIZE(_parent_names), \ .mux_flags = CLK_MUX_HIWORD_MASK, \ - .flag = _flag) + .core_flags = _flags) #define DEF_MUX(_name, _id, _conf, _parent_names) \ DEF_MUX_FLAGS(_name, _id, _conf, _parent_names, 0) #define DEF_MUX_RO(_name, _id, _conf, _parent_names) \ @@ -197,18 +197,18 @@ enum clk_types { DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, .sconf = _sconf, \ .parent_names = _parent_names, \ .num_parents = ARRAY_SIZE(_parent_names), \ - .mtable = _mtable, .flag = _clk_flags, .notifier = _notifier) + .mtable = _mtable, .core_flags = _clk_flags, .notifier = _notifier) #define DEF_PLL5_FOUTPOSTDIV(_name, _id, _parent) \ DEF_TYPE(_name, _id, CLK_TYPE_SIPLL5, .parent = _parent) #define DEF_PLL5_4_MUX(_name, _id, _conf, _parent_names) \ DEF_TYPE(_name, _id, CLK_TYPE_PLL5_4_MUX, .conf = _conf, \ .parent_names = _parent_names, \ .num_parents = ARRAY_SIZE(_parent_names)) -#define DEF_DSI_DIV(_name, _id, _parent, _flag) \ - DEF_TYPE(_name, _id, CLK_TYPE_DSI_DIV, .parent = _parent, .flag = _flag) +#define DEF_DSI_DIV(_name, _id, _parent, _flags) \ + DEF_TYPE(_name, _id, CLK_TYPE_DSI_DIV, .parent = _parent, .core_flags = _flags) #define DEF_G3L_DSI_DIV(_name, _id, _parent, _conf) \ DEF_TYPE(_name, _id, CLK_TYPE_G3L_DSI_DIV, .parent = _parent, .conf = _conf, \ - .flag = CLK_SET_RATE_PARENT) + .core_flags = CLK_SET_RATE_PARENT) #define DEF_G3L_PLLDSI(_name, _id, _parent, _conf) \ DEF_TYPE(_name, _id, CLK_TYPE_G3L_PLLDSI, .parent = _parent, .conf = _conf) From 5c2c85bff0b045edb46887b946ab3b37dffb36a5 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 11 Aug 2026 19:27:17 +0100 Subject: [PATCH 005/168] clk: renesas: rzg2l: Add support for divider flags Add support for passing divider flags apart from clock flags from soc specific clock drivers. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://patch.msgid.link/20260811182729.360959-5-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 8 ++++---- drivers/clk/renesas/rzg2l-cpg.h | 11 ++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 59a4d774f0cf..2cff9645cb24 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -487,20 +487,20 @@ rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, if (core->dtable) clk_hw = clk_hw_register_divider_table(dev, core->name, - parent_name, 0, + parent_name, core->core_flags, base + GET_REG_OFFSET(core->conf), GET_SHIFT(core->conf), GET_WIDTH(core->conf), - core->core_flags, + core->div_flags, core->dtable, &priv->rmw_lock); else clk_hw = clk_hw_register_divider(dev, core->name, - parent_name, 0, + parent_name, core->core_flags, base + GET_REG_OFFSET(core->conf), GET_SHIFT(core->conf), GET_WIDTH(core->conf), - core->core_flags, &priv->rmw_lock); + core->div_flags, &priv->rmw_lock); if (IS_ERR(clk_hw)) return ERR_CAST(clk_hw); diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 38db209aabf9..74a471ba12dc 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -112,6 +112,7 @@ struct cpg_core_clk { notifier_fn_t notifier; u32 core_flags; u32 mux_flags; + u32 div_flags; int num_parents; }; @@ -165,14 +166,18 @@ enum clk_types { DEF_TYPE(_name, _id, CLK_TYPE_IN) #define DEF_FIXED(_name, _id, _parent, _mult, _div) \ DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult) -#define DEF_DIV(_name, _id, _parent, _conf, _dtable) \ +#define DEF_DIV_FLAGS(_name, _id, _parent, _conf, _dtable, _flags, _div_flags) \ DEF_TYPE(_name, _id, CLK_TYPE_DIV, .conf = _conf, \ .parent = _parent, .dtable = _dtable, \ - .core_flags = CLK_DIVIDER_HIWORD_MASK) + .core_flags = _flags, \ + .div_flags = CLK_DIVIDER_HIWORD_MASK | (_div_flags)) +#define DEF_DIV(_name, _id, _parent, _conf, _dtable) \ + DEF_DIV_FLAGS(_name, _id, _parent, _conf, _dtable, 0, 0) #define DEF_DIV_RO(_name, _id, _parent, _conf, _dtable) \ DEF_TYPE(_name, _id, CLK_TYPE_DIV, .conf = _conf, \ .parent = _parent, .dtable = _dtable, \ - .core_flags = CLK_DIVIDER_READ_ONLY) + .core_flags = 0, \ + .div_flags = CLK_DIVIDER_READ_ONLY) #define DEF_G3S_DIV(_name, _id, _parent, _conf, _sconf, _dtable, _invalid_rate, \ _max_rate, _clk_flags, _notif) \ DEF_TYPE(_name, _id, CLK_TYPE_G3S_DIV, .conf = _conf, .sconf = _sconf, \ From 0243306b863992d6e9138510d686a57730d615ee Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 11 Aug 2026 19:27:18 +0100 Subject: [PATCH 006/168] clk: renesas: rzg2l: Add support for LVDS fixed-factor divider with 4:7 duty cycle Add a new CLK_TYPE_G3L_LVDS_DIV clock type and register function for a fixed-factor divider used by the LVDS clock, which cannot produce a 50% duty cycle for odd divider values. Implement a custom get_duty_cycle() callback that reports the actual (div + 1) / 2 : div duty cycle, and add the DEF_G3L_LVDS_DIV() macro to define such clocks. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260811182729.360959-6-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 87 +++++++++++++++++++++++++++++++++ drivers/clk/renesas/rzg2l-cpg.h | 6 +++ 2 files changed, 93 insertions(+) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 2cff9645cb24..3334e8543f74 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -864,6 +864,90 @@ rzg2l_cpg_dsi_div_clk_register(const struct cpg_core_clk *core, return clk_hw->clk; } +static int rzg3l_cpg_lvds_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return clk_fixed_factor_ops.determine_rate(hw, req); +} + +static int rzg3l_cpg_lvds_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return clk_fixed_factor_ops.set_rate(hw, rate, parent_rate); +} + +static unsigned long rzg3l_cpg_lvds_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return clk_fixed_factor_ops.recalc_rate(hw, parent_rate); +} + +static unsigned long rzg3l_cpg_lvds_div_recalc_accuracy(struct clk_hw *hw, + unsigned long parent_accuracy) +{ + return clk_fixed_factor_ops.recalc_accuracy(hw, parent_accuracy); +} + +static int rzg3l_cpg_lvds_div_get_duty_cycle(struct clk_hw *hw, + struct clk_duty *duty) +{ + struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); + + /* + * An odd divider cannot generate a 50% duty cycle: the output stays + * high for (div + 1) / 2 input clock cycles out of div, e.g. a divider + * of 7 gives a duty cycle of 4/7. + */ + duty->num = DIV_ROUND_UP(fix->div, 2); + duty->den = fix->div; + + return 0; +} + +static const struct clk_ops rzg3l_cpg_lvds_div_ops = { + .determine_rate = rzg3l_cpg_lvds_div_determine_rate, + .set_rate = rzg3l_cpg_lvds_div_set_rate, + .recalc_rate = rzg3l_cpg_lvds_div_recalc_rate, + .recalc_accuracy = rzg3l_cpg_lvds_div_recalc_accuracy, + .get_duty_cycle = rzg3l_cpg_lvds_div_get_duty_cycle, +}; + +static struct clk * __init +rzg3l_cpg_lvds_div_clk_register(const struct cpg_core_clk *core, + struct rzg2l_cpg_priv *priv) +{ + struct clk_fixed_factor *ff; + struct clk_init_data init; + const struct clk *parent; + const char *parent_name; + int ret; + + parent = priv->clks[core->parent]; + if (IS_ERR(parent)) + return ERR_CAST(parent); + + ff = devm_kzalloc(priv->dev, sizeof(*ff), GFP_KERNEL); + if (!ff) + return ERR_PTR(-ENOMEM); + + parent_name = __clk_get_name(parent); + init.name = core->name; + init.ops = &rzg3l_cpg_lvds_div_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = &parent_name; + init.num_parents = 1; + + ff->hw.init = &init; + ff->mult = 1; + ff->div = core->conf; + + ret = devm_clk_hw_register(priv->dev, &ff->hw); + if (ret) + return ERR_PTR(ret); + + return ff->hw.clk; +} + struct g3l_dsi_div_hw_data { struct clk_hw hw; struct rzg2l_cpg_priv *priv; @@ -1694,6 +1778,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, case CLK_TYPE_G3L_DSI_DIV: clk = rzg3l_cpg_dsi_div_clk_register(core, priv); break; + case CLK_TYPE_G3L_LVDS_DIV: + clk = rzg3l_cpg_lvds_div_clk_register(core, priv); + break; case CLK_TYPE_G3L_PLLDSI: clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg3l_cpg_plldsi_ops); break; diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 74a471ba12dc..7d38efee549f 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -148,6 +148,9 @@ enum clk_types { /* Clock for G3L DSI divider */ CLK_TYPE_G3L_DSI_DIV, + + /* Clock for G3L LVDS divider */ + CLK_TYPE_G3L_LVDS_DIV, }; #define DEF_TYPE(_name, _id, _type...) \ @@ -214,6 +217,9 @@ enum clk_types { #define DEF_G3L_DSI_DIV(_name, _id, _parent, _conf) \ DEF_TYPE(_name, _id, CLK_TYPE_G3L_DSI_DIV, .parent = _parent, .conf = _conf, \ .core_flags = CLK_SET_RATE_PARENT) +#define DEF_G3L_LVDS_DIV(_name, _id, _parent, _conf) \ + DEF_TYPE(_name, _id, CLK_TYPE_G3L_LVDS_DIV, .parent = _parent, .conf = _conf, \ + .core_flags = CLK_SET_RATE_PARENT) #define DEF_G3L_PLLDSI(_name, _id, _parent, _conf) \ DEF_TYPE(_name, _id, CLK_TYPE_G3L_PLLDSI, .parent = _parent, .conf = _conf) From cbba664c26d7f648eb388d1edd173e11a44deec7 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 11 Aug 2026 19:27:19 +0100 Subject: [PATCH 007/168] clk: renesas: rzg2l: Add support for RZ/G3L DSI mux Add support for RZ/G3L DSI mux that supports 2 duty cycles. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260811182729.360959-7-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzg2l-cpg.c | 84 +++++++++++++++++++++++++++++++++ drivers/clk/renesas/rzg2l-cpg.h | 10 ++++ 2 files changed, 94 insertions(+) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 3334e8543f74..c48502e0bd6a 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -1472,6 +1472,87 @@ static const struct clk_ops rzg3l_cpg_pll_ops = { .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate, }; +static u8 rzg3l_cpg_dsi_smux_get_parent(struct clk_hw *hw) +{ + return clk_mux_ops.get_parent(hw); +} + +static int rzg3l_cpg_dsi_smux_set_parent(struct clk_hw *hw, u8 index) +{ + return clk_mux_ops.set_parent(hw, index); +} + +static int rzg3l_cpg_dsi_smux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + return clk_mux_ops.determine_rate(hw, req); +} + +static int rzg3l_cpg_dsi_smux_set_duty_cycle(struct clk_hw *hw, + struct clk_duty *duty) +{ + struct clk_hw *parent_hw; + u8 parent_idx; + + /* + * Select parent based on requested duty cycle: + * - If duty > 50% (num/den > 1/2), select LVDS path (parent 0) + * - Otherwise, select DSI/RGB path (parent 1) + */ + if (duty->num * 2 > duty->den) + parent_idx = 0; + else + parent_idx = 1; + + if (parent_idx >= clk_hw_get_num_parents(hw)) + return -EINVAL; + + parent_hw = clk_hw_get_parent_by_index(hw, parent_idx); + if (!parent_hw) + return -EINVAL; + + return clk_hw_set_parent(hw, parent_hw); +} + +static const struct clk_ops rzg3l_cpg_dsi_smux_ops = { + .determine_rate = rzg3l_cpg_dsi_smux_determine_rate, + .get_parent = rzg3l_cpg_dsi_smux_get_parent, + .set_parent = rzg3l_cpg_dsi_smux_set_parent, + .set_duty_cycle = rzg3l_cpg_dsi_smux_set_duty_cycle, +}; + +static struct clk * __init +rzg3l_cpg_dsi_mux_clk_register(const struct cpg_core_clk *core, + struct rzg2l_cpg_priv *priv) +{ + struct clk_mux *mux_data; + struct clk_init_data init; + int ret; + + mux_data = devm_kzalloc(priv->dev, sizeof(*mux_data), GFP_KERNEL); + if (!mux_data) + return ERR_PTR(-ENOMEM); + + init.name = core->name; + init.ops = &rzg3l_cpg_dsi_smux_ops; + init.flags = core->core_flags | CLK_SET_RATE_PARENT; + init.parent_names = core->parent_names; + init.num_parents = core->num_parents; + + mux_data->reg = priv->base + GET_REG_OFFSET(core->conf); + mux_data->shift = GET_SHIFT(core->conf); + mux_data->mask = clk_div_mask(GET_WIDTH(core->conf)); + mux_data->flags = core->mux_flags; + mux_data->lock = &priv->rmw_lock; + mux_data->hw.init = &init; + + ret = devm_clk_hw_register(priv->dev, &mux_data->hw); + if (ret) + return ERR_PTR(ret); + + return mux_data->hw.clk; +} + static inline bool rzg3l_dsi_compute_pll_parameters(struct rzg3l_plldsi_parameters *pars, struct rzg3l_plldsi_parameters *p, @@ -1784,6 +1865,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, case CLK_TYPE_G3L_PLLDSI: clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg3l_cpg_plldsi_ops); break; + case CLK_TYPE_G3L_DSI_MUX: + clk = rzg3l_cpg_dsi_mux_clk_register(core, priv); + break; default: goto fail; } diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h index 7d38efee549f..81296046e353 100644 --- a/drivers/clk/renesas/rzg2l-cpg.h +++ b/drivers/clk/renesas/rzg2l-cpg.h @@ -151,6 +151,9 @@ enum clk_types { /* Clock for G3L LVDS divider */ CLK_TYPE_G3L_LVDS_DIV, + + /* Clock for G3L DSI clock source selector */ + CLK_TYPE_G3L_DSI_MUX, }; #define DEF_TYPE(_name, _id, _type...) \ @@ -201,6 +204,13 @@ enum clk_types { .parent_names = _parent_names, \ .num_parents = ARRAY_SIZE(_parent_names), \ .mux_flags = CLK_MUX_READ_ONLY) +#define DEF_G3L_SEL_DSI_MUX(_name, _id, _conf, _parent_names) \ + DEF_TYPE(_name, _id, CLK_TYPE_G3L_DSI_MUX, .conf = _conf, \ + .parent_names = _parent_names, \ + .num_parents = ARRAY_SIZE(_parent_names), \ + .core_flags = CLK_SET_RATE_PARENT | CLK_DUTY_CYCLE_PARENT | \ + CLK_SET_RATE_NO_REPARENT, \ + .mux_flags = CLK_MUX_HIWORD_MASK) #define DEF_SD_MUX(_name, _id, _conf, _sconf, _parent_names, _mtable, _clk_flags, _notifier) \ DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, .sconf = _sconf, \ .parent_names = _parent_names, \ From 5084af5d132ecdc93f8ead1bd38e58451ede4ef6 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 11 Aug 2026 19:27:20 +0100 Subject: [PATCH 008/168] clk: renesas: r9a08g046: Sort macro definitions alphabetically Reorder the DDIV_PACK() and SEL_PLL_PACK() macro definitions so they are grouped alphabetically by name, improving readability and making it easier to spot duplicates or gaps. No functional change. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260811182729.360959-8-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g046-cpg.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/renesas/r9a08g046-cpg.c b/drivers/clk/renesas/r9a08g046-cpg.c index 4488bd1988e8..aaf329081e15 100644 --- a/drivers/clk/renesas/r9a08g046-cpg.c +++ b/drivers/clk/renesas/r9a08g046-cpg.c @@ -35,14 +35,11 @@ #define G3L_DIVPL2A DDIV_PACK(G3L_CPG_PL2_DDIV, 0, 2) #define G3L_DIVPL2B DDIV_PACK(G3L_CPG_PL2_DDIV, 4, 2) #define G3L_DIVPL3A DDIV_PACK(G3L_CPG_PL3_DDIV, 0, 2) -#define G3L_DIV_SDHI0 DDIV_PACK(G3L_CPG_SDHI_DDIV, 0, 2) -#define G3L_DIV_SDHI1 DDIV_PACK(G3L_CPG_SDHI_DDIV, 4, 2) -#define G3L_DIV_SDHI2 DDIV_PACK(G3L_CPG_SDHI_DDIV, 8, 2) -#define G3L_DIV_GE3D DDIV_PACK(G3L_CPG_GE3D_DDIV, 0, 3) #define G3L_DIV_CA55_CORE0 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 0, 3) #define G3L_DIV_CA55_CORE1 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 4, 3) #define G3L_DIV_CA55_CORE2 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 8, 3) #define G3L_DIV_CA55_CORE3 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 12, 3) +#define G3L_DIV_GE3D DDIV_PACK(G3L_CPG_GE3D_DDIV, 0, 3) #define G3L_DIV_RSCI0 DDIV_PACK(G3L_CPG_RSCI_DDIV, 0, 2) #define G3L_DIV_RSCI1 DDIV_PACK(G3L_CPG_RSCI_DDIV, 2, 2) #define G3L_DIV_RSCI2 DDIV_PACK(G3L_CPG_RSCI_DDIV, 4, 2) @@ -50,6 +47,9 @@ #define G3L_DIV_RSPI0 DDIV_PACK(G3L_CPG_RSPI_DDIV, 0, 2) #define G3L_DIV_RSPI1 DDIV_PACK(G3L_CPG_RSPI_DDIV, 2, 2) #define G3L_DIV_RSPI2 DDIV_PACK(G3L_CPG_RSPI_DDIV, 4, 2) +#define G3L_DIV_SDHI0 DDIV_PACK(G3L_CPG_SDHI_DDIV, 0, 2) +#define G3L_DIV_SDHI1 DDIV_PACK(G3L_CPG_SDHI_DDIV, 4, 2) +#define G3L_DIV_SDHI2 DDIV_PACK(G3L_CPG_SDHI_DDIV, 8, 2) #define G3L_SDIV_ETH_A DDIV_PACK(G3L_CPG_ETH_SDIV, 0, 2) #define G3L_SDIV_ETH_B DDIV_PACK(G3L_CPG_ETH_SDIV, 4, 1) #define G3L_SDIV_ETH_C DDIV_PACK(G3L_CPG_ETH_SDIV, 8, 2) @@ -73,16 +73,13 @@ #define G3L_DIV_SDHI0_STS DDIV_PACK(G3L_CLKDIVSTATUS, 24, 1) #define G3L_DIV_SDHI1_STS DDIV_PACK(G3L_CLKDIVSTATUS, 25, 1) #define G3L_DIV_SDHI2_STS DDIV_PACK(G3L_CLKDIVSTATUS, 26, 1) +#define G3L_DIV_GE3D_STS DDIV_PACK(G3L_CLKDIVSTATUS, 27, 1) #define G3L_SEL_SDHI0_STS SEL_PLL_PACK(G3L_CLKSELSTATUS, 16, 1) #define G3L_SEL_SDHI1_STS SEL_PLL_PACK(G3L_CLKSELSTATUS, 17, 1) #define G3L_SEL_SDHI2_STS SEL_PLL_PACK(G3L_CLKSELSTATUS, 18, 1) -#define G3L_DIV_GE3D_STS DDIV_PACK(G3L_CLKDIVSTATUS, 27, 1) /* RZ/G3L Specific clocks select. */ -#define G3L_SEL_SDHI0 SEL_PLL_PACK(G3L_CPG_SDHI_DSEL, 0, 2) -#define G3L_SEL_SDHI1 SEL_PLL_PACK(G3L_CPG_SDHI_DSEL, 4, 2) -#define G3L_SEL_SDHI2 SEL_PLL_PACK(G3L_CPG_SDHI_DSEL, 8, 2) #define G3L_SEL_ETH0_TX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 0, 1) #define G3L_SEL_ETH0_RX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 1, 1) #define G3L_SEL_ETH0_RM SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 2, 1) @@ -101,6 +98,9 @@ #define G3L_SEL_RSPI0 SEL_PLL_PACK(G3L_CPG_RSPI_SSEL, 0, 2) #define G3L_SEL_RSPI1 SEL_PLL_PACK(G3L_CPG_RSPI_SSEL, 2, 2) #define G3L_SEL_RSPI2 SEL_PLL_PACK(G3L_CPG_RSPI_SSEL, 4, 2) +#define G3L_SEL_SDHI0 SEL_PLL_PACK(G3L_CPG_SDHI_DSEL, 0, 2) +#define G3L_SEL_SDHI1 SEL_PLL_PACK(G3L_CPG_SDHI_DSEL, 4, 2) +#define G3L_SEL_SDHI2 SEL_PLL_PACK(G3L_CPG_SDHI_DSEL, 8, 2) enum clk_ids { /* Core Clock Outputs exported to DT */ From 2d355b6ecb435b461c153f42708627cbae47d6a3 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 11 Aug 2026 19:27:21 +0100 Subject: [PATCH 009/168] clk: renesas: r9a08g046: Add MIPI DSI and LCDC clock/reset entries Add clock and reset entries for the MIPI DSI and LCDC peripherals on the RZ/G3L (R9A08G046) SoC. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260811182729.360959-9-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g046-cpg.c | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/drivers/clk/renesas/r9a08g046-cpg.c b/drivers/clk/renesas/r9a08g046-cpg.c index aaf329081e15..bd3ae08e626b 100644 --- a/drivers/clk/renesas/r9a08g046-cpg.c +++ b/drivers/clk/renesas/r9a08g046-cpg.c @@ -19,26 +19,31 @@ #define G3L_CPG_PL3_DDIV (0x208) #define G3L_CPG_SDHI_DDIV (0x218) #define G3L_CPG_GE3D_DDIV (0x224) +#define G3L_CPG_DSI_DDIV (0x228) #define G3L_CPG_CA55CORE_DDIV (0x234) #define G3L_CPG_RSCI_DDIV (0x238) #define G3L_CPG_RSPI_DDIV (0x23c) #define G3L_CPG_SDHI_DSEL (0x244) #define G3L_CLKDIVSTATUS (0x280) #define G3L_CLKSELSTATUS (0x284) +#define G3L_CPG_DSI_SSEL (0x408) #define G3L_CPG_GE3D_SSEL (0x40c) #define G3L_CPG_ETH_SSEL (0x410) #define G3L_CPG_RSCI_SSEL (0x414) #define G3L_CPG_RSPI_SSEL (0x418) +#define G3L_CPG_DSI_SDIV (0x430) #define G3L_CPG_ETH_SDIV (0x434) /* RZ/G3L Specific division configuration. */ #define G3L_DIVPL2A DDIV_PACK(G3L_CPG_PL2_DDIV, 0, 2) #define G3L_DIVPL2B DDIV_PACK(G3L_CPG_PL2_DDIV, 4, 2) #define G3L_DIVPL3A DDIV_PACK(G3L_CPG_PL3_DDIV, 0, 2) +#define G3L_DIVPL3B DDIV_PACK(G3L_CPG_PL3_DDIV, 4, 2) #define G3L_DIV_CA55_CORE0 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 0, 3) #define G3L_DIV_CA55_CORE1 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 4, 3) #define G3L_DIV_CA55_CORE2 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 8, 3) #define G3L_DIV_CA55_CORE3 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 12, 3) +#define G3L_DIV_DSI DDIV_PACK(G3L_CPG_DSI_DDIV, 0, 2) #define G3L_DIV_GE3D DDIV_PACK(G3L_CPG_GE3D_DDIV, 0, 3) #define G3L_DIV_RSCI0 DDIV_PACK(G3L_CPG_RSCI_DDIV, 0, 2) #define G3L_DIV_RSCI1 DDIV_PACK(G3L_CPG_RSCI_DDIV, 2, 2) @@ -50,6 +55,7 @@ #define G3L_DIV_SDHI0 DDIV_PACK(G3L_CPG_SDHI_DDIV, 0, 2) #define G3L_DIV_SDHI1 DDIV_PACK(G3L_CPG_SDHI_DDIV, 4, 2) #define G3L_DIV_SDHI2 DDIV_PACK(G3L_CPG_SDHI_DDIV, 8, 2) +#define G3L_SDIV_DSI_C_SET DDIV_PACK(G3L_CPG_DSI_SDIV, 8, 1) #define G3L_SDIV_ETH_A DDIV_PACK(G3L_CPG_ETH_SDIV, 0, 2) #define G3L_SDIV_ETH_B DDIV_PACK(G3L_CPG_ETH_SDIV, 4, 1) #define G3L_SDIV_ETH_C DDIV_PACK(G3L_CPG_ETH_SDIV, 8, 2) @@ -59,6 +65,7 @@ #define G3L_DIVPL2A_STS DDIV_PACK(G3L_CLKDIVSTATUS, 4, 1) #define G3L_DIVPL2B_STS DDIV_PACK(G3L_CLKDIVSTATUS, 5, 1) #define G3L_DIVPL3A_STS DDIV_PACK(G3L_CLKDIVSTATUS, 8, 1) +#define G3L_DIVPL3B_STS DDIV_PACK(G3L_CLKDIVSTATUS, 9, 1) #define G3L_DIV_CA55_CORE0_STS DDIV_PACK(G3L_CLKDIVSTATUS, 12, 1) #define G3L_DIV_CA55_CORE1_STS DDIV_PACK(G3L_CLKDIVSTATUS, 13, 1) #define G3L_DIV_CA55_CORE2_STS DDIV_PACK(G3L_CLKDIVSTATUS, 14, 1) @@ -74,12 +81,14 @@ #define G3L_DIV_SDHI1_STS DDIV_PACK(G3L_CLKDIVSTATUS, 25, 1) #define G3L_DIV_SDHI2_STS DDIV_PACK(G3L_CLKDIVSTATUS, 26, 1) #define G3L_DIV_GE3D_STS DDIV_PACK(G3L_CLKDIVSTATUS, 27, 1) +#define G3L_DIV_DSI_STS DDIV_PACK(G3L_CLKDIVSTATUS, 28, 1) #define G3L_SEL_SDHI0_STS SEL_PLL_PACK(G3L_CLKSELSTATUS, 16, 1) #define G3L_SEL_SDHI1_STS SEL_PLL_PACK(G3L_CLKSELSTATUS, 17, 1) #define G3L_SEL_SDHI2_STS SEL_PLL_PACK(G3L_CLKSELSTATUS, 18, 1) /* RZ/G3L Specific clocks select. */ +#define G3L_SEL_DSI SEL_PLL_PACK(G3L_CPG_DSI_SSEL, 0, 1) #define G3L_SEL_ETH0_TX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 0, 1) #define G3L_SEL_ETH0_RX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 1, 1) #define G3L_SEL_ETH0_RM SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 2, 1) @@ -126,8 +135,11 @@ enum clk_ids { CLK_PLL3_DIV2, CLK_PLL3_DIV2_2, CLK_PLL3_DIV3, + CLK_PLL3_DIV6, CLK_PLL6, CLK_PLL6_DIV10, + CLK_PLL7, + CLK_PLL7_DSI_SDIV, CLK_SEL_ETH0_TX, CLK_SEL_ETH0_RX, CLK_SEL_ETH0_RM, @@ -149,6 +161,7 @@ enum clk_ids { CLK_ETH0_RM, CLK_ETH1_TR, CLK_ETH1_RM, + CLK_M2_DIV7, CLK_SD0_DIV2, CLK_SD1_DIV2, CLK_SD2_DIV2, @@ -165,6 +178,12 @@ static const struct clk_div_table dtable_1_4[] = { { 0, 0 }, }; +static const struct clk_div_table dtable_1_2[] = { + { 0, 1 }, + { 1, 2 }, + { 0, 0 }, +}; + static const struct clk_div_table dtable_1_8[] = { { 0, 1 }, { 1, 2 }, @@ -220,7 +239,16 @@ static const struct clk_div_table dtable_8_256[] = { { 0, 0 }, }; +static const struct clk_div_table dtable_16_128[] = { + { 0, 16 }, + { 1, 32 }, + { 2, 64 }, + { 3, 128 }, + { 0, 0 }, +}; + /* Mux clock names tables. */ +static const char * const sel_dsi[] = { ".m2_div7", ".pll7_dsi_div"}; static const char * const sel_eth0_tx[] = { ".div_eth0_tr", "eth0_txc_tx_clk" }; static const char * const sel_eth0_rx[] = { ".div_eth0_tr", "eth0_rxc_rx_clk" }; static const char * const sel_eth0_rm[] = { ".pll6_div10", "eth0_rxc_rx_clk" }; @@ -254,6 +282,7 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = { DEF_G3L_PLL(".pll6", CLK_PLL6, CLK_EXTAL, CPG_PLL_CONF(0x50, 0), 500000000UL), DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 1, 2), + DEF_G3L_PLLDSI(".pll7", CLK_PLL7, CLK_EXTAL, CPG_PLL_CONF(0x80, 0)), DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2), DEF_FIXED(".pll2_div2_4", CLK_PLL2_DIV2_4, CLK_PLL2_DIV2, 1, 4), DEF_FIXED(".pll2_div5", CLK_PLL2_DIV5, CLK_PLL2, 1, 5), @@ -262,6 +291,7 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = { DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2), DEF_FIXED(".pll3_div2_2", CLK_PLL3_DIV2_2, CLK_PLL3_DIV2, 1, 2), DEF_FIXED(".pll3_div3", CLK_PLL3_DIV3, CLK_PLL3, 1, 3), + DEF_FIXED(".pll3_div6", CLK_PLL3_DIV6, CLK_PLL3, 1, 6), DEF_FIXED(".pll6_div10", CLK_PLL6_DIV10, CLK_PLL6, 1, 10), DEF_SD_MUX(".sel_sdhi0", CLK_SEL_SDHI0, G3L_SEL_SDHI0, G3L_SEL_SDHI0_STS, sel_sdhi, mtable_sd, 0, NULL), @@ -301,6 +331,8 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = { dtable_8_256, 0, 0, 0, NULL), DEF_G3S_DIV("P1", R9A08G046_CLK_P1, CLK_PLL3_DIV2, G3L_DIVPL3A, G3L_DIVPL3A_STS, dtable_4_128, 0, 0, 0, NULL), + DEF_G3S_DIV("P2", R9A08G046_CLK_P2, CLK_PLL3_DIV2, G3L_DIVPL3B, G3L_DIVPL3B_STS, + dtable_8_256, 0, 0, 0, NULL), DEF_G3S_DIV("P3", R9A08G046_CLK_P3, CLK_PLL2_DIV2, G3L_DIVPL2A, G3L_DIVPL2A_STS, dtable_4_128, 0, 0, 0, NULL), DEF_G3S_DIV("P13", R9A08G046_CLK_P13, CLK_SEL_RSCI0, G3L_DIV_RSCI0, G3L_DIV_RSCI0_STS, @@ -329,6 +361,15 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = { DEF_FIXED(".sd0_div2", CLK_SD0_DIV2, R9A08G046_CLK_SD0, 1, 2), DEF_FIXED(".sd1_div2", CLK_SD1_DIV2, R9A08G046_CLK_SD1, 1, 2), DEF_FIXED(".sd2_div2", CLK_SD2_DIV2, R9A08G046_CLK_SD2, 1, 2), + DEF_G3S_DIV("M1", R9A08G046_CLK_M1, CLK_PLL2_DIV6, G3L_DIV_DSI, G3L_DIV_DSI_STS, + dtable_16_128, 0, 0, 0, NULL), + DEF_DIV_FLAGS("M2", R9A08G046_CLK_M2, CLK_PLL7, G3L_SDIV_DSI_C_SET, dtable_1_2, + CLK_SET_RATE_PARENT, CLK_DIVIDER_ROUND_CLOSEST), + DEF_G3L_LVDS_DIV(".m2_div7", CLK_M2_DIV7, R9A08G046_CLK_M2, 7), + DEF_G3L_DSI_DIV(".pll7_dsi_div", CLK_PLL7_DSI_SDIV, CLK_PLL7, G3L_CPG_DSI_SDIV), + DEF_G3L_SEL_DSI_MUX("M3", R9A08G046_CLK_M3, G3L_SEL_DSI, sel_dsi), + DEF_FIXED("M4", R9A08G046_CLK_M4, CLK_PLL7, 1, 1), + DEF_FIXED("M5", R9A08G046_CLK_M5, CLK_PLL3_DIV6, 1, 2), DEF_FIXED("HP", R9A08G046_CLK_HP, CLK_PLL6_DIV10, 1, 1), DEF_MUX_FLAGS("ETHTX01", R9A08G046_CLK_ETHTX01, G3L_SEL_ETH0_CLK_TX_I, sel_eth0_clk_tx_i, CLK_SET_RATE_PARENT), @@ -347,6 +388,7 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = { DEF_G3S_DIV("G", R9A08G046_CLK_G, CLK_SEL_GE3D, G3L_DIV_GE3D, G3L_DIV_GE3D_STS, dtable_1_32, 0, 0, 0, NULL), DEF_FIXED("OSCCLK", R9A08G046_OSCCLK, CLK_EXTAL, 1, 1), + DEF_FIXED("mipi_dsi_pllclk", R9A08G046_MIPI_DSI_PLLCLK, R9A08G046_CLK_M4, 1, 1), }; static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = { @@ -400,6 +442,22 @@ static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = { MSTOP(BUS_PERI_VIDEO, BIT(12))), DEF_MOD("ge3d_ace_clk", R9A08G046_GE3D_ACE_CLK, R9A08G046_CLK_P1, 0x558, 2, MSTOP(BUS_PERI_VIDEO, BIT(12))), + DEF_MOD("mipi_dsi_sysclk", R9A08G046_MIPI_DSI_SYSCLK, R9A08G046_CLK_M5, 0x568, 1, + MSTOP(BUS_PERI_VIDEO, BIT(5) | BIT(6))), + DEF_MOD("mipi_dsi_aclk", R9A08G046_MIPI_DSI_ACLK, R9A08G046_CLK_P1, 0x568, 2, + MSTOP(BUS_PERI_VIDEO, BIT(5) | BIT(6))), + DEF_MOD("mipi_dsi_pclk", R9A08G046_MIPI_DSI_PCLK, R9A08G046_CLK_P2, 0x568, 3, + MSTOP(BUS_PERI_VIDEO, BIT(5) | BIT(6))), + DEF_MOD("mipi_dsi_vclk", R9A08G046_MIPI_DSI_VCLK, R9A08G046_CLK_M3, 0x568, 4, + MSTOP(BUS_PERI_VIDEO, BIT(5) | BIT(6))), + DEF_MOD("mipi_dsi_lpclk", R9A08G046_MIPI_DSI_LPCLK, R9A08G046_CLK_M1, 0x568, 5, + MSTOP(BUS_PERI_VIDEO, BIT(5) | BIT(6))), + DEF_MOD("lcdc_clk_a", R9A08G046_LCDC_CLK_A, R9A08G046_CLK_P1, 0x56c, 0, + MSTOP(BUS_PERI_VIDEO, BIT(7) | BIT(8) | BIT(9))), + DEF_MOD("lcdc_clk_d", R9A08G046_LCDC_CLK_D, R9A08G046_CLK_M3, 0x56c, 1, + MSTOP(BUS_PERI_VIDEO, BIT(7) | BIT(8) | BIT(9))), + DEF_MOD("lcdc_clk_p", R9A08G046_LCDC_CLK_P, R9A08G046_CLK_P2, 0x56c, 2, + MSTOP(BUS_PERI_VIDEO, BIT(7) | BIT(8) | BIT(9))), DEF_MOD("ssi0_pclk2", R9A08G046_SSI0_PCLK2, R9A08G046_CLK_P0, 0x570, 0, MSTOP(BUS_MCPU1, BIT(10))), DEF_MOD("ssi0_pclk_sfr", R9A08G046_SSI0_PCLK_SFR, R9A08G046_CLK_P0, 0x570, 1, @@ -537,6 +595,10 @@ static const struct rzg2l_reset r9a08g046_resets[] = { DEF_RST(R9A08G046_GE3D_RESETN, 0x858, 0), DEF_RST(R9A08G046_GE3D_AXI_RESETN, 0x858, 1), DEF_RST(R9A08G046_GE3D_ACE_RESETN, 0x858, 2), + DEF_RST(R9A08G046_MIPI_DSI_CMN_RSTB, 0x868, 0), + DEF_RST(R9A08G046_MIPI_DSI_ARESET_N, 0x868, 1), + DEF_RST(R9A08G046_MIPI_DSI_PRESET_N, 0x868, 2), + DEF_RST(R9A08G046_LCDC_RESET_N, 0x86c, 0), DEF_RST(R9A08G046_SSI0_RST_M2_REG, 0x870, 0), DEF_RST(R9A08G046_SSI1_RST_M2_REG, 0x870, 1), DEF_RST(R9A08G046_SSI2_RST_M2_REG, 0x870, 2), From f93dfd5fe16bff1d5d86e1906d728ed18c681164 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 11 Aug 2026 19:27:22 +0100 Subject: [PATCH 010/168] clk: renesas: r9a08g046: Add clock and reset entries for LVDS Add clock and reset entries for LVDS. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Link: https://patch.msgid.link/20260811182729.360959-10-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g046-cpg.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/clk/renesas/r9a08g046-cpg.c b/drivers/clk/renesas/r9a08g046-cpg.c index bd3ae08e626b..5878423db151 100644 --- a/drivers/clk/renesas/r9a08g046-cpg.c +++ b/drivers/clk/renesas/r9a08g046-cpg.c @@ -574,6 +574,10 @@ static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = { MSTOP(BUS_MCPU3, BIT(11))), DEF_MOD("rsci3_tclk", R9A08G046_RSCI3_TCLK, R9A08G046_CLK_P16, 0x618, 11, MSTOP(BUS_MCPU3, BIT(12))), + DEF_MOD("lvds_pllclk", R9A08G046_LVDS_PLLCLK, R9A08G046_CLK_M2, 0x61c, 0, + MSTOP(BUS_PERI_VIDEO, BIT(11))), + DEF_MOD("lvds_clk_dot0", R9A08G046_LVDS_CLK_DOT0, R9A08G046_CLK_M3, 0x61c, 1, + MSTOP(BUS_PERI_VIDEO, BIT(11))), }; static const struct rzg2l_reset r9a08g046_resets[] = { @@ -637,6 +641,7 @@ static const struct rzg2l_reset r9a08g046_resets[] = { DEF_RST(R9A08G046_RSCI1_TRESETN, 0x918, 9), DEF_RST(R9A08G046_RSCI2_TRESETN, 0x918, 10), DEF_RST(R9A08G046_RSCI3_TRESETN, 0x918, 11), + DEF_RST(R9A08G046_LVDS_RESET_N, 0x91c, 0), }; static const unsigned int r9a08g046_crit_mod_clks[] __initconst = { From 53c4586386e81ba61ac5d8708365ad600a309334 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:11 +0200 Subject: [PATCH 011/168] clk: aspeed: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <029b50dbb60753ef1e27045fc379802930c4085e.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/aspeed/clk-aspeed.c | 2 +- drivers/clk/aspeed/clk-ast2600.c | 2 +- drivers/clk/aspeed/clk-ast2700.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/aspeed/clk-aspeed.c b/drivers/clk/aspeed/clk-aspeed.c index 38a5766a435c..d32a3e9f300a 100644 --- a/drivers/clk/aspeed/clk-aspeed.c +++ b/drivers/clk/aspeed/clk-aspeed.c @@ -349,8 +349,8 @@ static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev, struct regmap *map, u8 clock_idx, u8 reset_idx, u8 clk_gate_flags, spinlock_t *lock) { + struct clk_init_data init = {}; struct aspeed_clk_gate *gate; - struct clk_init_data init; struct clk_hw *hw; int ret; diff --git a/drivers/clk/aspeed/clk-ast2600.c b/drivers/clk/aspeed/clk-ast2600.c index 70061c961b69..cc3d26602b16 100644 --- a/drivers/clk/aspeed/clk-ast2600.c +++ b/drivers/clk/aspeed/clk-ast2600.c @@ -425,8 +425,8 @@ static struct clk_hw *aspeed_g6_clk_hw_register_gate(struct device *dev, struct regmap *map, u8 clock_idx, u8 reset_idx, u8 clk_gate_flags, spinlock_t *lock) { + struct clk_init_data init = {}; struct aspeed_clk_gate *gate; - struct clk_init_data init; struct clk_hw *hw; int ret; diff --git a/drivers/clk/aspeed/clk-ast2700.c b/drivers/clk/aspeed/clk-ast2700.c index 536600fcd024..495b7fa3395b 100644 --- a/drivers/clk/aspeed/clk-ast2700.c +++ b/drivers/clk/aspeed/clk-ast2700.c @@ -824,7 +824,7 @@ static struct clk_hw *ast2700_clk_hw_register_gate(struct device *dev, const cha void __iomem *reg, u8 clock_idx, unsigned long flags, spinlock_t *lock) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_gate *gate; struct clk_hw *hw; int ret = -EINVAL; From 16f9dc4296c4714d51fb168f3c20cd9548816e09 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:12 +0200 Subject: [PATCH 012/168] clk: at91: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Acked-by: Nicolas Ferre Message-ID: Signed-off-by: Brian Masney --- drivers/clk/at91/clk-audio-pll.c | 4 ++-- drivers/clk/at91/clk-h32mx.c | 2 +- drivers/clk/at91/clk-main.c | 2 +- drivers/clk/at91/clk-pll.c | 2 +- drivers/clk/at91/clk-plldiv.c | 2 +- drivers/clk/at91/clk-slow.c | 2 +- drivers/clk/at91/clk-smd.c | 2 +- drivers/clk/at91/clk-usb.c | 6 +++--- drivers/clk/at91/sckc.c | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/clk/at91/clk-audio-pll.c b/drivers/clk/at91/clk-audio-pll.c index 732037bfbda8..26875ad0cce7 100644 --- a/drivers/clk/at91/clk-audio-pll.c +++ b/drivers/clk/at91/clk-audio-pll.c @@ -486,8 +486,8 @@ struct clk_hw * __init at91_clk_register_audio_pll_pad(struct regmap *regmap, const char *name, const char *parent_name) { + struct clk_init_data init = {}; struct clk_audio_pad *apad_ck; - struct clk_init_data init; int ret; apad_ck = kzalloc_obj(*apad_ck); @@ -517,8 +517,8 @@ struct clk_hw * __init at91_clk_register_audio_pll_pmc(struct regmap *regmap, const char *name, const char *parent_name) { + struct clk_init_data init = {}; struct clk_audio_pmc *apmc_ck; - struct clk_init_data init; int ret; apmc_ck = kzalloc_obj(*apmc_ck); diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c index 12bd112d3c50..8d5488223e49 100644 --- a/drivers/clk/at91/clk-h32mx.c +++ b/drivers/clk/at91/clk-h32mx.c @@ -97,7 +97,7 @@ at91_clk_register_h32mx(struct regmap *regmap, const char *name, const char *parent_name) { struct clk_sama5d4_h32mx *h32mxclk; - struct clk_init_data init; + struct clk_init_data init = {}; int ret; h32mxclk = kzalloc_obj(*h32mxclk); diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c index ab515239adcf..6074ed2a16ce 100644 --- a/drivers/clk/at91/clk-main.c +++ b/drivers/clk/at91/clk-main.c @@ -298,8 +298,8 @@ at91_clk_register_main_rc_osc(struct regmap *regmap, const char *name, u32 frequency, u32 accuracy) { + struct clk_init_data init = {}; struct clk_main_rc_osc *osc; - struct clk_init_data init; struct clk_hw *hw; int ret; diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index b89f60cf0241..1b9a37a9e070 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c @@ -318,7 +318,7 @@ at91_clk_register_pll(struct regmap *regmap, const char *name, { struct clk_pll *pll; struct clk_hw *hw; - struct clk_init_data init; + struct clk_init_data init = {}; int offset = PLL_REG(id); unsigned int pllr; int ret; diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c index 5f93aead03fa..135ca0abeb18 100644 --- a/drivers/clk/at91/clk-plldiv.c +++ b/drivers/clk/at91/clk-plldiv.c @@ -86,9 +86,9 @@ struct clk_hw * __init at91_clk_register_plldiv(struct regmap *regmap, const char *name, const char *parent_name) { + struct clk_init_data init = {}; struct clk_plldiv *plldiv; struct clk_hw *hw; - struct clk_init_data init; int ret; plldiv = kzalloc_obj(*plldiv); diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c index f0cad50e490b..dc0009ca2cef 100644 --- a/drivers/clk/at91/clk-slow.c +++ b/drivers/clk/at91/clk-slow.c @@ -42,8 +42,8 @@ at91_clk_register_sam9260_slow(struct regmap *regmap, int num_parents) { struct clk_sam9260_slow *slowck; + struct clk_init_data init = {}; struct clk_hw *hw; - struct clk_init_data init; int ret; if (!name) diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c index 77f2b8fe6cab..4eff52a9798b 100644 --- a/drivers/clk/at91/clk-smd.c +++ b/drivers/clk/at91/clk-smd.c @@ -113,9 +113,9 @@ struct clk_hw * __init at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents) { + struct clk_init_data init = {}; struct at91sam9x5_clk_smd *smd; struct clk_hw *hw; - struct clk_init_data init; int ret; smd = kzalloc_obj(*smd); diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index b4dc86193e09..0e4c0367c1af 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -224,9 +224,9 @@ _at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name, const char **parent_names, u8 num_parents, u32 usbs_mask) { + struct clk_init_data init = {}; struct at91sam9x5_clk_usb *usb; struct clk_hw *hw; - struct clk_init_data init; int ret; usb = kzalloc_obj(*usb); @@ -275,9 +275,9 @@ struct clk_hw * __init at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name) { + struct clk_init_data init = {}; struct at91sam9x5_clk_usb *usb; struct clk_hw *hw; - struct clk_init_data init; int ret; usb = kzalloc_obj(*usb); @@ -394,9 +394,9 @@ struct clk_hw * __init at91rm9200_clk_register_usb(struct regmap *regmap, const char *name, const char *parent_name, const u32 *divisors) { + struct clk_init_data init = {}; struct at91rm9200_clk_usb *usb; struct clk_hw *hw; - struct clk_init_data init; int ret; usb = kzalloc_obj(*usb); diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 776118f14867..fc5ca22d181a 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -231,9 +231,9 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, unsigned long startup, const struct clk_slow_bits *bits) { + struct clk_init_data init = {}; struct clk_slow_rc_osc *osc; struct clk_hw *hw; - struct clk_init_data init; int ret; if (!sckcr || !name) From b546e02f3662c5953862f136e0367c641c043fb4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:13 +0200 Subject: [PATCH 013/168] clk: bcm: iproc: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Reviewed-by: Florian Fainelli Message-ID: <28233748ddbdefe6a2eb18127d5cd5f72984ab62.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/bcm/clk-iproc-armpll.c | 2 +- drivers/clk/bcm/clk-iproc-asiu.c | 2 +- drivers/clk/bcm/clk-iproc-pll.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/bcm/clk-iproc-armpll.c b/drivers/clk/bcm/clk-iproc-armpll.c index 8485428fe49c..aca53e2bda01 100644 --- a/drivers/clk/bcm/clk-iproc-armpll.c +++ b/drivers/clk/bcm/clk-iproc-armpll.c @@ -235,7 +235,7 @@ void __init iproc_armpll_setup(struct device_node *node) { int ret; struct iproc_arm_pll *pll; - struct clk_init_data init; + struct clk_init_data init = {}; const char *parent_name; pll = kzalloc_obj(*pll); diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c index 56a813227981..86c0100934f8 100644 --- a/drivers/clk/bcm/clk-iproc-asiu.c +++ b/drivers/clk/bcm/clk-iproc-asiu.c @@ -206,7 +206,7 @@ void __init iproc_asiu_setup(struct device_node *node, goto err_iomap_gate; for (i = 0; i < num_clks; i++) { - struct clk_init_data init; + struct clk_init_data init = {}; const char *parent_name; struct iproc_asiu_clk *asiu_clk; const char *clk_name; diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index d708f770971c..4354aac2d270 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -722,7 +722,7 @@ void iproc_pll_clk_setup(struct device_node *node, int i, ret; struct iproc_pll *pll; struct iproc_clk *iclk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *parent_name; struct iproc_clk *iclk_array; struct clk_hw_onecell_data *clk_data; From c4e5c5900653ada3e5f647244a167c92b0a2ef90 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:14 +0200 Subject: [PATCH 014/168] clk: berlin: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/berlin/berlin2-avpll.c | 4 ++-- drivers/clk/berlin/berlin2-pll.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/berlin/berlin2-avpll.c b/drivers/clk/berlin/berlin2-avpll.c index c801d42397bf..33a3cc16b0cc 100644 --- a/drivers/clk/berlin/berlin2-avpll.c +++ b/drivers/clk/berlin/berlin2-avpll.c @@ -181,8 +181,8 @@ int __init berlin2_avpll_vco_register(void __iomem *base, const char *name, const char *parent_name, u8 vco_flags, unsigned long flags) { + struct clk_init_data init = {}; struct berlin2_avpll_vco *vco; - struct clk_init_data init; vco = kzalloc_obj(*vco); if (!vco) @@ -358,7 +358,7 @@ int __init berlin2_avpll_channel_register(void __iomem *base, u8 ch_flags, unsigned long flags) { struct berlin2_avpll_channel *ch; - struct clk_init_data init; + struct clk_init_data init = {}; ch = kzalloc_obj(*ch); if (!ch) diff --git a/drivers/clk/berlin/berlin2-pll.c b/drivers/clk/berlin/berlin2-pll.c index d0ec3d0bcf3e..1c4203736ecf 100644 --- a/drivers/clk/berlin/berlin2-pll.c +++ b/drivers/clk/berlin/berlin2-pll.c @@ -78,7 +78,7 @@ berlin2_pll_register(const struct berlin2_pll_map *map, void __iomem *base, const char *name, const char *parent_name, unsigned long flags) { - struct clk_init_data init; + struct clk_init_data init = {}; struct berlin2_pll *pll; pll = kzalloc_obj(*pll); From c78035fea04a6fc953b131c122919cdf9c826405 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:15 +0200 Subject: [PATCH 015/168] clk: cdce925: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Reviewed-by: Liviu Dudau Message-ID: <308a33a0e63241d94ee08a08a6de6cffa739556e.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-cdce925.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index 30d0493c7718..4d49cc1659c0 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -620,7 +620,7 @@ static int cdce925_probe(struct i2c_client *client) struct device_node *node = client->dev.of_node; const char *parent_name; const char *pll_clk_name[MAX_NUMBER_OF_PLLS] = {NULL,}; - struct clk_init_data init; + struct clk_init_data init = {}; u32 value; int i; int err; From babffbad2c91a4e9175078e84e931eb65e64066d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:16 +0200 Subject: [PATCH 016/168] clk: clk-axi-clkgen: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <2c6fe5e2efb86c8fec0b19cb14cfa1e3be5b6b99.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-axi-clkgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 6fcee41447e4..e53256c56dfa 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -568,7 +568,7 @@ static int axi_clkgen_probe(struct platform_device *pdev) const struct axi_clkgen_limits *dflt_limits; struct axi_clkgen *axi_clkgen; unsigned int pcore_version; - struct clk_init_data init; + struct clk_init_data init = {}; const char *parent_names[2]; const char *clk_name; struct clk *axi_clk; From 8ed7cb12be01382da35c2344a4ff255c797c00aa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:17 +0200 Subject: [PATCH 017/168] clk: cs2000-cp: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/clk-cs2000-cp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-cs2000-cp.c b/drivers/clk/clk-cs2000-cp.c index e415bdff4d97..aa1823b3100e 100644 --- a/drivers/clk/clk-cs2000-cp.c +++ b/drivers/clk/clk-cs2000-cp.c @@ -461,7 +461,7 @@ static int cs2000_clk_register(struct cs2000_priv *priv) { struct device *dev = priv_to_dev(priv); struct device_node *np = dev->of_node; - struct clk_init_data init; + struct clk_init_data init = {}; const char *name = np->name; static const char *parent_names[CLK_MAX]; u32 aux_out = 0; From 9cb9148fdd1c46613dd30b493f0c2a6f611f6dee Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:18 +0200 Subject: [PATCH 018/168] clk: davinci: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Reviewed-by: David Lechner Message-ID: Signed-off-by: Brian Masney --- drivers/clk/davinci/da8xx-cfgchip.c | 4 ++-- drivers/clk/davinci/pll.c | 2 +- drivers/clk/davinci/psc.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index a5109fe8b16e..9d7fced898ae 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -91,7 +91,7 @@ da8xx_cfgchip_gate_clk_register(struct device *dev, struct clk *parent; const char *parent_name; struct da8xx_cfgchip_gate_clk *gate; - struct clk_init_data init; + struct clk_init_data init = {}; int ret; parent = devm_clk_get(dev, NULL); @@ -241,7 +241,7 @@ da8xx_cfgchip_mux_clk_register(struct device *dev, { const char * const parent_names[] = { info->parent0, info->parent1 }; struct da8xx_cfgchip_mux_clk *mux; - struct clk_init_data init; + struct clk_init_data init = {}; int ret; mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); diff --git a/drivers/clk/davinci/pll.c b/drivers/clk/davinci/pll.c index f73b0ac5d8a0..0e58b02d7aca 100644 --- a/drivers/clk/davinci/pll.c +++ b/drivers/clk/davinci/pll.c @@ -371,7 +371,7 @@ struct clk *davinci_pll_clk_register(struct device *dev, char pllout_name[MAX_NAME_SIZE]; char postdiv_name[MAX_NAME_SIZE]; char pllen_name[MAX_NAME_SIZE]; - struct clk_init_data init; + struct clk_init_data init = {}; struct davinci_pll_clk *pllout; struct davinci_pllen_clk *pllen; struct clk *oscin_clk = NULL; diff --git a/drivers/clk/davinci/psc.c b/drivers/clk/davinci/psc.c index ff603520d56f..73dce7ce2be6 100644 --- a/drivers/clk/davinci/psc.c +++ b/drivers/clk/davinci/psc.c @@ -234,7 +234,7 @@ davinci_lpsc_clk_register(struct device *dev, const char *name, const char *parent_name, struct regmap *regmap, u32 md, u32 pd, u32 flags) { - struct clk_init_data init; + struct clk_init_data init = {}; struct davinci_lpsc_clk *lpsc; int ret; bool is_on; From c90b2b664edd4ed33bee0c8a2b3d61bf0217f8b9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:19 +0200 Subject: [PATCH 019/168] clk: fractional-divider: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/clk-fractional-divider.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 1c5fdcb68a50..c8e00d75cd14 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -271,7 +271,7 @@ struct clk_hw *clk_hw_register_fractional_divider(struct device *dev, u8 clk_divider_flags, spinlock_t *lock) { struct clk_fractional_divider *fd; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_hw *hw; int ret; From 732daf59dcf72ae76bfd5726313cb90c760a0d2d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:20 +0200 Subject: [PATCH 020/168] clk: gemini: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Message-ID: <33f8a87834a75b6677894f1993c90f00eb6a2547.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-gemini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-gemini.c b/drivers/clk/clk-gemini.c index 9c0e6e7a7cac..4e874392e3b0 100644 --- a/drivers/clk/clk-gemini.c +++ b/drivers/clk/clk-gemini.c @@ -193,8 +193,8 @@ static struct clk_hw *gemini_pci_clk_setup(const char *name, const char *parent_name, struct regmap *map) { + struct clk_init_data init = {}; struct clk_gemini_pci *pciclk; - struct clk_init_data init; int ret; pciclk = kzalloc_obj(*pciclk); From 530bb0068f79fcffb5ab1d504adcacbfbc008375 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:21 +0200 Subject: [PATCH 021/168] clk: highbank: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <21a8ecd80d87eb4fbea3a098957ccf8450299efd.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-highbank.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c index e9b177811dfc..61c231997635 100644 --- a/drivers/clk/clk-highbank.c +++ b/drivers/clk/clk-highbank.c @@ -269,7 +269,7 @@ static void __init hb_clk_init(struct device_node *node, const struct clk_ops *o struct hb_clk *hb_clk; const char *clk_name = node->name; const char *parent_name; - struct clk_init_data init; + struct clk_init_data init = {}; struct device_node *srnp; int rc; From 7a2a3a1dbe88ada07f2269122e94a288b100687f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:22 +0200 Subject: [PATCH 022/168] clk: hisilicon: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <04ef5b163e1ae63ffd6b568d3544c482b43f347f.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/hisilicon/clk-hi3559a.c | 2 +- drivers/clk/hisilicon/clk-hi3620.c | 2 +- drivers/clk/hisilicon/clk-hi6220-stub.c | 2 +- drivers/clk/hisilicon/clk-hisi-phase.c | 2 +- drivers/clk/hisilicon/clk-hix5hd2.c | 2 +- drivers/clk/hisilicon/clkdivider-hi6220.c | 2 +- drivers/clk/hisilicon/clkgate-separated.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/hisilicon/clk-hi3559a.c b/drivers/clk/hisilicon/clk-hi3559a.c index f297fb25c512..fea6fb9e98f5 100644 --- a/drivers/clk/hisilicon/clk-hi3559a.c +++ b/drivers/clk/hisilicon/clk-hi3559a.c @@ -456,8 +456,8 @@ static void hisi_clk_register_pll(struct hi3559av100_pll_clock *clks, { void __iomem *base = data->base; struct hi3559av100_clk_pll *p_clk = NULL; + struct clk_init_data init = {}; struct clk *clk = NULL; - struct clk_init_data init; int i; p_clk = devm_kcalloc(dev, nums, sizeof(*p_clk), GFP_KERNEL); diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index 8dcad74e679a..a2c4637eaa98 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -410,9 +410,9 @@ static const struct clk_ops clk_mmc_ops = { static struct clk *hisi_register_clk_mmc(struct hisi_mmc_clock *mmc_clk, void __iomem *base, struct device_node *np) { + struct clk_init_data init = {}; struct clk_mmc *mclk; struct clk *clk; - struct clk_init_data init; mclk = kzalloc_obj(*mclk); if (!mclk) diff --git a/drivers/clk/hisilicon/clk-hi6220-stub.c b/drivers/clk/hisilicon/clk-hi6220-stub.c index bf99cfafafa0..a70544d2bdb9 100644 --- a/drivers/clk/hisilicon/clk-hi6220-stub.c +++ b/drivers/clk/hisilicon/clk-hi6220-stub.c @@ -195,7 +195,7 @@ static const struct clk_ops hi6220_stub_clk_ops = { static int hi6220_stub_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct clk_init_data init; + struct clk_init_data init = {}; struct hi6220_stub_clk *stub_clk; struct clk *clk; struct device_node *np = pdev->dev.of_node; diff --git a/drivers/clk/hisilicon/clk-hisi-phase.c b/drivers/clk/hisilicon/clk-hisi-phase.c index ba6afad66a2b..d8e555d9728d 100644 --- a/drivers/clk/hisilicon/clk-hisi-phase.c +++ b/drivers/clk/hisilicon/clk-hisi-phase.c @@ -94,8 +94,8 @@ struct clk *clk_register_hisi_phase(struct device *dev, const struct hisi_phase_clock *clks, void __iomem *base, spinlock_t *lock) { + struct clk_init_data init = {}; struct clk_hisi_phase *phase; - struct clk_init_data init; phase = devm_kzalloc(dev, sizeof(struct clk_hisi_phase), GFP_KERNEL); if (!phase) diff --git a/drivers/clk/hisilicon/clk-hix5hd2.c b/drivers/clk/hisilicon/clk-hix5hd2.c index 57db6fab43aa..4b7ebebfac4b 100644 --- a/drivers/clk/hisilicon/clk-hix5hd2.c +++ b/drivers/clk/hisilicon/clk-hix5hd2.c @@ -258,8 +258,8 @@ hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks, int nums, for (i = 0; i < nums; i++) { struct hix5hd2_clk_complex *p_clk; + struct clk_init_data init = {}; struct clk *clk; - struct clk_init_data init; p_clk = kzalloc_obj(*p_clk); if (!p_clk) diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c index 20a337383a1e..cc53d0a33e3c 100644 --- a/drivers/clk/hisilicon/clkdivider-hi6220.c +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c @@ -103,7 +103,7 @@ struct clk *hi6220_register_clkdiv(struct device *dev, const char *name, { struct hi6220_clk_divider *div; struct clk *clk; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_div_table *table; u32 max_div, min_div; int i; diff --git a/drivers/clk/hisilicon/clkgate-separated.c b/drivers/clk/hisilicon/clkgate-separated.c index 199303157ebd..e02d6bb5ada7 100644 --- a/drivers/clk/hisilicon/clkgate-separated.c +++ b/drivers/clk/hisilicon/clkgate-separated.c @@ -87,8 +87,8 @@ struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name, u8 clk_gate_flags, spinlock_t *lock) { struct clkgate_separated *sclk; + struct clk_init_data init = {}; struct clk *clk; - struct clk_init_data init; sclk = kzalloc_obj(*sclk); if (!sclk) From b61d1be7a8fb91be6b75681728a42abc8e0f775a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:23 +0200 Subject: [PATCH 023/168] clk: imx: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Acked-by: Abel Vesa Message-ID: <7300fde72b6449d2cd7c043e4caec9a6c4171424.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/imx/clk-busy.c | 4 ++-- drivers/clk/imx/clk-cpu.c | 2 +- drivers/clk/imx/clk-divider-gate.c | 2 +- drivers/clk/imx/clk-fixup-div.c | 2 +- drivers/clk/imx/clk-fixup-mux.c | 2 +- drivers/clk/imx/clk-frac-pll.c | 2 +- drivers/clk/imx/clk-fracn-gppll.c | 2 +- drivers/clk/imx/clk-gate-93.c | 2 +- drivers/clk/imx/clk-gate-exclusive.c | 2 +- drivers/clk/imx/clk-gate2.c | 2 +- drivers/clk/imx/clk-lpcg-scu.c | 2 +- drivers/clk/imx/clk-pfd.c | 2 +- drivers/clk/imx/clk-pfdv2.c | 2 +- drivers/clk/imx/clk-pll14xx.c | 2 +- drivers/clk/imx/clk-pllv1.c | 2 +- drivers/clk/imx/clk-pllv2.c | 2 +- drivers/clk/imx/clk-pllv3.c | 2 +- drivers/clk/imx/clk-pllv4.c | 2 +- drivers/clk/imx/clk-scu.c | 4 ++-- drivers/clk/imx/clk-sscg-pll.c | 2 +- 20 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index b8b6e7c7e1fe..75a2bf29e42f 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -78,8 +78,8 @@ struct clk_hw *imx_clk_hw_busy_divider(const char *name, const char *parent_name void __iomem *busy_reg, u8 busy_shift) { struct clk_busy_divider *busy; + struct clk_init_data init = {}; struct clk_hw *hw; - struct clk_init_data init; int ret; busy = kzalloc_obj(*busy); @@ -157,9 +157,9 @@ struct clk_hw *imx_clk_hw_busy_mux(const char *name, void __iomem *reg, u8 shift u8 width, void __iomem *busy_reg, u8 busy_shift, const char * const *parent_names, int num_parents) { + struct clk_init_data init = {}; struct clk_busy_mux *busy; struct clk_hw *hw; - struct clk_init_data init; int ret; busy = kzalloc_obj(*busy); diff --git a/drivers/clk/imx/clk-cpu.c b/drivers/clk/imx/clk-cpu.c index f53dbaacddcc..b4d9722eb17e 100644 --- a/drivers/clk/imx/clk-cpu.c +++ b/drivers/clk/imx/clk-cpu.c @@ -76,9 +76,9 @@ struct clk_hw *imx_clk_hw_cpu(const char *name, const char *parent_name, struct clk *div, struct clk *mux, struct clk *pll, struct clk *step) { + struct clk_init_data init = {}; struct clk_cpu *cpu; struct clk_hw *hw; - struct clk_init_data init; int ret; cpu = kzalloc_obj(*cpu); diff --git a/drivers/clk/imx/clk-divider-gate.c b/drivers/clk/imx/clk-divider-gate.c index 957d132c4607..a1b7c109069c 100644 --- a/drivers/clk/imx/clk-divider-gate.c +++ b/drivers/clk/imx/clk-divider-gate.c @@ -179,8 +179,8 @@ struct clk_hw *imx_clk_hw_divider_gate(const char *name, const char *parent_name const struct clk_div_table *table, spinlock_t *lock) { - struct clk_init_data init; struct clk_divider_gate *div_gate; + struct clk_init_data init = {}; struct clk_hw *hw; u32 val; int ret; diff --git a/drivers/clk/imx/clk-fixup-div.c b/drivers/clk/imx/clk-fixup-div.c index 3866319af54e..a6f68317cd2e 100644 --- a/drivers/clk/imx/clk-fixup-div.c +++ b/drivers/clk/imx/clk-fixup-div.c @@ -90,8 +90,8 @@ struct clk_hw *imx_clk_hw_fixup_divider(const char *name, const char *parent, void (*fixup)(u32 *val)) { struct clk_fixup_div *fixup_div; + struct clk_init_data init = {}; struct clk_hw *hw; - struct clk_init_data init; int ret; if (!fixup) diff --git a/drivers/clk/imx/clk-fixup-mux.c b/drivers/clk/imx/clk-fixup-mux.c index 7188cdad79d3..f43648f7fb45 100644 --- a/drivers/clk/imx/clk-fixup-mux.c +++ b/drivers/clk/imx/clk-fixup-mux.c @@ -70,8 +70,8 @@ struct clk_hw *imx_clk_hw_fixup_mux(const char *name, void __iomem *reg, int num_parents, void (*fixup)(u32 *val)) { struct clk_fixup_mux *fixup_mux; + struct clk_init_data init = {}; struct clk_hw *hw; - struct clk_init_data init; int ret; if (!fixup) diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c index cd4e26bac19c..d6c59634c0c0 100644 --- a/drivers/clk/imx/clk-frac-pll.c +++ b/drivers/clk/imx/clk-frac-pll.c @@ -208,7 +208,7 @@ struct clk_hw *imx_clk_hw_frac_pll(const char *name, const char *parent_name, void __iomem *base) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_frac_pll *pll; struct clk_hw *hw; int ret; diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 4048c16c0578..32bb3e9a8d6e 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -363,9 +363,9 @@ static struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_ const struct imx_fracn_gppll_clk *pll_clk, u32 pll_flags) { + struct clk_init_data init = {}; struct clk_fracn_gppll *pll; struct clk_hw *hw; - struct clk_init_data init; int ret; pll = kzalloc_obj(*pll); diff --git a/drivers/clk/imx/clk-gate-93.c b/drivers/clk/imx/clk-gate-93.c index 7acbcfec9610..7208138d615d 100644 --- a/drivers/clk/imx/clk-gate-93.c +++ b/drivers/clk/imx/clk-gate-93.c @@ -158,9 +158,9 @@ struct clk_hw *imx93_clk_gate(struct device *dev, const char *name, const char * unsigned long flags, void __iomem *reg, u32 bit_idx, u32 val, u32 mask, u32 domain_id, unsigned int *share_count) { + struct clk_init_data init = {}; struct imx93_clk_gate *gate; struct clk_hw *hw; - struct clk_init_data init; int ret; u32 authen; diff --git a/drivers/clk/imx/clk-gate-exclusive.c b/drivers/clk/imx/clk-gate-exclusive.c index 504cfeef28a0..cf873e490362 100644 --- a/drivers/clk/imx/clk-gate-exclusive.c +++ b/drivers/clk/imx/clk-gate-exclusive.c @@ -59,9 +59,9 @@ struct clk_hw *imx_clk_hw_gate_exclusive(const char *name, const char *parent, void __iomem *reg, u8 shift, u32 exclusive_mask) { struct clk_gate_exclusive *exgate; + struct clk_init_data init = {}; struct clk_gate *gate; struct clk_hw *hw; - struct clk_init_data init; int ret; if (exclusive_mask == 0) diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index f07cf82dd9c9..c8b6323571ee 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -139,9 +139,9 @@ struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name, u8 clk_gate2_flags, spinlock_t *lock, unsigned int *share_count) { + struct clk_init_data init = {}; struct clk_gate2 *gate; struct clk_hw *hw; - struct clk_init_data init; int ret; gate = kzalloc_obj(struct clk_gate2); diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index 03bbfbe9bff3..da110a823fd5 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -114,8 +114,8 @@ struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, bool hw_gate) { + struct clk_init_data init = {}; struct clk_lpcg_scu *clk; - struct clk_init_data init; struct clk_hw *hw; int ret; diff --git a/drivers/clk/imx/clk-pfd.c b/drivers/clk/imx/clk-pfd.c index e7a5d80c5008..e56bb27e57cc 100644 --- a/drivers/clk/imx/clk-pfd.c +++ b/drivers/clk/imx/clk-pfd.c @@ -127,9 +127,9 @@ static const struct clk_ops clk_pfd_ops = { struct clk_hw *imx_clk_hw_pfd(const char *name, const char *parent_name, void __iomem *reg, u8 idx) { + struct clk_init_data init = {}; struct clk_pfd *pfd; struct clk_hw *hw; - struct clk_init_data init; int ret; pfd = kzalloc_obj(*pfd); diff --git a/drivers/clk/imx/clk-pfdv2.c b/drivers/clk/imx/clk-pfdv2.c index 0f92b92e2229..43ba79e47eac 100644 --- a/drivers/clk/imx/clk-pfdv2.c +++ b/drivers/clk/imx/clk-pfdv2.c @@ -203,7 +203,7 @@ static const struct clk_ops clk_pfdv2_ops = { struct clk_hw *imx_clk_hw_pfdv2(enum imx_pfdv2_type type, const char *name, const char *parent_name, void __iomem *reg, u8 idx) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_pfdv2 *pfd; struct clk_hw *hw; int ret; diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index b6f1cc9f5700..2f9e36f9e240 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -515,9 +515,9 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name, const char *parent_name, void __iomem *base, const struct imx_pll14xx_clk *pll_clk) { + struct clk_init_data init = {}; struct clk_pll14xx *pll; struct clk_hw *hw; - struct clk_init_data init; int ret; u32 val; diff --git a/drivers/clk/imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c index da5531e57da2..ee60c7660ef4 100644 --- a/drivers/clk/imx/clk-pllv1.c +++ b/drivers/clk/imx/clk-pllv1.c @@ -114,9 +114,9 @@ static const struct clk_ops clk_pllv1_ops = { struct clk_hw *imx_clk_hw_pllv1(enum imx_pllv1_type type, const char *name, const char *parent, void __iomem *base) { + struct clk_init_data init = {}; struct clk_pllv1 *pll; struct clk_hw *hw; - struct clk_init_data init; int ret; pll = kmalloc_obj(*pll); diff --git a/drivers/clk/imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c index 43396388030e..aacc3d84e797 100644 --- a/drivers/clk/imx/clk-pllv2.c +++ b/drivers/clk/imx/clk-pllv2.c @@ -249,9 +249,9 @@ static const struct clk_ops clk_pllv2_ops = { struct clk_hw *imx_clk_hw_pllv2(const char *name, const char *parent, void __iomem *base) { + struct clk_init_data init = {}; struct clk_pllv2 *pll; struct clk_hw *hw; - struct clk_init_data init; int ret; pll = kzalloc_obj(*pll); diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index a0ad6f4aae8f..714d9c723e16 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -422,8 +422,8 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name, { struct clk_pllv3 *pll; const struct clk_ops *ops; + struct clk_init_data init = {}; struct clk_hw *hw; - struct clk_init_data init; int ret; pll = kzalloc_obj(*pll); diff --git a/drivers/clk/imx/clk-pllv4.c b/drivers/clk/imx/clk-pllv4.c index 8fa2f7111ce9..6dc9640d2f19 100644 --- a/drivers/clk/imx/clk-pllv4.c +++ b/drivers/clk/imx/clk-pllv4.c @@ -246,9 +246,9 @@ static const struct clk_ops clk_pllv4_ops = { struct clk_hw *imx_clk_hw_pllv4(enum imx_pllv4_type type, const char *name, const char *parent_name, void __iomem *base) { + struct clk_init_data init = {}; struct clk_pllv4 *pll; struct clk_hw *hw; - struct clk_init_data init; int ret; pll = kzalloc_obj(*pll); diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c index 44220e9c5c2a..0d034e206c6b 100644 --- a/drivers/clk/imx/clk-scu.c +++ b/drivers/clk/imx/clk-scu.c @@ -445,7 +445,7 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name, const char * const *parents, int num_parents, u32 rsrc_id, u8 clk_type) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_scu *clk; struct clk_hw *hw; int ret; @@ -839,9 +839,9 @@ struct clk_hw *__imx_clk_gpr_scu(const char *name, const char * const *parent_na bool invert) { struct imx_scu_clk_node *clk_node; + struct clk_init_data init = {}; struct clk_gpr_scu *clk; struct clk_hw *hw; - struct clk_init_data init; int ret; if (rsrc_id >= IMX_SC_R_LAST || gpr_id >= IMX_SC_C_LAST) diff --git a/drivers/clk/imx/clk-sscg-pll.c b/drivers/clk/imx/clk-sscg-pll.c index 7f104ecfa80f..f6286ec11e0c 100644 --- a/drivers/clk/imx/clk-sscg-pll.c +++ b/drivers/clk/imx/clk-sscg-pll.c @@ -504,8 +504,8 @@ struct clk_hw *imx_clk_hw_sscg_pll(const char *name, void __iomem *base, unsigned long flags) { + struct clk_init_data init = {}; struct clk_sscg_pll *pll; - struct clk_init_data init; struct clk_hw *hw; int ret; From 967c621add03627126af3fce8a482b345e5bcd1c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:24 +0200 Subject: [PATCH 024/168] clk: ingenic: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Acked-by: Paul Cercueil Message-ID: Signed-off-by: Brian Masney --- drivers/clk/ingenic/cgu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index 41e4c69131bd..ad223aa20e8d 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -644,8 +644,8 @@ static const struct clk_ops ingenic_clk_ops = { static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx) { const struct ingenic_cgu_clk_info *clk_info = &cgu->clock_info[idx]; - struct clk_init_data clk_init; struct ingenic_clk *ingenic_clk = NULL; + struct clk_init_data clk_init = {}; struct clk *clk, *parent; const char *parent_names[4]; unsigned caps, i, num_possible; From 1c72603a6f0ff617deceb5351ceff2bcc9081b25 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:25 +0200 Subject: [PATCH 025/168] clk: keystone: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/keystone/gate.c | 2 +- drivers/clk/keystone/pll.c | 2 +- drivers/clk/keystone/syscon-clk.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c index 03e854f10fd9..e83e3d4c7d67 100644 --- a/drivers/clk/keystone/gate.c +++ b/drivers/clk/keystone/gate.c @@ -164,7 +164,7 @@ static struct clk *clk_register_psc(struct device *dev, struct clk_psc_data *psc_data, spinlock_t *lock) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_psc *psc; struct clk *clk; diff --git a/drivers/clk/keystone/pll.c b/drivers/clk/keystone/pll.c index ed197ee0cc88..020d5f4e9ed6 100644 --- a/drivers/clk/keystone/pll.c +++ b/drivers/clk/keystone/pll.c @@ -122,7 +122,7 @@ static struct clk *clk_register_pll(struct device *dev, const char *parent_name, struct clk_pll_data *pll_data) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_pll *pll; struct clk *clk; diff --git a/drivers/clk/keystone/syscon-clk.c b/drivers/clk/keystone/syscon-clk.c index ecf180a7949c..338174be4121 100644 --- a/drivers/clk/keystone/syscon-clk.c +++ b/drivers/clk/keystone/syscon-clk.c @@ -67,7 +67,7 @@ static struct clk_hw const struct ti_syscon_gate_clk_data *data) { struct ti_syscon_gate_clk_priv *priv; - struct clk_init_data init; + struct clk_init_data init = {}; char *name = NULL; int ret; From a7d37e6c9331edd6cb89ed9766e4ea4ec179c043 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:26 +0200 Subject: [PATCH 026/168] clk: lmk04832: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <357cf49d53cc8abc27f3ec3372b8de587e2278c9.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-lmk04832.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c index f9a0684d2628..10e5cfa96e6b 100644 --- a/drivers/clk/clk-lmk04832.c +++ b/drivers/clk/clk-lmk04832.c @@ -587,8 +587,8 @@ static const struct clk_ops lmk04832_vco_ops = { */ static int lmk04832_register_vco(struct lmk04832 *lmk) { + struct clk_init_data init = {}; const char *parent_names[1]; - struct clk_init_data init; int ret; init.name = "lmk-vco"; @@ -947,8 +947,8 @@ static const struct clk_ops lmk04832_sclk_ops = { static int lmk04832_register_sclk(struct lmk04832 *lmk) { + struct clk_init_data init = {}; const char *parent_names[1]; - struct clk_init_data init; int ret; init.name = "lmk-sclk"; @@ -1292,8 +1292,8 @@ static int lmk04832_register_clkout(struct lmk04832 *lmk, const int num) { char name[] = "lmk-clkoutXX"; char dclk_name[] = "lmk-dclkXX_YY"; + struct clk_init_data init = {}; const char *parent_names[2]; - struct clk_init_data init; int dclk_num = num / 2; int ret; From 472ea753e5641b0ba15a9cdd9fa7f7884d88ce59 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:27 +0200 Subject: [PATCH 027/168] clk: mediatek: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <6cf9d1621379b34175743e764aaea3ed514db01b.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/mediatek/clk-cpumux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/mediatek/clk-cpumux.c b/drivers/clk/mediatek/clk-cpumux.c index 412558b95127..9799bc156dcc 100644 --- a/drivers/clk/mediatek/clk-cpumux.c +++ b/drivers/clk/mediatek/clk-cpumux.c @@ -62,9 +62,9 @@ static struct clk_hw * mtk_clk_register_cpumux(struct device *dev, const struct mtk_composite *mux, struct regmap *regmap) { + struct clk_init_data init = {}; struct mtk_clk_cpumux *cpumux; int ret; - struct clk_init_data init; cpumux = kzalloc_obj(*cpumux); if (!cpumux) From 61f678fa711fbbbeac611f6aaea5b88fac0b66d3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:28 +0200 Subject: [PATCH 028/168] clk: milbeaut: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <79693c173c0b74a8d176e51409b89cd14156179b.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-milbeaut.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-milbeaut.c b/drivers/clk/clk-milbeaut.c index 4265bc442dfd..485540b95528 100644 --- a/drivers/clk/clk-milbeaut.c +++ b/drivers/clk/clk-milbeaut.c @@ -328,9 +328,9 @@ static struct clk_hw *m10v_clk_hw_register_mux(struct device *dev, u8 shift, u32 mask, u8 clk_mux_flags, u32 *table, spinlock_t *lock) { + struct clk_init_data init = {}; struct clk_mux *mux; struct clk_hw *hw; - struct clk_init_data init; int ret; mux = kzalloc_obj(*mux); @@ -459,9 +459,9 @@ static struct clk_hw *m10v_clk_hw_register_divider(struct device *dev, u8 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock, void __iomem *write_valid_reg) { + struct clk_init_data init = {}; struct m10v_clk_divider *div; struct clk_hw *hw; - struct clk_init_data init; int ret; div = kzalloc_obj(*div); From 6dab17f8c83348f00e7068e6fa90f46396d7e4e1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:29 +0200 Subject: [PATCH 029/168] clk: mmp: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/mmp/clk-apbc.c | 2 +- drivers/clk/mmp/clk-apmu.c | 2 +- drivers/clk/mmp/clk-frac.c | 2 +- drivers/clk/mmp/clk-gate.c | 2 +- drivers/clk/mmp/clk-mix.c | 2 +- drivers/clk/mmp/clk-pll.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/clk/mmp/clk-apbc.c b/drivers/clk/mmp/clk-apbc.c index 84532ce8fd09..338ccd8fe99c 100644 --- a/drivers/clk/mmp/clk-apbc.c +++ b/drivers/clk/mmp/clk-apbc.c @@ -120,9 +120,9 @@ struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name, void __iomem *base, unsigned int delay, unsigned int apbc_flags, spinlock_t *lock) { + struct clk_init_data init = {}; struct clk_apbc *apbc; struct clk *clk; - struct clk_init_data init; apbc = kzalloc_obj(*apbc); if (!apbc) diff --git a/drivers/clk/mmp/clk-apmu.c b/drivers/clk/mmp/clk-apmu.c index 30bbac1deca1..887854d8f5b1 100644 --- a/drivers/clk/mmp/clk-apmu.c +++ b/drivers/clk/mmp/clk-apmu.c @@ -65,9 +65,9 @@ static const struct clk_ops clk_apmu_ops = { struct clk *mmp_clk_register_apmu(const char *name, const char *parent_name, void __iomem *base, u32 enable_mask, spinlock_t *lock) { + struct clk_init_data init = {}; struct clk_apmu *apmu; struct clk *clk; - struct clk_init_data init; apmu = kzalloc_obj(*apmu); if (!apmu) diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c index 13bfc4c99f3a..5774354563aa 100644 --- a/drivers/clk/mmp/clk-frac.c +++ b/drivers/clk/mmp/clk-frac.c @@ -171,8 +171,8 @@ struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, struct mmp_clk_factor_masks *masks, struct u32_fract *ftbl, unsigned int ftbl_cnt, spinlock_t *lock) { + struct clk_init_data init = {}; struct mmp_clk_factor *factor; - struct clk_init_data init; struct clk *clk; if (!masks) { diff --git a/drivers/clk/mmp/clk-gate.c b/drivers/clk/mmp/clk-gate.c index cc2f841ae9d9..e8dad4ed0125 100644 --- a/drivers/clk/mmp/clk-gate.c +++ b/drivers/clk/mmp/clk-gate.c @@ -94,9 +94,9 @@ struct clk *mmp_clk_register_gate(struct device *dev, const char *name, void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable, unsigned int gate_flags, spinlock_t *lock) { + struct clk_init_data init = {}; struct mmp_clk_gate *gate; struct clk *clk; - struct clk_init_data init; /* allocate the gate */ gate = kzalloc_obj(*gate); diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index b1c9899c71af..2f3d1cb6f836 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -444,9 +444,9 @@ struct clk *mmp_clk_register_mix(struct device *dev, struct mmp_clk_mix_config *config, spinlock_t *lock) { + struct clk_init_data init = {}; struct mmp_clk_mix *mix; struct clk *clk; - struct clk_init_data init; mix = kzalloc_obj(*mix); if (!mix) diff --git a/drivers/clk/mmp/clk-pll.c b/drivers/clk/mmp/clk-pll.c index 430f5e3c8540..e0ea29b5bb66 100644 --- a/drivers/clk/mmp/clk-pll.c +++ b/drivers/clk/mmp/clk-pll.c @@ -104,9 +104,9 @@ static struct clk *mmp_clk_register_pll(char *name, unsigned long input_rate, void __iomem *postdiv_reg, u8 postdiv_shift) { + struct clk_init_data init = {}; struct mmp_clk_pll *pll; struct clk *clk; - struct clk_init_data init; pll = kzalloc_obj(*pll); if (!pll) From 9d31f4b021f283adfa021a4ff0410763731a4d34 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:30 +0200 Subject: [PATCH 030/168] clk: mvebu: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/mvebu/ap-cpu-clk.c | 2 +- drivers/clk/mvebu/clk-corediv.c | 2 +- drivers/clk/mvebu/clk-cpu.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/mvebu/ap-cpu-clk.c b/drivers/clk/mvebu/ap-cpu-clk.c index 1e44ace7d951..721cad421867 100644 --- a/drivers/clk/mvebu/ap-cpu-clk.c +++ b/drivers/clk/mvebu/ap-cpu-clk.c @@ -286,7 +286,7 @@ static int ap_cpu_clock_probe(struct platform_device *pdev) for_each_of_cpu_node(dn) { char *clk_name = "cpu-cluster-0"; - struct clk_init_data init; + struct clk_init_data init = {}; const char *parent_name; struct clk *parent; u64 cpu; diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c index ae48293b0c41..e26ada3c29ae 100644 --- a/drivers/clk/mvebu/clk-corediv.c +++ b/drivers/clk/mvebu/clk-corediv.c @@ -253,7 +253,7 @@ static void __init mvebu_corediv_clk_init(struct device_node *node, const struct clk_corediv_soc_desc *soc_desc) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_corediv *corediv; struct clk **clks; void __iomem *base; diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c index 24196e288fe2..a7646a25726b 100644 --- a/drivers/clk/mvebu/clk-cpu.c +++ b/drivers/clk/mvebu/clk-cpu.c @@ -192,7 +192,7 @@ static void __init of_cpu_clk_setup(struct device_node *node) goto clks_out; for_each_possible_cpu(cpu) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk *clk; char *clk_name = kzalloc(5, GFP_KERNEL); From 523fd58a9c39ee50da8e9e9de8b28f50b290cb0e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:31 +0200 Subject: [PATCH 031/168] clk: mxs: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/mxs/clk-div.c | 2 +- drivers/clk/mxs/clk-frac.c | 2 +- drivers/clk/mxs/clk-pll.c | 2 +- drivers/clk/mxs/clk-ref.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c index fe7224162b3c..d4ee785c6511 100644 --- a/drivers/clk/mxs/clk-div.c +++ b/drivers/clk/mxs/clk-div.c @@ -70,9 +70,9 @@ static const struct clk_ops clk_div_ops = { struct clk *mxs_clk_div(const char *name, const char *parent_name, void __iomem *reg, u8 shift, u8 width, u8 busy) { + struct clk_init_data init = {}; struct clk_div *div; struct clk *clk; - struct clk_init_data init; div = kzalloc_obj(*div); if (!div) diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c index 52eb82fde322..e317710ab503 100644 --- a/drivers/clk/mxs/clk-frac.c +++ b/drivers/clk/mxs/clk-frac.c @@ -112,9 +112,9 @@ static const struct clk_ops clk_frac_ops = { struct clk *mxs_clk_frac(const char *name, const char *parent_name, void __iomem *reg, u8 shift, u8 width, u8 busy) { + struct clk_init_data init = {}; struct clk_frac *frac; struct clk *clk; - struct clk_init_data init; frac = kzalloc_obj(*frac); if (!frac) diff --git a/drivers/clk/mxs/clk-pll.c b/drivers/clk/mxs/clk-pll.c index 581868e0693c..5acf48cddbb2 100644 --- a/drivers/clk/mxs/clk-pll.c +++ b/drivers/clk/mxs/clk-pll.c @@ -82,9 +82,9 @@ static const struct clk_ops clk_pll_ops = { struct clk *mxs_clk_pll(const char *name, const char *parent_name, void __iomem *base, u8 power, unsigned long rate) { + struct clk_init_data init = {}; struct clk_pll *pll; struct clk *clk; - struct clk_init_data init; pll = kzalloc_obj(*pll); if (!pll) diff --git a/drivers/clk/mxs/clk-ref.c b/drivers/clk/mxs/clk-ref.c index 9667d4d3c2a8..66ea1c229014 100644 --- a/drivers/clk/mxs/clk-ref.c +++ b/drivers/clk/mxs/clk-ref.c @@ -113,9 +113,9 @@ static const struct clk_ops clk_ref_ops = { struct clk *mxs_clk_ref(const char *name, const char *parent_name, void __iomem *reg, u8 idx) { + struct clk_init_data init = {}; struct clk_ref *ref; struct clk *clk; - struct clk_init_data init; ref = kzalloc_obj(*ref); if (!ref) From ecf7f551669e7ab8faf99fbf2d79a2aa9e2b418b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:32 +0200 Subject: [PATCH 032/168] clk: nomadik: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Message-ID: <631df13629bf77d55bda770f94c7b1863690f2e2.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-nomadik.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c index da6b89759a14..890084b3912b 100644 --- a/drivers/clk/clk-nomadik.c +++ b/drivers/clk/clk-nomadik.c @@ -263,7 +263,7 @@ pll_clk_register(struct device *dev, const char *name, { int ret; struct clk_pll *pll; - struct clk_init_data init; + struct clk_init_data init = {}; if (id != 1 && id != 2) { pr_err("%s: the Nomadik has only PLL 1 & 2\n", __func__); @@ -355,7 +355,7 @@ src_clk_register(struct device *dev, const char *name, { int ret; struct clk_src *sclk; - struct clk_init_data init; + struct clk_init_data init = {}; sclk = kzalloc_obj(*sclk); if (!sclk) From 4e00db6819ddf228c4847317a7c03f651c43d952 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:33 +0200 Subject: [PATCH 033/168] clk: npcm7xx: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/clk-npcm7xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-npcm7xx.c b/drivers/clk/clk-npcm7xx.c index 79eca6ee3120..562d2d406d7a 100644 --- a/drivers/clk/clk-npcm7xx.c +++ b/drivers/clk/clk-npcm7xx.c @@ -69,8 +69,8 @@ static struct clk_hw * npcm7xx_clk_register_pll(void __iomem *pllcon, const char *name, const char *parent_name, unsigned long flags) { + struct clk_init_data init = {}; struct npcm7xx_clk_pll *pll; - struct clk_init_data init; struct clk_hw *hw; int ret; From 4d13fa78840c368e669bb7f00cd5a1fbc874e8f9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:34 +0200 Subject: [PATCH 034/168] clk: nxp: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Reviewed-by: Vladimir Zapolskiy Message-ID: Signed-off-by: Brian Masney --- drivers/clk/nxp/clk-lpc18xx-creg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/nxp/clk-lpc18xx-creg.c b/drivers/clk/nxp/clk-lpc18xx-creg.c index 3d3982e9c661..de3c214a80fc 100644 --- a/drivers/clk/nxp/clk-lpc18xx-creg.c +++ b/drivers/clk/nxp/clk-lpc18xx-creg.c @@ -138,7 +138,7 @@ static struct clk *clk_register_creg_clk(struct device *dev, const char **parent_name, struct regmap *syscon) { - struct clk_init_data init; + struct clk_init_data init = {}; init.ops = creg_clk->ops; init.name = creg_clk->name; From cf01bfad8fd234edfff9df71e92a2361e01d69e6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:35 +0200 Subject: [PATCH 035/168] clk: pistachio: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <34b65a00a6a40ddcb7a9f4d3d724e80a00ac9bd2.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/pistachio/clk-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/pistachio/clk-pll.c b/drivers/clk/pistachio/clk-pll.c index 5b268a985a9c..ad997a777632 100644 --- a/drivers/clk/pistachio/clk-pll.c +++ b/drivers/clk/pistachio/clk-pll.c @@ -453,8 +453,8 @@ static struct clk *pll_register(const char *name, const char *parent_name, struct pistachio_pll_rate_table *rates, unsigned int nr_rates) { + struct clk_init_data init = {}; struct pistachio_clk_pll *pll; - struct clk_init_data init; struct clk *clk; pll = kzalloc_obj(*pll); From 80e22db07d9fe8a7d5b406debf1199aaab9452b5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:36 +0200 Subject: [PATCH 036/168] clk: pwm: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/clk-pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-pwm.c b/drivers/clk/clk-pwm.c index 4709f0338e37..2001c7c9367c 100644 --- a/drivers/clk/clk-pwm.c +++ b/drivers/clk/clk-pwm.c @@ -95,7 +95,7 @@ static const struct clk_ops clk_pwm_ops = { static int clk_pwm_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_pwm *clk_pwm; struct pwm_device *pwm; struct pwm_args pargs; From 6a3a8ca3c98d5d81451c29af8a171ca73134490f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:38 +0200 Subject: [PATCH 037/168] clk: rockchip: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Reviewed-by: Heiko Stuebner Reviewed-by: Sebastian Reichel Message-ID: <49127c1f7529acccb17e1408db9f21f6d15aee2b.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/rockchip/clk-cpu.c | 2 +- drivers/clk/rockchip/clk-ddr.c | 2 +- drivers/clk/rockchip/clk-gate-grf.c | 2 +- drivers/clk/rockchip/clk-inverter.c | 2 +- drivers/clk/rockchip/clk-mmc-phase.c | 2 +- drivers/clk/rockchip/clk-muxgrf.c | 2 +- drivers/clk/rockchip/clk-pll.c | 2 +- drivers/clk/rockchip/clk.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c index 6205af9ba88a..eb6b8b878e4d 100644 --- a/drivers/clk/rockchip/clk-cpu.c +++ b/drivers/clk/rockchip/clk-cpu.c @@ -304,7 +304,7 @@ struct clk *rockchip_clk_register_cpuclk(const char *name, int nrates, void __iomem *reg_base, spinlock_t *lock) { struct rockchip_cpuclk *cpuclk; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk *clk, *cclk; int ret; diff --git a/drivers/clk/rockchip/clk-ddr.c b/drivers/clk/rockchip/clk-ddr.c index 81ae8a4ee30e..fbb702d0b9d9 100644 --- a/drivers/clk/rockchip/clk-ddr.c +++ b/drivers/clk/rockchip/clk-ddr.c @@ -97,7 +97,7 @@ struct clk *rockchip_clk_register_ddrclk(const char *name, int flags, spinlock_t *lock) { struct rockchip_ddrclk *ddrclk; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk *clk; ddrclk = kzalloc_obj(*ddrclk); diff --git a/drivers/clk/rockchip/clk-gate-grf.c b/drivers/clk/rockchip/clk-gate-grf.c index 88e409e91a63..458314a25691 100644 --- a/drivers/clk/rockchip/clk-gate-grf.c +++ b/drivers/clk/rockchip/clk-gate-grf.c @@ -73,7 +73,7 @@ struct clk *rockchip_clk_register_gate_grf(const char *name, u8 gate_flags) { struct rockchip_gate_grf *gate; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk *clk; if (IS_ERR(regmap)) { diff --git a/drivers/clk/rockchip/clk-inverter.c b/drivers/clk/rockchip/clk-inverter.c index bf9072ed9fd4..e6c7dad60e96 100644 --- a/drivers/clk/rockchip/clk-inverter.c +++ b/drivers/clk/rockchip/clk-inverter.c @@ -75,8 +75,8 @@ struct clk *rockchip_clk_register_inverter(const char *name, void __iomem *reg, int shift, int flags, spinlock_t *lock) { - struct clk_init_data init; struct rockchip_inv_clock *inv_clock; + struct clk_init_data init = {}; struct clk *clk; inv_clock = kmalloc_obj(*inv_clock); diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c index 4efd22953f3e..d92bea75faf7 100644 --- a/drivers/clk/rockchip/clk-mmc-phase.c +++ b/drivers/clk/rockchip/clk-mmc-phase.c @@ -205,8 +205,8 @@ struct clk *rockchip_clk_register_mmc(const char *name, struct regmap *grf, int grf_reg, int shift) { - struct clk_init_data init; struct rockchip_mmc_clock *mmc_clock; + struct clk_init_data init = {}; struct clk *clk; int ret; diff --git a/drivers/clk/rockchip/clk-muxgrf.c b/drivers/clk/rockchip/clk-muxgrf.c index ccbb1379501a..ecdc77654813 100644 --- a/drivers/clk/rockchip/clk-muxgrf.c +++ b/drivers/clk/rockchip/clk-muxgrf.c @@ -59,7 +59,7 @@ struct clk *rockchip_clk_register_muxgrf(const char *name, int shift, int width, int mux_flags) { struct rockchip_muxgrf_clock *muxgrf_clock; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk *clk; if (IS_ERR(regmap)) { diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c index 706ca4b344d3..7204b09243d4 100644 --- a/drivers/clk/rockchip/clk-pll.c +++ b/drivers/clk/rockchip/clk-pll.c @@ -1069,7 +1069,7 @@ struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx, unsigned long flags, u8 clk_pll_flags) { const char *pll_parents[3]; - struct clk_init_data init; + struct clk_init_data init = {}; struct rockchip_clk_pll *pll; struct clk_mux *pll_mux; struct clk *pll_clk, *mux_clk; diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index ee8c79b938d3..10df21178ba4 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -257,7 +257,7 @@ static struct clk *rockchip_clk_register_frac_branch( if (child) { struct clk_mux *frac_mux = &frac->mux; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk *mux_clk; int ret; From 03f7a64e9d6dc47ae743c86aff9c504741873385 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:39 +0200 Subject: [PATCH 038/168] clk: samsung: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Reviewed-by: Krzysztof Kozlowski Message-ID: <87b3e83137e1a987f3c69d214706e93ef3898cab.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/samsung/clk-cpu.c | 2 +- drivers/clk/samsung/clk-pll.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c index 37cf47533dc6..a17ce26494f3 100644 --- a/drivers/clk/samsung/clk-cpu.c +++ b/drivers/clk/samsung/clk-cpu.c @@ -647,7 +647,7 @@ static int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx, const struct clk_hw *parent, *alt_parent; struct clk_hw **hws; struct exynos_cpuclk *cpuclk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *parent_name; unsigned int num_cfgs; int ret = 0; diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index e74552846ba3..813b8834ef16 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -1591,8 +1591,8 @@ static const struct clk_ops samsung_a9fraco_clk_min_ops = { static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, const struct samsung_pll_clock *pll_clk) { + struct clk_init_data init = {}; struct samsung_clk_pll *pll; - struct clk_init_data init; unsigned int len = 0; int ret; From 40814a899facb59d8a8bc4c2315f7d81237db0a8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:40 +0200 Subject: [PATCH 039/168] clk: scpi: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <939f1be93abebc7967a889e9c24c34942df8229a.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-scpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index 2328d2abf6d8..16796cf3c892 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -128,7 +128,7 @@ static int scpi_clk_ops_init(struct device *dev, const struct of_device_id *match, struct scpi_clk *sclk, const char *name) { - struct clk_init_data init; + struct clk_init_data init = {}; unsigned long min = 0, max = 0; int ret; From 292a454790f2d257a284c1c51b15ca021fee423a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:41 +0200 Subject: [PATCH 040/168] clk: silabs: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/clk-si514.c | 2 +- drivers/clk/clk-si5341.c | 2 +- drivers/clk/clk-si544.c | 2 +- drivers/clk/clk-si570.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c index c0b433ad9372..07091b91420d 100644 --- a/drivers/clk/clk-si514.c +++ b/drivers/clk/clk-si514.c @@ -337,8 +337,8 @@ static const struct regmap_config si514_regmap_config = { static int si514_probe(struct i2c_client *client) { + struct clk_init_data init = {}; struct clk_si514 *data; - struct clk_init_data init; int err; data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c index 5311c23532b4..88522333525b 100644 --- a/drivers/clk/clk-si5341.c +++ b/drivers/clk/clk-si5341.c @@ -1556,8 +1556,8 @@ static const struct attribute *si5341_attributes[] = { static int si5341_probe(struct i2c_client *client) { + struct clk_init_data init = {}; struct clk_si5341 *data; - struct clk_init_data init; struct clk *input; const char *root_clock_name; const char *synth_clock_names[SI5341_NUM_SYNTH] = { NULL }; diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c index 9c520128e0a2..3924ec3e2163 100644 --- a/drivers/clk/clk-si544.c +++ b/drivers/clk/clk-si544.c @@ -445,8 +445,8 @@ static const struct regmap_config si544_regmap_config = { static int si544_probe(struct i2c_client *client) { + struct clk_init_data init = {}; struct clk_si544 *data; - struct clk_init_data init; int err; data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c index 3063e38c66da..ac9013e7379c 100644 --- a/drivers/clk/clk-si570.c +++ b/drivers/clk/clk-si570.c @@ -412,7 +412,7 @@ static const struct regmap_config si570_regmap_config = { static int si570_probe(struct i2c_client *client) { struct clk_si570 *data; - struct clk_init_data init; + struct clk_init_data init = {}; u32 initial_fout, factory_fout, stability; bool skip_recall; int err; From 40322814a647f23392729305330aadc811463549 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:42 +0200 Subject: [PATCH 041/168] clk: socfpga: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Acked-by: Dinh Nguyen Message-ID: <2d38d78f8d59583e29778bebc65eaab911d8a120.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/socfpga/clk-gate-a10.c | 2 +- drivers/clk/socfpga/clk-gate-s10.c | 6 +++--- drivers/clk/socfpga/clk-gate.c | 2 +- drivers/clk/socfpga/clk-periph-a10.c | 2 +- drivers/clk/socfpga/clk-periph-s10.c | 8 ++++---- drivers/clk/socfpga/clk-periph.c | 2 +- drivers/clk/socfpga/clk-pll-a10.c | 2 +- drivers/clk/socfpga/clk-pll-s10.c | 8 ++++---- drivers/clk/socfpga/clk-pll.c | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/clk/socfpga/clk-gate-a10.c b/drivers/clk/socfpga/clk-gate-a10.c index dd8d1713aaff..ba12179061b3 100644 --- a/drivers/clk/socfpga/clk-gate-a10.c +++ b/drivers/clk/socfpga/clk-gate-a10.c @@ -49,7 +49,7 @@ static void __init __socfpga_gate_init(struct device_node *node, struct socfpga_gate_clk *socfpga_clk; const char *clk_name = node->name; const char *parent_name[SOCFPGA_MAX_PARENTS]; - struct clk_init_data init; + struct clk_init_data init = {}; int rc; socfpga_clk = kzalloc_obj(*socfpga_clk); diff --git a/drivers/clk/socfpga/clk-gate-s10.c b/drivers/clk/socfpga/clk-gate-s10.c index 24f56a9edc44..4b23909c5810 100644 --- a/drivers/clk/socfpga/clk-gate-s10.c +++ b/drivers/clk/socfpga/clk-gate-s10.c @@ -128,7 +128,7 @@ struct clk_hw *s10_register_gate(const struct stratix10_gate_clock *clks, void _ { struct clk_hw *hw_clk; struct socfpga_gate_clk *socfpga_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *parent_name = clks->parent_name; int ret; @@ -186,7 +186,7 @@ struct clk_hw *agilex_register_gate(const struct stratix10_gate_clock *clks, voi { struct clk_hw *hw_clk; struct socfpga_gate_clk *socfpga_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *parent_name = clks->parent_name; int ret; @@ -244,7 +244,7 @@ struct clk_hw *agilex5_register_gate(const struct agilex5_gate_clock *clks, void { struct clk_hw *hw_clk; struct socfpga_gate_clk *socfpga_clk; - struct clk_init_data init; + struct clk_init_data init = {}; int ret; socfpga_clk = kzalloc_obj(*socfpga_clk); diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c index ced8e0988406..d0f9fa44ad18 100644 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c @@ -143,7 +143,7 @@ void __init socfpga_gate_init(struct device_node *node) struct socfpga_gate_clk *socfpga_clk; const char *clk_name = node->name; const char *parent_name[SOCFPGA_MAX_PARENTS]; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_ops *ops; int rc; diff --git a/drivers/clk/socfpga/clk-periph-a10.c b/drivers/clk/socfpga/clk-periph-a10.c index 4eb5787f0dea..8aefc58ba4ec 100644 --- a/drivers/clk/socfpga/clk-periph-a10.c +++ b/drivers/clk/socfpga/clk-periph-a10.c @@ -65,7 +65,7 @@ static void __init __socfpga_periph_init(struct device_node *node, struct socfpga_periph_clk *periph_clk; const char *clk_name = node->name; const char *parent_name[SOCFPGA_MAX_PARENTS]; - struct clk_init_data init; + struct clk_init_data init = {}; int rc; u32 fixed_div; u32 div_reg[3]; diff --git a/drivers/clk/socfpga/clk-periph-s10.c b/drivers/clk/socfpga/clk-periph-s10.c index 5195b9476da1..dc923d0d8786 100644 --- a/drivers/clk/socfpga/clk-periph-s10.c +++ b/drivers/clk/socfpga/clk-periph-s10.c @@ -103,7 +103,7 @@ struct clk_hw *s10_register_periph(const struct stratix10_perip_c_clock *clks, { struct clk_hw *hw_clk; struct socfpga_periph_clk *periph_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *name = clks->name; const char *parent_name = clks->parent_name; int ret; @@ -139,7 +139,7 @@ struct clk_hw *n5x_register_periph(const struct n5x_perip_c_clock *clks, { struct clk_hw *hw_clk; struct socfpga_periph_clk *periph_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *name = clks->name; const char *parent_name = clks->parent_name; int ret; @@ -174,7 +174,7 @@ struct clk_hw *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *c { struct clk_hw *hw_clk; struct socfpga_periph_clk *periph_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *name = clks->name; const char *parent_name = clks->parent_name; int ret; @@ -220,7 +220,7 @@ struct clk_hw *agilex5_register_cnt_periph(const struct agilex5_perip_cnt_clock { struct clk_hw *hw_clk; struct socfpga_periph_clk *periph_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *name = clks->name; int ret; diff --git a/drivers/clk/socfpga/clk-periph.c b/drivers/clk/socfpga/clk-periph.c index 3821db6777e7..8fa3d8e20042 100644 --- a/drivers/clk/socfpga/clk-periph.c +++ b/drivers/clk/socfpga/clk-periph.c @@ -55,7 +55,7 @@ static void __init __socfpga_periph_init(struct device_node *node, struct socfpga_periph_clk *periph_clk; const char *clk_name = node->name; const char *parent_name[SOCFPGA_MAX_PARENTS]; - struct clk_init_data init; + struct clk_init_data init = {}; int rc; u32 fixed_div; u32 div_reg[3]; diff --git a/drivers/clk/socfpga/clk-pll-a10.c b/drivers/clk/socfpga/clk-pll-a10.c index c56f276e8d51..63b8b75045ae 100644 --- a/drivers/clk/socfpga/clk-pll-a10.c +++ b/drivers/clk/socfpga/clk-pll-a10.c @@ -71,7 +71,7 @@ static void __init __socfpga_pll_init(struct device_node *node, struct socfpga_pll *pll_clk; const char *clk_name = node->name; const char *parent_name[SOCFGPA_MAX_PARENTS]; - struct clk_init_data init; + struct clk_init_data init = {}; struct device_node *clkmgr_np; int rc; int i = 0; diff --git a/drivers/clk/socfpga/clk-pll-s10.c b/drivers/clk/socfpga/clk-pll-s10.c index ee236e87da33..1dca54b48375 100644 --- a/drivers/clk/socfpga/clk-pll-s10.c +++ b/drivers/clk/socfpga/clk-pll-s10.c @@ -192,7 +192,7 @@ struct clk_hw *s10_register_pll(const struct stratix10_pll_clock *clks, { struct clk_hw *hw_clk; struct socfpga_pll *pll_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *name = clks->name; int ret; @@ -232,7 +232,7 @@ struct clk_hw *agilex_register_pll(const struct stratix10_pll_clock *clks, { struct clk_hw *hw_clk; struct socfpga_pll *pll_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *name = clks->name; int ret; @@ -271,7 +271,7 @@ struct clk_hw *n5x_register_pll(const struct stratix10_pll_clock *clks, { struct clk_hw *hw_clk; struct socfpga_pll *pll_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *name = clks->name; int ret; @@ -310,7 +310,7 @@ struct clk_hw *agilex5_register_pll(const struct agilex5_pll_clock *clks, { struct clk_hw *hw_clk; struct socfpga_pll *pll_clk; - struct clk_init_data init; + struct clk_init_data init = {}; const char *name = clks->name; int ret; diff --git a/drivers/clk/socfpga/clk-pll.c b/drivers/clk/socfpga/clk-pll.c index f85adb16d414..aa13cc9d6db1 100644 --- a/drivers/clk/socfpga/clk-pll.c +++ b/drivers/clk/socfpga/clk-pll.c @@ -78,7 +78,7 @@ static void __init __socfpga_pll_init(struct device_node *node, struct socfpga_pll *pll_clk; const char *clk_name = node->name; const char *parent_name[SOCFPGA_MAX_PARENTS]; - struct clk_init_data init; + struct clk_init_data init = {}; struct device_node *clkmgr_np; int rc; From bf79ec19522ccf869c7ee8f5c06cc6d78d0e336d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:43 +0200 Subject: [PATCH 042/168] clk: spear: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Acked-by: Viresh Kumar Message-ID: Signed-off-by: Brian Masney --- drivers/clk/spear/clk-aux-synth.c | 2 +- drivers/clk/spear/clk-frac-synth.c | 2 +- drivers/clk/spear/clk-gpt-synth.c | 2 +- drivers/clk/spear/clk-vco-pll.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c index 61a8c3d4c1e4..85cfb9b5ec35 100644 --- a/drivers/clk/spear/clk-aux-synth.c +++ b/drivers/clk/spear/clk-aux-synth.c @@ -138,8 +138,8 @@ struct clk *clk_register_aux(const char *aux_name, const char *gate_name, const struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk) { + struct clk_init_data init = {}; struct clk_aux *aux; - struct clk_init_data init; struct clk *clk; if (!aux_name || !parent_name || !reg || !rtbl || !rtbl_cnt) { diff --git a/drivers/clk/spear/clk-frac-synth.c b/drivers/clk/spear/clk-frac-synth.c index 3549f1cfdae1..1b5e184d9668 100644 --- a/drivers/clk/spear/clk-frac-synth.c +++ b/drivers/clk/spear/clk-frac-synth.c @@ -125,7 +125,7 @@ struct clk *clk_register_frac(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, struct frac_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_frac *frac; struct clk *clk; diff --git a/drivers/clk/spear/clk-gpt-synth.c b/drivers/clk/spear/clk-gpt-synth.c index 1a431d7ec20c..411cacdfc11f 100644 --- a/drivers/clk/spear/clk-gpt-synth.c +++ b/drivers/clk/spear/clk-gpt-synth.c @@ -114,7 +114,7 @@ struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, struct gpt_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock) { - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_gpt *gpt; struct clk *clk; diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c index faba727e2f84..21fcc522c738 100644 --- a/drivers/clk/spear/clk-vco-pll.c +++ b/drivers/clk/spear/clk-vco-pll.c @@ -284,7 +284,7 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, struct clk_vco *vco; struct clk_pll *pll; struct clk *vco_clk, *tpll_clk, *tvco_gate_clk; - struct clk_init_data vco_init, pll_init; + struct clk_init_data vco_init = {}, pll_init = {}; const char **vco_parent_name; if (!vco_name || !pll_name || !parent_name || !mode_reg || !cfg_reg || From 605757e1771357a97710f1e3cdedaa739a283cda Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:44 +0200 Subject: [PATCH 043/168] clk: stm32: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <0b80535e9cfdc96d43169e5023e3a92a8f2252d6.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-stm32f4.c | 4 ++-- drivers/clk/clk-stm32h7.c | 2 +- drivers/clk/stm32/clk-stm32mp1.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index 565b4d99bebb..6603d4815514 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -485,8 +485,8 @@ static struct clk *clk_register_apb_mul(struct device *dev, const char *name, const char *parent_name, unsigned long flags, u8 bit_idx) { + struct clk_init_data init = {}; struct clk_apb_mul *am; - struct clk_init_data init; struct clk *clk; am = kzalloc_obj(*am); @@ -810,8 +810,8 @@ static struct clk_hw *clk_register_pll_div(const char *name, struct clk_hw *pll_hw, spinlock_t *lock) { struct stm32f4_pll_div *pll_div; + struct clk_init_data init = {}; struct clk_hw *hw; - struct clk_init_data init; int ret; /* allocate the divider */ diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c index 82e0789cf189..c6afa9b20235 100644 --- a/drivers/clk/clk-stm32h7.c +++ b/drivers/clk/clk-stm32h7.c @@ -462,8 +462,8 @@ static struct clk_hw *clk_register_stm32_timer_ker(struct device *dev, u8 dppre_shift, spinlock_t *lock) { + struct clk_init_data init = {}; struct timer_ker *element; - struct clk_init_data init; struct clk_hw *hw; int err; diff --git a/drivers/clk/stm32/clk-stm32mp1.c b/drivers/clk/stm32/clk-stm32mp1.c index 2d9ccd96ec98..b265e3f3e94c 100644 --- a/drivers/clk/stm32/clk-stm32mp1.c +++ b/drivers/clk/stm32/clk-stm32mp1.c @@ -902,8 +902,8 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name, unsigned long flags, spinlock_t *lock) { + struct clk_init_data init = {}; struct stm32_pll_obj *element; - struct clk_init_data init; struct clk_hw *hw; int err; @@ -1041,8 +1041,8 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, void __iomem *timpre, spinlock_t *lock) { + struct clk_init_data init = {}; struct timer_cker *tim_ker; - struct clk_init_data init; struct clk_hw *hw; int err; From f444c655938f3c64f59d4f29cc8bd79c151d39ff Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:45 +0200 Subject: [PATCH 044/168] clk: st: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/st/clk-flexgen.c | 2 +- drivers/clk/st/clkgen-fsyn.c | 4 ++-- drivers/clk/st/clkgen-pll.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c index 211535fd8ac9..46e5c7be43e8 100644 --- a/drivers/clk/st/clk-flexgen.c +++ b/drivers/clk/st/clk-flexgen.c @@ -209,7 +209,7 @@ static struct clk *clk_register_flexgen(const char *name, unsigned long flexgen_flags, bool mode) { struct flexgen *fgxbar; struct clk *clk; - struct clk_init_data init; + struct clk_init_data init = {}; u32 xbar_shift; void __iomem *xbar_reg, *fdiv_reg; diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index 3fcc1da20c04..705133b959d7 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -444,9 +444,9 @@ static struct clk * __init st_clk_register_quadfs_pll( struct clkgen_quadfs_data *quadfs, void __iomem *reg, spinlock_t *lock) { + struct clk_init_data init = {}; struct st_clk_quadfs_pll *pll; struct clk *clk; - struct clk_init_data init; /* * Sanity check required pointers. @@ -885,8 +885,8 @@ static struct clk * __init st_clk_register_quadfs_fsynth( unsigned long flags, spinlock_t *lock) { struct st_clk_quadfs_fsynth *fs; + struct clk_init_data init = {}; struct clk *clk; - struct clk_init_data init; /* * Sanity check required pointers, note that nsdiv3 is optional. diff --git a/drivers/clk/st/clkgen-pll.c b/drivers/clk/st/clkgen-pll.c index 17551c6a879a..aaa28aaff627 100644 --- a/drivers/clk/st/clkgen-pll.c +++ b/drivers/clk/st/clkgen-pll.c @@ -652,9 +652,9 @@ static struct clk * __init clkgen_pll_register(const char *parent_name, void __iomem *reg, unsigned long pll_flags, const char *clk_name, spinlock_t *lock) { + struct clk_init_data init = {}; struct clkgen_pll *pll; struct clk *clk; - struct clk_init_data init; pll = kzalloc_obj(*pll); if (!pll) From 5af0e417e28ea317ed2507e18007c0807f6d2593 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:46 +0200 Subject: [PATCH 045/168] clk: sunxi: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/sunxi/clk-sun4i-tcon-ch1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c index b61eba112a7f..b7f55864ea2a 100644 --- a/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c +++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c @@ -225,7 +225,7 @@ static void __init tcon_ch1_setup(struct device_node *node) { const char *parents[TCON_CH1_SCLK2_PARENTS]; const char *clk_name = node->name; - struct clk_init_data init; + struct clk_init_data init = {}; struct tcon_ch1_clk *tclk; struct resource res; struct clk *clk; From 888a064a78503a6d6332188a5569969c8b2726fe Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:47 +0200 Subject: [PATCH 046/168] clk: tegra: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <1cc7367a121a748dc126f54e1df70a5acebe5914.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/tegra/clk-audio-sync.c | 2 +- drivers/clk/tegra/clk-divider.c | 2 +- drivers/clk/tegra/clk-periph-fixed.c | 2 +- drivers/clk/tegra/clk-periph-gate.c | 2 +- drivers/clk/tegra/clk-periph.c | 2 +- drivers/clk/tegra/clk-pll-out.c | 2 +- drivers/clk/tegra/clk-pll.c | 2 +- drivers/clk/tegra/clk-sdmmc-mux.c | 2 +- drivers/clk/tegra/clk-super.c | 4 ++-- drivers/clk/tegra/clk-tegra-super-cclk.c | 2 +- drivers/clk/tegra/clk-tegra124-emc.c | 2 +- drivers/clk/tegra/clk-tegra20-emc.c | 2 +- drivers/clk/tegra/clk-tegra210-emc.c | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/clk/tegra/clk-audio-sync.c b/drivers/clk/tegra/clk-audio-sync.c index 0bbfcf46bedd..0fb4377c80bf 100644 --- a/drivers/clk/tegra/clk-audio-sync.c +++ b/drivers/clk/tegra/clk-audio-sync.c @@ -47,7 +47,7 @@ struct clk *tegra_clk_register_sync_source(const char *name, unsigned long max_rate) { struct tegra_clk_sync_source *sync; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk *clk; sync = kzalloc_obj(*sync); diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c index 27f43c3da156..2dc771343345 100644 --- a/drivers/clk/tegra/clk-divider.c +++ b/drivers/clk/tegra/clk-divider.c @@ -145,8 +145,8 @@ struct clk *tegra_clk_register_divider(const char *name, u8 frac_width, spinlock_t *lock) { struct tegra_clk_frac_div *divider; + struct clk_init_data init = {}; struct clk *clk; - struct clk_init_data init; divider = kzalloc_obj(*divider); if (!divider) { diff --git a/drivers/clk/tegra/clk-periph-fixed.c b/drivers/clk/tegra/clk-periph-fixed.c index bb33e32cad4a..9ea9d41f4796 100644 --- a/drivers/clk/tegra/clk-periph-fixed.c +++ b/drivers/clk/tegra/clk-periph-fixed.c @@ -77,7 +77,7 @@ struct clk *tegra_clk_register_periph_fixed(const char *name, { const struct tegra_clk_periph_regs *regs; struct tegra_clk_periph_fixed *fixed; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk *clk; regs = get_reg_bank(num); diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index fa39d6487515..d821e1b9f77e 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -139,7 +139,7 @@ struct clk *tegra_clk_register_periph_gate(const char *name, { struct tegra_clk_periph_gate *gate; struct clk *clk; - struct clk_init_data init; + struct clk_init_data init = {}; const struct tegra_clk_periph_regs *pregs; pregs = get_reg_bank(clk_num); diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index 6ebeaa7cb656..7af832d9af9b 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -166,7 +166,7 @@ static struct clk *_tegra_clk_register_periph(const char *name, unsigned long flags) { struct clk *clk; - struct clk_init_data init; + struct clk_init_data init = {}; const struct tegra_clk_periph_regs *bank; bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV); diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c index 2299545fc386..285b0af811fb 100644 --- a/drivers/clk/tegra/clk-pll-out.c +++ b/drivers/clk/tegra/clk-pll-out.c @@ -90,8 +90,8 @@ struct clk *tegra_clk_register_pll_out(const char *name, spinlock_t *lock) { struct tegra_clk_pll_out *pll_out; + struct clk_init_data init = {}; struct clk *clk; - struct clk_init_data init; pll_out = kzalloc_obj(*pll_out); if (!pll_out) diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index adfb74f111ef..fc3abe86414d 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -1903,7 +1903,7 @@ static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll, const char *name, const char *parent_name, unsigned long flags, const struct clk_ops *ops) { - struct clk_init_data init; + struct clk_init_data init = {}; init.name = name; init.ops = ops; diff --git a/drivers/clk/tegra/clk-sdmmc-mux.c b/drivers/clk/tegra/clk-sdmmc-mux.c index 14b5439a100a..74fe06fa546a 100644 --- a/drivers/clk/tegra/clk-sdmmc-mux.c +++ b/drivers/clk/tegra/clk-sdmmc-mux.c @@ -236,7 +236,7 @@ struct clk *tegra_clk_register_sdmmc_mux_div(const char *name, unsigned long flags, void *lock) { struct clk *clk; - struct clk_init_data init; + struct clk_init_data init = {}; const struct tegra_clk_periph_regs *bank; struct tegra_sdmmc_mux *sdmmc_mux; diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c index 370445e3d5ac..7aa3c3774445 100644 --- a/drivers/clk/tegra/clk-super.c +++ b/drivers/clk/tegra/clk-super.c @@ -204,8 +204,8 @@ struct clk *tegra_clk_register_super_mux(const char *name, u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock) { struct tegra_clk_super_mux *super; + struct clk_init_data init = {}; struct clk *clk; - struct clk_init_data init; super = kzalloc_obj(*super); if (!super) @@ -240,8 +240,8 @@ struct clk *tegra_clk_register_super_clk(const char *name, spinlock_t *lock) { struct tegra_clk_super_mux *super; + struct clk_init_data init = {}; struct clk *clk; - struct clk_init_data init; super = kzalloc_obj(*super); if (!super) diff --git a/drivers/clk/tegra/clk-tegra-super-cclk.c b/drivers/clk/tegra/clk-tegra-super-cclk.c index e7aeb67606b1..1047a1104ec1 100644 --- a/drivers/clk/tegra/clk-tegra-super-cclk.c +++ b/drivers/clk/tegra/clk-tegra-super-cclk.c @@ -135,8 +135,8 @@ struct clk *tegra_clk_register_super_cclk(const char *name, spinlock_t *lock) { struct tegra_clk_super_mux *super; + struct clk_init_data init = {}; struct clk *clk; - struct clk_init_data init; u32 val; if (WARN_ON(cclk_super)) diff --git a/drivers/clk/tegra/clk-tegra124-emc.c b/drivers/clk/tegra/clk-tegra124-emc.c index 94ac24ea1e6a..0fc74808fe39 100644 --- a/drivers/clk/tegra/clk-tegra124-emc.c +++ b/drivers/clk/tegra/clk-tegra124-emc.c @@ -485,8 +485,8 @@ static const struct clk_ops tegra_clk_emc_ops = { struct clk *tegra124_clk_register_emc(void __iomem *base, struct device_node *np, spinlock_t *lock) { + struct clk_init_data init = {}; struct tegra_clk_emc *tegra; - struct clk_init_data init; struct device_node *node; u32 node_ram_code; struct clk *clk; diff --git a/drivers/clk/tegra/clk-tegra20-emc.c b/drivers/clk/tegra/clk-tegra20-emc.c index 44465726a8a6..5cd026e8f305 100644 --- a/drivers/clk/tegra/clk-tegra20-emc.c +++ b/drivers/clk/tegra/clk-tegra20-emc.c @@ -245,8 +245,8 @@ bool tegra20_clk_emc_driver_available(struct clk_hw *emc_hw) struct clk *tegra20_clk_register_emc(void __iomem *ioaddr, bool low_jitter) { + struct clk_init_data init = {}; struct tegra_clk_emc *emc; - struct clk_init_data init; struct clk *clk; emc = kzalloc_obj(*emc); diff --git a/drivers/clk/tegra/clk-tegra210-emc.c b/drivers/clk/tegra/clk-tegra210-emc.c index 9f140d94bef7..2e559d95d40e 100644 --- a/drivers/clk/tegra/clk-tegra210-emc.c +++ b/drivers/clk/tegra/clk-tegra210-emc.c @@ -274,8 +274,8 @@ static const struct clk_ops tegra210_clk_emc_ops = { struct clk *tegra210_clk_register_emc(struct device_node *np, void __iomem *regs) { + struct clk_init_data init = {}; struct tegra210_clk_emc *emc; - struct clk_init_data init; struct clk *clk; emc = kzalloc_obj(*emc); From fcd74898a4eeca688c9d9d77a7fec705884cc1e5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:48 +0200 Subject: [PATCH 047/168] clk: uniphier: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <491e41d759cec667d6bcd742673e1fec70b4bc31.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/uniphier/clk-uniphier-cpugear.c | 2 +- drivers/clk/uniphier/clk-uniphier-fixed-factor.c | 2 +- drivers/clk/uniphier/clk-uniphier-fixed-rate.c | 2 +- drivers/clk/uniphier/clk-uniphier-gate.c | 2 +- drivers/clk/uniphier/clk-uniphier-mux.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/uniphier/clk-uniphier-cpugear.c b/drivers/clk/uniphier/clk-uniphier-cpugear.c index a2f01a4da127..165c6832b722 100644 --- a/drivers/clk/uniphier/clk-uniphier-cpugear.c +++ b/drivers/clk/uniphier/clk-uniphier-cpugear.c @@ -79,7 +79,7 @@ struct clk_hw *uniphier_clk_register_cpugear(struct device *dev, const struct uniphier_clk_cpugear_data *data) { struct uniphier_clk_cpugear *gear; - struct clk_init_data init; + struct clk_init_data init = {}; int ret; gear = devm_kzalloc(dev, sizeof(*gear), GFP_KERNEL); diff --git a/drivers/clk/uniphier/clk-uniphier-fixed-factor.c b/drivers/clk/uniphier/clk-uniphier-fixed-factor.c index a6a37a6bca3a..c86683fce205 100644 --- a/drivers/clk/uniphier/clk-uniphier-fixed-factor.c +++ b/drivers/clk/uniphier/clk-uniphier-fixed-factor.c @@ -13,8 +13,8 @@ struct clk_hw *uniphier_clk_register_fixed_factor(struct device *dev, const char *name, const struct uniphier_clk_fixed_factor_data *data) { + struct clk_init_data init = {}; struct clk_fixed_factor *fix; - struct clk_init_data init; int ret; fix = devm_kzalloc(dev, sizeof(*fix), GFP_KERNEL); diff --git a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c index 3bc55ab75314..63f49d3bab80 100644 --- a/drivers/clk/uniphier/clk-uniphier-fixed-rate.c +++ b/drivers/clk/uniphier/clk-uniphier-fixed-rate.c @@ -13,8 +13,8 @@ struct clk_hw *uniphier_clk_register_fixed_rate(struct device *dev, const char *name, const struct uniphier_clk_fixed_rate_data *data) { + struct clk_init_data init = {}; struct clk_fixed_rate *fixed; - struct clk_init_data init; int ret; /* allocate fixed-rate clock */ diff --git a/drivers/clk/uniphier/clk-uniphier-gate.c b/drivers/clk/uniphier/clk-uniphier-gate.c index e58093e79dd7..9f49e6bb6b20 100644 --- a/drivers/clk/uniphier/clk-uniphier-gate.c +++ b/drivers/clk/uniphier/clk-uniphier-gate.c @@ -61,8 +61,8 @@ struct clk_hw *uniphier_clk_register_gate(struct device *dev, const char *name, const struct uniphier_clk_gate_data *data) { + struct clk_init_data init = {}; struct uniphier_clk_gate *gate; - struct clk_init_data init; int ret; gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); diff --git a/drivers/clk/uniphier/clk-uniphier-mux.c b/drivers/clk/uniphier/clk-uniphier-mux.c index 1998e9d4cfc0..a63ad4df8e65 100644 --- a/drivers/clk/uniphier/clk-uniphier-mux.c +++ b/drivers/clk/uniphier/clk-uniphier-mux.c @@ -58,8 +58,8 @@ struct clk_hw *uniphier_clk_register_mux(struct device *dev, const char *name, const struct uniphier_clk_mux_data *data) { + struct clk_init_data init = {}; struct uniphier_clk_mux *mux; - struct clk_init_data init; int ret; mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); From f3bdb1723be1d72724db69b71df4c6ce8a54bb71 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:49 +0200 Subject: [PATCH 048/168] clk: ux500: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Acked-by: Ulf Hansson Acked-by: Linus Walleij Message-ID: Signed-off-by: Brian Masney --- drivers/clk/ux500/clk-prcc.c | 2 +- drivers/clk/ux500/clk-prcmu.c | 4 ++-- drivers/clk/ux500/clk-sysctrl.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c index dce235df2576..dde72d2fd0ac 100644 --- a/drivers/clk/ux500/clk-prcc.c +++ b/drivers/clk/ux500/clk-prcc.c @@ -97,8 +97,8 @@ static struct clk *clk_reg_prcc(const char *name, unsigned long flags, const struct clk_ops *clk_prcc_ops) { + struct clk_init_data clk_prcc_init = {}; struct clk_prcc *clk; - struct clk_init_data clk_prcc_init; struct clk *clk_reg; if (!name) { diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c index ac96c46bd1bb..d89f3b634f8b 100644 --- a/drivers/clk/ux500/clk-prcmu.c +++ b/drivers/clk/ux500/clk-prcmu.c @@ -200,8 +200,8 @@ static struct clk_hw *clk_reg_prcmu(const char *name, unsigned long flags, const struct clk_ops *clk_prcmu_ops) { + struct clk_init_data clk_prcmu_init = {}; struct clk_prcmu *clk; - struct clk_init_data clk_prcmu_init; int ret; if (!name) { @@ -357,8 +357,8 @@ struct clk_hw *clk_reg_prcmu_clkout(const char *name, u8 source, u8 divider) { + struct clk_init_data clk_prcmu_clkout_init = {}; struct clk_prcmu_clkout *clk; - struct clk_init_data clk_prcmu_clkout_init; u8 clkout_id; int ret; diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c index ba3258c88d28..2127a949e56c 100644 --- a/drivers/clk/ux500/clk-sysctrl.c +++ b/drivers/clk/ux500/clk-sysctrl.c @@ -127,8 +127,8 @@ static struct clk *clk_reg_sysctrl(struct device *dev, unsigned long flags, const struct clk_ops *clk_sysctrl_ops) { + struct clk_init_data clk_sysctrl_init = {}; struct clk_sysctrl *clk; - struct clk_init_data clk_sysctrl_init; struct clk *clk_reg; int i; From 55798638d98d36f31c6eb2e7b394d1e45452f549 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:50 +0200 Subject: [PATCH 049/168] clk: versatile: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Acked-by: Linus Walleij Reviewed-by: Liviu Dudau Message-ID: <7c480e73222bb51982fb82dc0cc6cd503f2e8b92.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/versatile/clk-icst.c | 2 +- drivers/clk/versatile/clk-sp810.c | 2 +- drivers/clk/versatile/clk-vexpress-osc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 6bd3db54dd22..97a1bfd6cf0e 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -360,8 +360,8 @@ struct clk *icst_clk_setup(struct device *dev, { struct clk *clk; struct clk_icst *icst; - struct clk_init_data init; struct icst_params *pclone; + struct clk_init_data init = {}; icst = kzalloc_obj(*icst); if (!icst) diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c index b0e69686f7a9..28e5c0cf1fda 100644 --- a/drivers/clk/versatile/clk-sp810.c +++ b/drivers/clk/versatile/clk-sp810.c @@ -86,7 +86,7 @@ static void __init clk_sp810_of_setup(struct device_node *node) const char *parent_names[2]; int num = ARRAY_SIZE(parent_names); char name[12]; - struct clk_init_data init; + struct clk_init_data init = {}; static int instance; int i; bool deprecated; diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c index 9adbf5c33bd1..72e872ec6b7c 100644 --- a/drivers/clk/versatile/clk-vexpress-osc.c +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -64,7 +64,7 @@ static const struct clk_ops vexpress_osc_ops = { static int vexpress_osc_probe(struct platform_device *pdev) { - struct clk_init_data init; + struct clk_init_data init = {}; struct vexpress_osc *osc; u32 range[2]; int ret; From 754ad934ecc8281cc013dc2f8431369597476b61 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:51 +0200 Subject: [PATCH 050/168] clk: vt8500: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/clk-vt8500.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index 3e62cb853d5e..581ac00c31bc 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c @@ -227,8 +227,8 @@ static __init void vtwm_device_clk_init(struct device_node *node) struct clk_hw *hw; struct clk_device *dev_clk; const char *clk_name = node->name; + struct clk_init_data init = {}; const char *parent_name; - struct clk_init_data init; int rc; int clk_init_flags = 0; @@ -687,8 +687,8 @@ static __init void vtwm_pll_clk_init(struct device_node *node, int pll_type) struct clk_hw *hw; struct clk_pll *pll_clk; const char *clk_name = node->name; + struct clk_init_data init = {}; const char *parent_name; - struct clk_init_data init; int rc; if (!pmc_base) From c6479449be12b08e1e57ae9fdc84a8079796b7c4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:52 +0200 Subject: [PATCH 051/168] clk: x86: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <2d1690a6966152450bda8e8b1e6f5fe2c1df1610.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/x86/clk-pmc-atom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/x86/clk-pmc-atom.c b/drivers/clk/x86/clk-pmc-atom.c index 08c83e0abc41..43dda274e329 100644 --- a/drivers/clk/x86/clk-pmc-atom.c +++ b/drivers/clk/x86/clk-pmc-atom.c @@ -151,8 +151,8 @@ static struct clk_plt *plt_clk_register(struct platform_device *pdev, int id, const char **parent_names, int num_parents) { + struct clk_init_data init = {}; struct clk_plt *pclk; - struct clk_init_data init; int ret; pclk = devm_kzalloc(&pdev->dev, sizeof(*pclk), GFP_KERNEL); From cfa82da56416eba490a4a6fe056f8209da6f9ca2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:53 +0200 Subject: [PATCH 052/168] clk: xgene: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: <21374aa8a23b8a72746030eda9e67f6ca3dc37e3.1787239813.git.geert+renesas@glider.be> Signed-off-by: Brian Masney --- drivers/clk/clk-xgene.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index abb6c8fcdc91..2029962ae5aa 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -126,9 +126,9 @@ static struct clk *xgene_register_clk_pll(struct device *dev, unsigned long flags, void __iomem *reg, u32 pll_offset, u32 type, spinlock_t *lock, int version) { + struct clk_init_data init = {}; struct xgene_clk_pll *apmclk; struct clk *clk; - struct clk_init_data init; /* allocate the APM clock structure */ apmclk = kzalloc_obj(*apmclk); @@ -350,8 +350,8 @@ xgene_register_clk_pmd(struct device *dev, unsigned long flags, void __iomem *reg, u8 shift, u8 width, u64 denom, u32 clk_flags, spinlock_t *lock) { + struct clk_init_data init = {}; struct xgene_clk_pmd *fd; - struct clk_init_data init; struct clk *clk; fd = kzalloc_obj(*fd); @@ -634,9 +634,9 @@ static struct clk *xgene_register_clk(struct device *dev, const char *name, const char *parent_name, struct xgene_dev_parameters *parameters, spinlock_t *lock) { + struct clk_init_data init = {}; struct xgene_clk *apmclk; struct clk *clk; - struct clk_init_data init; int rc; /* allocate the APM clock structure */ From c0d0fe4ccfa35b231b9d2708507fa4b19d84ad53 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:54 +0200 Subject: [PATCH 053/168] clk: xilinx: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 6 +++--- drivers/clk/xilinx/xlnx_vcu.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index edf8c0eaca27..4e5b9cb3754b 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -936,9 +936,9 @@ static struct clk_hw *clk_wzrd_register_divf(struct device *dev, u32 div_type, spinlock_t *lock) { + struct clk_init_data init = {}; struct clk_wzrd_divider *div; struct clk_hw *hw; - struct clk_init_data init; int ret; div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); @@ -980,9 +980,9 @@ static struct clk_hw *clk_wzrd_ver_register_divider(struct device *dev, u32 div_type, spinlock_t *lock) { + struct clk_init_data init = {}; struct clk_wzrd_divider *div; struct clk_hw *hw; - struct clk_init_data init; int ret; div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); @@ -1026,9 +1026,9 @@ static struct clk_hw *clk_wzrd_register_divider(struct device *dev, u32 div_type, spinlock_t *lock) { + struct clk_init_data init = {}; struct clk_wzrd_divider *div; struct clk_hw *hw; - struct clk_init_data init; int ret; div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); diff --git a/drivers/clk/xilinx/xlnx_vcu.c b/drivers/clk/xilinx/xlnx_vcu.c index f14bda375e35..ccd9d7c0b180 100644 --- a/drivers/clk/xilinx/xlnx_vcu.c +++ b/drivers/clk/xilinx/xlnx_vcu.c @@ -406,9 +406,9 @@ static struct clk_hw *xvcu_register_pll(struct device *dev, const char *name, const char *parent, unsigned long flags) { + struct clk_init_data init = {}; struct vcu_pll *pll; struct clk_hw *hw; - struct clk_init_data init; int ret; init.name = name; From 4fbb1d7c25b01369d656662933171ed7ff74f71c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:55 +0200 Subject: [PATCH 054/168] clk: zynqmp: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Message-ID: Signed-off-by: Brian Masney --- drivers/clk/zynqmp/clk-gate-zynqmp.c | 2 +- drivers/clk/zynqmp/clk-mux-zynqmp.c | 2 +- drivers/clk/zynqmp/divider.c | 2 +- drivers/clk/zynqmp/pll.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/zynqmp/clk-gate-zynqmp.c b/drivers/clk/zynqmp/clk-gate-zynqmp.c index db10eb69f3fe..1a462af7b8ea 100644 --- a/drivers/clk/zynqmp/clk-gate-zynqmp.c +++ b/drivers/clk/zynqmp/clk-gate-zynqmp.c @@ -109,10 +109,10 @@ struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id, u8 num_parents, const struct clock_topology *nodes) { + struct clk_init_data init = {}; struct zynqmp_clk_gate *gate; struct clk_hw *hw; int ret; - struct clk_init_data init; /* allocate the gate */ gate = kzalloc_obj(*gate); diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c index e37bd3516974..79509e387b51 100644 --- a/drivers/clk/zynqmp/clk-mux-zynqmp.c +++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c @@ -133,9 +133,9 @@ struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id, u8 num_parents, const struct clock_topology *nodes) { + struct clk_init_data init = {}; struct zynqmp_clk_mux *mux; struct clk_hw *hw; - struct clk_init_data init; int ret; mux = kzalloc_obj(*mux); diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c index 4075f6ecf076..3eabd1cf211d 100644 --- a/drivers/clk/zynqmp/divider.c +++ b/drivers/clk/zynqmp/divider.c @@ -278,9 +278,9 @@ struct clk_hw *zynqmp_clk_register_divider(const char *name, u8 num_parents, const struct clock_topology *nodes) { + struct clk_init_data init = {}; struct zynqmp_clk_divider *div; struct clk_hw *hw; - struct clk_init_data init; int ret; /* allocate the divider */ diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c index 6463787cf57b..6158386ca743 100644 --- a/drivers/clk/zynqmp/pll.c +++ b/drivers/clk/zynqmp/pll.c @@ -313,9 +313,9 @@ struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id, u8 num_parents, const struct clock_topology *nodes) { + struct clk_init_data init = {}; struct zynqmp_pll *pll; struct clk_hw *hw; - struct clk_init_data init; int ret; init.name = name; From 26e80ec751c87f437650a2f9eed5ef3ec436bf0b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Aug 2026 10:53:37 +0200 Subject: [PATCH 055/168] clk: renesas: Make sure clk_init_data is fully initialized The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled. Make sure all members are fully initialized, to avoid such bugs, and to prevent future breakage when converting drivers to a different method for specifying the parents. Signed-off-by: Geert Uytterhoeven Reviewed-by: Brian Masney Link: https://patch.msgid.link/b3473adc50c71aec5bc5f7ce6f5cda1727e26635.1787239813.git.geert+renesas@glider.be --- drivers/clk/renesas/rzg2l-cpg.c | 18 +++++++++--------- drivers/clk/renesas/rzv2h-cpg.c | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index c48502e0bd6a..7f8decef92fd 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -580,7 +580,7 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv) { struct sd_mux_hw_data *sd_mux_hw_data; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_hw *clk_hw; int ret; @@ -831,9 +831,9 @@ rzg2l_cpg_dsi_div_clk_register(const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv) { struct dsi_div_hw_data *clk_hw_data; + struct clk_init_data init = {}; const struct clk *parent; const char *parent_name; - struct clk_init_data init; struct clk_hw *clk_hw; int ret; @@ -916,8 +916,8 @@ static struct clk * __init rzg3l_cpg_lvds_div_clk_register(const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv) { + struct clk_init_data init = {}; struct clk_fixed_factor *ff; - struct clk_init_data init; const struct clk *parent; const char *parent_name; int ret; @@ -1031,9 +1031,9 @@ rzg3l_cpg_dsi_div_clk_register(const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv) { struct g3l_dsi_div_hw_data *clk_hw_data; + struct clk_init_data init = {}; const struct clk *parent; const char *parent_name; - struct clk_init_data init; struct clk_hw *clk_hw; int ret; @@ -1128,7 +1128,7 @@ rzg2l_cpg_pll5_4_mux_clk_register(const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv) { struct pll5_mux_hw_data *clk_hw_data; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_hw *clk_hw; int ret; @@ -1255,8 +1255,8 @@ static struct clk * __init rzg2l_cpg_sipll5_register(const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv) { + struct clk_init_data init = {}; const struct clk *parent; - struct clk_init_data init; const char *parent_name; struct sipll5 *sipll5; struct clk_hw *clk_hw; @@ -1381,9 +1381,9 @@ rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv, const struct clk_ops *ops) { + struct clk_init_data init = {}; struct device *dev = priv->dev; const struct clk *parent; - struct clk_init_data init; const char *parent_name; struct pll_clk *pll_clk; int ret; @@ -1525,8 +1525,8 @@ static struct clk * __init rzg3l_cpg_dsi_mux_clk_register(const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv) { + struct clk_init_data init = {}; struct clk_mux *mux_data; - struct clk_init_data init; int ret; mux_data = devm_kzalloc(priv->dev, sizeof(*mux_data), GFP_KERNEL); @@ -2264,10 +2264,10 @@ rzg2l_cpg_register_mod_clk(const struct rzg2l_mod_clk *mod, const struct rzg2l_cpg_info *info, struct rzg2l_cpg_priv *priv) { + struct clk_init_data init = {}; struct mod_clock *clock = NULL; struct device *dev = priv->dev; unsigned int id = mod->id; - struct clk_init_data init; struct clk *parent, *clk; const char *parent_name; unsigned int i; diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c index 917fc737f254..7003d59ac34b 100644 --- a/drivers/clk/renesas/rzv2h-cpg.c +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -338,7 +338,7 @@ rzv2h_cpg_plldsi_div_clk_register(const struct cpg_core_clk *core, { struct rzv2h_plldsi_div_clk *clk_hw_data; struct clk **clks = priv->clks; - struct clk_init_data init; + struct clk_init_data init = {}; const struct clk *parent; const char *parent_name; struct clk_hw *clk_hw; @@ -582,7 +582,7 @@ rzv2h_cpg_plldsi_smux_clk_register(const struct cpg_core_clk *core, struct rzv2h_cpg_priv *priv) { struct rzv2h_plldsi_mux_clk *clk_hw_data; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk_hw *clk_hw; struct smuxed smux; int ret; @@ -711,7 +711,7 @@ rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core, const struct clk_ops *ops) { struct device *dev = priv->dev; - struct clk_init_data init; + struct clk_init_data init = {}; const struct clk *parent; const char *parent_name; struct pll_clk *pll_clk; @@ -1229,7 +1229,7 @@ rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod, { struct mod_clock *clock = NULL; struct device *dev = priv->dev; - struct clk_init_data init; + struct clk_init_data init = {}; struct clk *parent, *clk; const char *parent_name; unsigned int id; From a1c8d531c694e193dc48ef2428877d5ea2e35134 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Thu, 23 Jul 2026 15:00:51 +0200 Subject: [PATCH 056/168] clk: fix self-consuming provider module pinning clk_hw_get_clk() lets a provider get a struct clk for one of its own struct clk_hw. When a struct clk is created, the module usage count of the provider is unconditionally increased. For a self-consuming provider, this means it pins itself and the module can never be unloaded. Increasing the module usage count should only be done when the consumer lives in a different module from the provider. Use THIS_MODULE to capture caller's module and increase the module usage count accordingly. It is OK for consumer-only APIs such as clk_get() or of_clk_get() to pass a NULL owner. As a result, any provider module will get pinned, same as before. Fixes: 30d6f8c15d2c ("clk: add api to get clk consumer from clk_hw") Signed-off-by: Jerome Brunet Signed-off-by: Brian Masney --- drivers/clk/clk.c | 46 ++++++++++++++++++++---------------- drivers/clk/clk.h | 5 ++-- drivers/clk/clkdev.c | 4 ++-- include/linux/clk-provider.h | 22 ++++++++++++++--- 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fef87167a60b..7fd5bc2a31f6 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -166,6 +166,7 @@ struct clk { unsigned long max_rate; unsigned int exclusive_count; struct hlist_node clks_node; + bool pinning; }; /*** runtime pm ***/ @@ -4237,13 +4238,15 @@ static void free_clk(struct clk *clk) * @hw: clk_hw associated with the clk being consumed * @dev_id: string describing device name * @con_id: connection ID string on device + * @owner: reference to the module creating the clock * * This is the main function used to create a clk pointer for use by clk * consumers. It connects a consumer to the clk_core and clk_hw structures * used by the framework and clk provider respectively. */ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, - const char *dev_id, const char *con_id) + const char *dev_id, const char *con_id, + struct module *owner) { struct clk *clk; struct clk_core *core; @@ -4258,7 +4261,13 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, return clk; clk->dev = dev; - if (!try_module_get(core->owner)) { + /* + * Pin the provider module only when the consumer lives in a different + * module. A provider getting a clk from its own clk_hw would otherwise + * pin itself and could never be unloaded. + */ + clk->pinning = owner != core->owner; + if (clk->pinning && !try_module_get(core->owner)) { free_clk(clk); return ERR_PTR(-ENOENT); } @@ -4269,24 +4278,19 @@ struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, return clk; } -/** - * clk_hw_get_clk - get clk consumer given an clk_hw - * @hw: clk_hw associated with the clk being consumed - * @con_id: connection ID string on device - * - * Returns: new clk consumer - * This is the function to be used by providers which need - * to get a consumer clk and act on the clock element - * Calls to this function must be balanced with calls clk_put() +/* + * Internal helper backing the clk_hw_get_clk() macro, which passes the caller's + * module via THIS_MODULE. */ -struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id) +struct clk *__clk_hw_get_clk(struct clk_hw *hw, const char *con_id, + struct module *owner) { struct device *dev = hw->core->dev; const char *name = dev ? dev_name(dev) : NULL; - return clk_hw_create_clk(dev, hw, name, con_id); + return clk_hw_create_clk(dev, hw, name, con_id, owner); } -EXPORT_SYMBOL(clk_hw_get_clk); +EXPORT_SYMBOL(__clk_hw_get_clk); static int clk_cpy_name(const char **dst_p, const char *src, bool must_exist) { @@ -4450,8 +4454,9 @@ __clk_register(struct device *dev, struct device_node *np, struct clk_hw *hw) INIT_HLIST_HEAD(&core->clks); /* - * Don't call clk_hw_create_clk() here because that would pin the - * provider module to itself and prevent it from ever being removed. + * Don't call clk_hw_create_clk() here because it would systematically + * add a consumer to the hw clock and all clocks would appear to have + * consumer in the clock summary. */ hw->clk = alloc_clk(core, NULL, NULL); if (IS_ERR(hw->clk)) { @@ -4808,7 +4813,7 @@ struct clk *devm_clk_hw_get_clk(struct device *dev, struct clk_hw *hw, if (!clkp) return ERR_PTR(-ENOMEM); - clk = clk_hw_get_clk(hw, con_id); + clk = __clk_hw_get_clk(hw, con_id, dev->driver->owner); if (!IS_ERR(clk)) { *clkp = clk; devres_add(dev, clkp); @@ -4855,7 +4860,8 @@ void __clk_put(struct clk *clk) owner = clk->core->owner; kref_put(&clk->core->ref, __clk_release); - module_put(owner); + if (clk->pinning) + module_put(owner); free_clk(clk); } @@ -5376,7 +5382,7 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) { struct clk_hw *hw = of_clk_get_hw_from_clkspec(clkspec); - return clk_hw_create_clk(NULL, hw, NULL, __func__); + return clk_hw_create_clk(NULL, hw, NULL, __func__, NULL); } EXPORT_SYMBOL_GPL(of_clk_get_from_provider); @@ -5403,7 +5409,7 @@ static struct clk *__of_clk_get(struct device_node *np, { struct clk_hw *hw = of_clk_get_hw(np, index, con_id); - return clk_hw_create_clk(NULL, hw, dev_id, con_id); + return clk_hw_create_clk(NULL, hw, dev_id, con_id, NULL); } struct clk *of_clk_get(struct device_node *np, int index) diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 2d801900cad5..5009380863a9 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -23,13 +23,14 @@ struct clk_hw *clk_find_hw(const char *dev_id, const char *con_id); #ifdef CONFIG_COMMON_CLK struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw, - const char *dev_id, const char *con_id); + const char *dev_id, const char *con_id, + struct module *owner); void __clk_put(struct clk *clk); #else /* All these casts to avoid ifdefs in clkdev... */ static inline struct clk * clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id, - const char *con_id) + const char *con_id, struct module *owner) { return (struct clk *)hw; } diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index abaa0f9e0083..919fc680ae4d 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -88,7 +88,7 @@ static struct clk *__clk_get_sys(struct device *dev, const char *dev_id, { struct clk_hw *hw = clk_find_hw(dev_id, con_id); - return clk_hw_create_clk(dev, hw, dev_id, con_id); + return clk_hw_create_clk(dev, hw, dev_id, con_id, NULL); } struct clk *clk_get_sys(const char *dev_id, const char *con_id) @@ -105,7 +105,7 @@ struct clk *clk_get(struct device *dev, const char *con_id) if (dev && dev->of_node) { hw = of_clk_get_hw(dev->of_node, 0, con_id); if (!IS_ERR(hw) || PTR_ERR(hw) == -EPROBE_DEFER) - return clk_hw_create_clk(dev, hw, dev_id, con_id); + return clk_hw_create_clk(dev, hw, dev_id, con_id, NULL); } return __clk_get_sys(dev, dev_id, con_id); diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index dc8e161f9c2c..58902e8dfd68 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -50,6 +50,7 @@ struct clk; struct clk_hw; struct clk_core; struct dentry; +struct module; /** * struct clk_rate_request - Structure encoding the clk constraints that @@ -351,8 +352,9 @@ struct clk_init_data { * @core: pointer to the struct clk_core instance that points back to this * struct clk_hw instance * - * @clk: pointer to the per-user struct clk instance that can be used to call - * into the clk API + * @clk: pointer to the per-user struct clk instance. This will be removed at + * some point in the future, Please consider the field obsolete and do not use + * it. Use clk_hw_get_clk() to get a per-user struct clk from a struct clk_hw. * * @init: pointer to struct clk_init_data that contains the init data shared * with the common clock framework. This pointer will be set to NULL once @@ -1474,10 +1476,24 @@ static inline struct clk_hw *__clk_get_hw(struct clk *clk) } #endif -struct clk *clk_hw_get_clk(struct clk_hw *hw, const char *con_id); +struct clk *__clk_hw_get_clk(struct clk_hw *hw, const char *con_id, + struct module *owner); struct clk *devm_clk_hw_get_clk(struct device *dev, struct clk_hw *hw, const char *con_id); +/** + * clk_hw_get_clk - get clk consumer given a clk_hw + * @hw: clk_hw associated with the clk being consumed + * @con_id: connection ID string on device + * + * Return: new clk consumer + * This is the function to be used by providers which need + * to get a consumer clk and act on the clock element + * Calls to this function must be balanced with calls to clk_put() + */ +#define clk_hw_get_clk(hw, con_id) \ + __clk_hw_get_clk((hw), (con_id), THIS_MODULE) + unsigned int clk_hw_get_num_parents(const struct clk_hw *hw); struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw); struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw, From 712b75152c00a8ab0c56dbfe34caf88e3870ddde Mon Sep 17 00:00:00 2001 From: hanzhijian Date: Mon, 24 Aug 2026 22:28:00 +0800 Subject: [PATCH 057/168] clk: mstar: msc313-mpll: fix off-by-one in clock array allocation The hws array of mpll->clk_data is allocated with struct_size() using ARRAY_SIZE(output_dividers) as the element count, giving it 7 elements. But the probe function stores the MPLL clock at hws[0] and one fixed-factor clock for each output divider at hws[i + 1] for i in [0, ARRAY_SIZE(output_dividers)), writing 8 elements in total. The final write to hws[7] is past the end of the allocation. clk_data->num is also set to NUMOUTPUTS (8), so the clock framework reads hws[0..7], again accessing hws[7] out of bounds. Use NUMOUTPUTS as the element count so the allocation matches the number of clocks actually stored and exposed. Found by smatch: drivers/clk/mstar/clk-msc313-mpll.c:134 msc313_mpll_probe() error: buffer overflow 'mpll->clk_data->hws' 7 <= 7 Fixes: bef7a78da716 ("clk: mstar: MStar/SigmaStar MPLL driver") Cc: stable@vger.kernel.org Signed-off-by: hanzhijian Reviewed-by: Brian Masney Signed-off-by: Brian Masney --- drivers/clk/mstar/clk-msc313-mpll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/mstar/clk-msc313-mpll.c b/drivers/clk/mstar/clk-msc313-mpll.c index 61beb4e87525..bd45aa0aec01 100644 --- a/drivers/clk/mstar/clk-msc313-mpll.c +++ b/drivers/clk/mstar/clk-msc313-mpll.c @@ -105,7 +105,7 @@ static int msc313_mpll_probe(struct platform_device *pdev) return PTR_ERR(mpll->loop_div_second); mpll->clk_data = devm_kzalloc(dev, struct_size(mpll->clk_data, hws, - ARRAY_SIZE(output_dividers)), GFP_KERNEL); + NUMOUTPUTS), GFP_KERNEL); if (!mpll->clk_data) return -ENOMEM; From e831ea3564120f5eb21a90eb7a46249b5b4f2878 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 14 Aug 2026 16:43:30 +0200 Subject: [PATCH 058/168] clk: actions: Drop unneeded forward declarations for clk_fixed_factor_ops This is already provided by . Signed-off-by: Geert Uytterhoeven Reviewed-by: Brian Masney Reviewed-by: Manivannan Sadhasivam Signed-off-by: Brian Masney --- drivers/clk/actions/owl-composite.h | 1 - drivers/clk/actions/owl-fixed-factor.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/clk/actions/owl-composite.h b/drivers/clk/actions/owl-composite.h index 6d7c6f0c47c8..ca055599b2fc 100644 --- a/drivers/clk/actions/owl-composite.h +++ b/drivers/clk/actions/owl-composite.h @@ -119,6 +119,5 @@ extern const struct clk_ops owl_comp_div_ops; extern const struct clk_ops owl_comp_fact_ops; extern const struct clk_ops owl_comp_fix_fact_ops; extern const struct clk_ops owl_comp_pass_ops; -extern const struct clk_ops clk_fixed_factor_ops; #endif /* _OWL_COMPOSITE_H_ */ diff --git a/drivers/clk/actions/owl-fixed-factor.h b/drivers/clk/actions/owl-fixed-factor.h index 3dfd7fd7d292..bbac5afadd67 100644 --- a/drivers/clk/actions/owl-fixed-factor.h +++ b/drivers/clk/actions/owl-fixed-factor.h @@ -23,6 +23,4 @@ _flags), \ } -extern const struct clk_ops clk_fixed_factor_ops; - #endif /* _OWL_FIXED_FACTOR_H_ */ From 48bec6fd8ec32ffdf65a5ccf268428a9f79ea210 Mon Sep 17 00:00:00 2001 From: Triet Hoang Date: Thu, 20 Aug 2026 13:59:04 +0700 Subject: [PATCH 059/168] drivers/clk: Convert to DEFINE_SIMPLE_DEV_PM_OPS() Convert the deprecated SIMPLE_DEV_PM_OPS to DEFINE_SIMPLE_DEV_PM_OPS and pm_sleep_ptr(). This lets us drop the __maybe_unused annotations from its suspend and resume callbacks, and reduces kernel size in case CONFIG_PM or CONFIG_PM_SLEEP is disabled. Signed-off-by: Triet Hoang Reviewed-by: Brian Masney Signed-off-by: Brian Masney --- drivers/clk/clk-si521xx.c | 8 ++++---- drivers/clk/clk-versaclock5.c | 8 ++++---- drivers/clk/samsung/clk-exynos-clkout.c | 8 ++++---- drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c index e3fb8df712ef..cd0553796125 100644 --- a/drivers/clk/clk-si521xx.c +++ b/drivers/clk/clk-si521xx.c @@ -341,7 +341,7 @@ static int si521xx_probe(struct i2c_client *client) return ret; } -static int __maybe_unused si521xx_suspend(struct device *dev) +static int si521xx_suspend(struct device *dev) { struct si521xx *si = dev_get_drvdata(dev); @@ -351,7 +351,7 @@ static int __maybe_unused si521xx_suspend(struct device *dev) return 0; } -static int __maybe_unused si521xx_resume(struct device *dev) +static int si521xx_resume(struct device *dev) { struct si521xx *si = dev_get_drvdata(dev); int ret; @@ -379,12 +379,12 @@ static const struct of_device_id clk_si521xx_of_match[] = { }; MODULE_DEVICE_TABLE(of, clk_si521xx_of_match); -static SIMPLE_DEV_PM_OPS(si521xx_pm_ops, si521xx_suspend, si521xx_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(si521xx_pm_ops, si521xx_suspend, si521xx_resume); static struct i2c_driver si521xx_driver = { .driver = { .name = "clk-si521xx", - .pm = &si521xx_pm_ops, + .pm = pm_sleep_ptr(&si521xx_pm_ops), .of_match_table = clk_si521xx_of_match, }, .probe = si521xx_probe, diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index b51148920216..fe3827b6c097 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -1223,7 +1223,7 @@ static void vc5_remove(struct i2c_client *client) clk_unregister_fixed_rate(vc5->pin_xin); } -static int __maybe_unused vc5_suspend(struct device *dev) +static int vc5_suspend(struct device *dev) { struct vc5_driver_data *vc5 = dev_get_drvdata(dev); @@ -1233,7 +1233,7 @@ static int __maybe_unused vc5_suspend(struct device *dev) return 0; } -static int __maybe_unused vc5_resume(struct device *dev) +static int vc5_resume(struct device *dev) { struct vc5_driver_data *vc5 = dev_get_drvdata(dev); int ret; @@ -1335,12 +1335,12 @@ static const struct of_device_id clk_vc5_of_match[] = { }; MODULE_DEVICE_TABLE(of, clk_vc5_of_match); -static SIMPLE_DEV_PM_OPS(vc5_pm_ops, vc5_suspend, vc5_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(vc5_pm_ops, vc5_suspend, vc5_resume); static struct i2c_driver vc5_driver = { .driver = { .name = "vc5", - .pm = &vc5_pm_ops, + .pm = pm_sleep_ptr(&vc5_pm_ops), .of_match_table = clk_vc5_of_match, }, .probe = vc5_probe, diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index 5f64d93b2fac..9c8b17cb5e7c 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -214,7 +214,7 @@ static void exynos_clkout_remove(struct platform_device *pdev) iounmap(clkout->reg); } -static int __maybe_unused exynos_clkout_suspend(struct device *dev) +static int exynos_clkout_suspend(struct device *dev) { struct exynos_clkout *clkout = dev_get_drvdata(dev); @@ -223,7 +223,7 @@ static int __maybe_unused exynos_clkout_suspend(struct device *dev) return 0; } -static int __maybe_unused exynos_clkout_resume(struct device *dev) +static int exynos_clkout_resume(struct device *dev) { struct exynos_clkout *clkout = dev_get_drvdata(dev); @@ -232,13 +232,13 @@ static int __maybe_unused exynos_clkout_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(exynos_clkout_pm_ops, exynos_clkout_suspend, +static DEFINE_SIMPLE_DEV_PM_OPS(exynos_clkout_pm_ops, exynos_clkout_suspend, exynos_clkout_resume); static struct platform_driver exynos_clkout_driver = { .driver = { .name = DRV_NAME, - .pm = &exynos_clkout_pm_ops, + .pm = pm_sleep_ptr(&exynos_clkout_pm_ops), }, .probe = exynos_clkout_probe, .remove = exynos_clkout_remove, diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index 4e5b9cb3754b..25bd71822dd6 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -1091,7 +1091,7 @@ static int clk_wzrd_clk_notifier(struct notifier_block *nb, unsigned long event, } } -static int __maybe_unused clk_wzrd_suspend(struct device *dev) +static int clk_wzrd_suspend(struct device *dev) { struct clk_wzrd *clk_wzrd = dev_get_drvdata(dev); @@ -1101,7 +1101,7 @@ static int __maybe_unused clk_wzrd_suspend(struct device *dev) return 0; } -static int __maybe_unused clk_wzrd_resume(struct device *dev) +static int clk_wzrd_resume(struct device *dev) { int ret; struct clk_wzrd *clk_wzrd = dev_get_drvdata(dev); @@ -1117,7 +1117,7 @@ static int __maybe_unused clk_wzrd_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(clk_wzrd_dev_pm_ops, clk_wzrd_suspend, +static DEFINE_SIMPLE_DEV_PM_OPS(clk_wzrd_dev_pm_ops, clk_wzrd_suspend, clk_wzrd_resume); static const struct versal_clk_data versal_data = { @@ -1378,7 +1378,7 @@ static struct platform_driver clk_wzrd_driver = { .driver = { .name = "clk-wizard", .of_match_table = clk_wzrd_ids, - .pm = &clk_wzrd_dev_pm_ops, + .pm = pm_sleep_ptr(&clk_wzrd_dev_pm_ops), }, .probe = clk_wzrd_probe, }; From 551ba775497e93d93bb849f6ee572ca768cbaa3e Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 2 Sep 2026 15:20:12 -0700 Subject: [PATCH 060/168] clk: davinci: add COMPILE_TEST support Add a driver-scoped Kconfig symbol for the DaVinci clock drivers so they can be built through COMPILE_TEST without selecting the ARM DaVinci platform symbols. Keep the existing ARM platform behavior by defaulting the new symbol from ARCH_DAVINCI, and use it for the davinci clock Makefile entries. ARCH_DAVINCI_DA850 is the only remaining DaVinci platform symbol, so a single COMMON_CLK_DAVINCI symbol suffices; the whole directory builds together just fine. Assisted-by: Codex:GPT-5.5 Signed-off-by: Rosen Penev Reviewed-by: Brian Masney Signed-off-by: Brian Masney --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 2 +- drivers/clk/davinci/Kconfig | 10 ++++++++++ drivers/clk/davinci/Makefile | 8 +++----- 4 files changed, 15 insertions(+), 6 deletions(-) create mode 100644 drivers/clk/davinci/Kconfig diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index f9592fd9ec2b..252f6a1f21b8 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -510,6 +510,7 @@ source "drivers/clk/analogbits/Kconfig" source "drivers/clk/aspeed/Kconfig" source "drivers/clk/bcm/Kconfig" source "drivers/clk/cix/Kconfig" +source "drivers/clk/davinci/Kconfig" source "drivers/clk/eswin/Kconfig" source "drivers/clk/hisilicon/Kconfig" source "drivers/clk/imgtec/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index b18af485d7f0..24ad716d1717 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -132,7 +132,7 @@ obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/ obj-y += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-y += cix/ -obj-$(CONFIG_ARCH_DAVINCI) += davinci/ +obj-$(CONFIG_COMMON_CLK_DAVINCI) += davinci/ obj-$(CONFIG_COMMON_CLK_ESWIN) += eswin/ obj-$(CONFIG_COMMON_CLK_HISI) += hisilicon/ obj-y += imgtec/ diff --git a/drivers/clk/davinci/Kconfig b/drivers/clk/davinci/Kconfig new file mode 100644 index 000000000000..7b8c518ef6b4 --- /dev/null +++ b/drivers/clk/davinci/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only +config COMMON_CLK_DAVINCI + bool "Clock drivers for TI DaVinci SoCs" + depends on ARCH_DAVINCI || COMPILE_TEST + depends on HAS_IOMEM + select REGMAP_MMIO + select RESET_CONTROLLER + default ARCH_DAVINCI + help + Support for the clock controllers found on TI DaVinci SoCs. diff --git a/drivers/clk/davinci/Makefile b/drivers/clk/davinci/Makefile index f9d5c9a392e4..7cb030b5e046 100644 --- a/drivers/clk/davinci/Makefile +++ b/drivers/clk/davinci/Makefile @@ -1,11 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 -ifeq ($(CONFIG_COMMON_CLK), y) -obj-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx-cfgchip.o +obj-y += da8xx-cfgchip.o obj-y += pll.o -obj-$(CONFIG_ARCH_DAVINCI_DA850) += pll-da850.o +obj-y += pll-da850.o obj-y += psc.o -obj-$(CONFIG_ARCH_DAVINCI_DA850) += psc-da850.o -endif +obj-y += psc-da850.o From 84964d0ce3faed815e1b8e048ce5ce1c93badb18 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Mon, 31 Aug 2026 08:50:56 +0000 Subject: [PATCH 061/168] clk: mediatek: Add missing depend for COMMON_CLK_MT8173 PM_GENERIC_DOMAINS_OF depends on OF, by adding a select to it without adding a depend on OF, the following warning is triggered: WARNING: unmet direct dependencies detected for PM_GENERIC_DOMAINS_OF Depends on [n]: PM_GENERIC_DOMAINS [=y] && OF [=n] Selected by [y]: - COMMON_CLK_MT8173_MFGTOP [=y] && COMMON_CLK [=y] && (ARCH_MEDIATEK || COMPILE_TEST [=y]) && COMMON_CLK_MT8173 [=y] && PM [=y] This patch explicitly adds a dependency on OF to solve this issue. Cc: stable@vger.kernel.org Fixes: ebd0b73d2137 ("clk: mediatek: Add mt8173-mfgtop driver") Signed-off-by: Ricardo Ribalda Reviewed-by: Chen-Yu Tsai Signed-off-by: Brian Masney --- drivers/clk/mediatek/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index b059d44577f1..ba1ca9c90dbf 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -541,6 +541,7 @@ config COMMON_CLK_MT8173_MFGTOP tristate "Clock and power driver for MediaTek MT8173 mfgtop" depends on COMMON_CLK_MT8173 depends on PM + depends on OF default COMMON_CLK_MT8173 select PM_GENERIC_DOMAINS select PM_GENERIC_DOMAINS_OF From e0be7b4eedd3b7c6d1a3db0dd76babc35ff89bc6 Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Fri, 7 Aug 2026 17:24:02 +0200 Subject: [PATCH 062/168] dt-bindings: clock: Introduce nexus nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardware containers can just decouple external resources like clock without any more control. Nexus nodes already exist for PWM and GPIOs, add a binding to allow them for clocks as well. No examples are given, the file is litteraly a copy-paste from Hervé Codina's work on PWM Nexus nodes, hence we just point to the examples there which already illustrate very clearly the concept of the various properties. Signed-off-by: Miquel Raynal (Schneider Electric) Reviewed-by: Rob Herring (Arm) Reviewed-by: Frank Li Signed-off-by: Brian Masney --- .../bindings/clock/clock-nexus-node.yaml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/clock-nexus-node.yaml diff --git a/Documentation/devicetree/bindings/clock/clock-nexus-node.yaml b/Documentation/devicetree/bindings/clock/clock-nexus-node.yaml new file mode 100644 index 000000000000..ff3283bd5fb1 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/clock-nexus-node.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/clock-nexus-node.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Clock Nexus + +description: > + A nexus node allows to remap a clock specifier list in a consumer node + through a container or a connector node in a generic way. With this + remapping, the consumer node needs to know only about the nexus + node. Resources behind the nexus node are decoupled by the nexus node + itself. + +maintainers: + - Miquel Raynal + +select: true + +properties: + clock-map: + $ref: /schemas/types.yaml#/definitions/uint32-matrix + +dependentRequired: + clock-map: ['#clock-cells'] + +additionalProperties: true + +# See the original pwm-nexus-node.yaml description for examples From d0a15b827251de65bd39ce0555d656d5563c41dc Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Fri, 7 Aug 2026 17:24:03 +0200 Subject: [PATCH 063/168] clk: tests: Add clk_parse_clkspec() Kunit testing Create a new set of kunit tests to make sure clk_parse_clkspec() is working as expected. We currently verify if we get a proper device when using indexes and names. If we make an out of bounds request we expect an error. For testing purposes, we must ensure of_clk_get_hw()'s symbol is exported. Suggested-by: Stephen Boyd Signed-off-by: Miquel Raynal (Schneider Electric) Reviewed-by: Brian Masney Reviewed-by: Frank Li Signed-off-by: Brian Masney --- drivers/clk/Makefile | 1 + drivers/clk/clk.c | 2 + drivers/clk/clk_test.c | 110 +++++++++++++++++++++++ drivers/clk/kunit_clk_parse_clkspec.dtso | 21 +++++ 4 files changed, 134 insertions(+) create mode 100644 drivers/clk/kunit_clk_parse_clkspec.dtso diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 24ad716d1717..d56abaad9883 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -29,6 +29,7 @@ clk-test-y := clk_test.o \ kunit_clk_assigned_sscs_zero.dtbo.o \ kunit_clk_assigned_sscs_zero_consumer.dtbo.o \ kunit_clk_hw_get_dev_of_node.dtbo.o \ + kunit_clk_parse_clkspec.dtbo.o \ kunit_clk_parent_data_test.dtbo.o obj-$(CONFIG_COMMON_CLK) += clk-divider.o obj-$(CONFIG_CLK_DIVIDER_KUNIT_TEST) += clk-divider_test.o diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 7fd5bc2a31f6..49cafdc77680 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "clk.h" @@ -5402,6 +5403,7 @@ struct clk_hw *of_clk_get_hw(struct device_node *np, int index, return hw; } +EXPORT_SYMBOL_IF_KUNIT(of_clk_get_hw); static struct clk *__of_clk_get(struct device_node *np, int index, const char *dev_id, diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index 1c5c8b7c1f3c..d6e364f25d8c 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -3738,11 +3738,120 @@ static struct kunit_suite clk_hw_get_dev_of_node_test_suite = { .test_cases = clk_hw_get_dev_of_node_test_cases, }; +static const struct clk_init_data clk_parse_clkspec_1_init_data = { + .name = "clk_parse_clkspec_1", + .ops = &empty_clk_ops, +}; + +static const struct clk_init_data clk_parse_clkspec_2_init_data = { + .name = "clk_parse_clkspec_2", + .ops = &empty_clk_ops, +}; + +struct clk_parse_clkspec_ctx { + struct device_node *cons_np; +}; + +static int clk_parse_clkspec_init(struct kunit *test) +{ + struct device_node *prov1_np, *prov2_np; + struct clk_parse_clkspec_ctx *ctx; + struct clk_hw *hw1, *hw2; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + test->priv = ctx; + + KUNIT_ASSERT_EQ(test, 0, of_overlay_apply_kunit(test, kunit_clk_parse_clkspec)); + + /* Register provider 1 */ + hw1 = kunit_kzalloc(test, sizeof(*hw1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw1); + hw1->init = &clk_parse_clkspec_1_init_data; + + prov1_np = of_find_compatible_node(NULL, NULL, "test,clock-provider1"); + KUNIT_ASSERT_NOT_NULL(test, prov1_np); + of_node_put_kunit(test, prov1_np); + + KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, prov1_np, hw1)); + KUNIT_ASSERT_EQ(test, 0, of_clk_add_hw_provider_kunit(test, prov1_np, of_clk_hw_simple_get, hw1)); + + /* Register provider 2 */ + hw2 = kunit_kzalloc(test, sizeof(*hw2), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw2); + hw2->init = &clk_parse_clkspec_2_init_data; + + prov2_np = of_find_compatible_node(NULL, NULL, "test,clock-provider2"); + KUNIT_ASSERT_NOT_NULL(test, prov2_np); + of_node_put_kunit(test, prov2_np); + + KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, prov2_np, hw2)); + KUNIT_ASSERT_EQ(test, 0, of_clk_add_hw_provider_kunit(test, prov2_np, of_clk_hw_simple_get, hw2)); + + ctx->cons_np = of_find_compatible_node(NULL, NULL, "test,clock-consumer"); + KUNIT_ASSERT_NOT_NULL(test, ctx->cons_np); + of_node_put_kunit(test, ctx->cons_np); + + return 0; +} + +/* Test DT phandle lookups using correct index or name succeed */ +static void clk_parse_clkspec_with_correct_index_and_name(struct kunit *test) +{ + struct clk_parse_clkspec_ctx *ctx = test->priv; + struct clk_hw *hw1, *hw2, *hw3, *hw4; + + /* Get clocks by index */ + hw1 = of_clk_get_hw(ctx->cons_np, 0, NULL); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw1); + + hw2 = of_clk_get_hw(ctx->cons_np, 1, NULL); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw2); + KUNIT_EXPECT_PTR_NE(test, hw1, hw2); + + /* Get clocks by name */ + hw3 = of_clk_get_hw(ctx->cons_np, 0, "first_clock"); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw3); + KUNIT_EXPECT_PTR_EQ(test, hw1, hw3); + + hw4 = of_clk_get_hw(ctx->cons_np, 0, "second_clock"); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, hw4); + KUNIT_EXPECT_PTR_EQ(test, hw2, hw4); +} + +/* Test DT phandle lookups using wrong index or name fail */ +static void clk_parse_clkspec_with_incorrect_index_and_name(struct kunit *test) +{ + struct clk_parse_clkspec_ctx *ctx = test->priv; + struct clk_hw *hw; + + /* Get clock by index */ + hw = of_clk_get_hw(ctx->cons_np, 2, NULL); + KUNIT_EXPECT_TRUE(test, IS_ERR(hw)); + + /* Get clock by name */ + hw = of_clk_get_hw(ctx->cons_np, 0, "third_clock"); + KUNIT_EXPECT_TRUE(test, IS_ERR(hw)); +} + +static struct kunit_case clk_parse_clkspec_test_cases[] = { + KUNIT_CASE(clk_parse_clkspec_with_correct_index_and_name), + KUNIT_CASE(clk_parse_clkspec_with_incorrect_index_and_name), + {} +}; + +/* Test suite to verify clk_parse_clkspec() */ +static struct kunit_suite clk_parse_clkspec_test_suite = { + .name = "clk_parse_clkspec", + .init = clk_parse_clkspec_init, + .test_cases = clk_parse_clkspec_test_cases, +}; kunit_test_suites( &clk_assigned_rates_suite, &clk_assigned_sscs_suite, &clk_hw_get_dev_of_node_test_suite, + &clk_parse_clkspec_test_suite, &clk_leaf_mux_set_rate_parent_test_suite, &clk_test_suite, &clk_multiple_parents_mux_test_suite, @@ -3760,4 +3869,5 @@ kunit_test_suites( &clk_uncached_test_suite, ); MODULE_DESCRIPTION("Kunit tests for clk framework"); +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/kunit_clk_parse_clkspec.dtso b/drivers/clk/kunit_clk_parse_clkspec.dtso new file mode 100644 index 000000000000..c93feb93e101 --- /dev/null +++ b/drivers/clk/kunit_clk_parse_clkspec.dtso @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +&{/} { + kunit_clock_provider1: kunit-clock-provider1 { + compatible = "test,clock-provider1"; + #clock-cells = <1>; + }; + + kunit_clock_provider2: kunit-clock-provider2 { + compatible = "test,clock-provider2"; + #clock-cells = <1>; + }; + + kunit-clock-consumer { + compatible = "test,clock-consumer"; + clocks = <&kunit_clock_provider1 0>, <&kunit_clock_provider2 0>; + clock-names = "first_clock", "second_clock"; + }; +}; From 32d4598a48d63003e732f2de3608fcd184aa8061 Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Fri, 7 Aug 2026 17:24:04 +0200 Subject: [PATCH 064/168] clk: tests: Add Kunit testing for of_clk_get_parent_name() Ensure this helper remains correct before making upcoming changes to it. Signed-off-by: Miquel Raynal (Schneider Electric) Reviewed-by: Brian Masney Reviewed-by: Frank Li Signed-off-by: Brian Masney --- drivers/clk/clk_test.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index d6e364f25d8c..bd424bb8dc27 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -3834,9 +3834,23 @@ static void clk_parse_clkspec_with_incorrect_index_and_name(struct kunit *test) KUNIT_EXPECT_TRUE(test, IS_ERR(hw)); } +/* + * Verify that of_clk_get_parent_name() returns the correct clock name when + * looking up by index through the consumer's clocks property. + */ +static void of_clk_get_parent_name_gets_parent_name(struct kunit *test) +{ + struct clk_parse_clkspec_ctx *ctx = test->priv; + const char *expected_name = "clk_parse_clkspec_1"; + + KUNIT_EXPECT_STREQ(test, expected_name, + of_clk_get_parent_name(ctx->cons_np, 0)); +} + static struct kunit_case clk_parse_clkspec_test_cases[] = { KUNIT_CASE(clk_parse_clkspec_with_correct_index_and_name), KUNIT_CASE(clk_parse_clkspec_with_incorrect_index_and_name), + KUNIT_CASE(of_clk_get_parent_name_gets_parent_name), {} }; From 4ee1e9e1d614a6b3a6264bac5b070c67a89ce19a Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Fri, 7 Aug 2026 17:24:05 +0200 Subject: [PATCH 065/168] clk: Improve a couple of comments Avoid mentioning the function names directly in the comments, it makes them easily out of sync with the rest of the code. Use a more generic wording. Suggested-by: Stephen Boyd Signed-off-by: Miquel Raynal (Schneider Electric) Reviewed-by: Brian Masney Reviewed-by: Frank Li Signed-off-by: Brian Masney --- drivers/clk/clk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 49cafdc77680..632213a38665 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -5304,7 +5304,7 @@ static int of_parse_clkspec(const struct device_node *np, int index, /* * For named clocks, first look up the name in the * "clock-names" property. If it cannot be found, then index - * will be an error code and of_parse_phandle_with_args() will + * will be an error code and the OF phandle parser will * return -EINVAL. */ if (name) @@ -5377,7 +5377,7 @@ of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec) * * This function looks up a struct clk from the registered list of clock * providers, an input is a clock specifier data structure as returned - * from the of_parse_phandle_with_args() function call. + * from the OF phandle parser. */ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) { From 57d728b4ab15a8af890013bb0f302e7733f7c1c6 Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Fri, 7 Aug 2026 17:24:06 +0200 Subject: [PATCH 066/168] clk: Use the generic OF phandle parsing in only one place Ideally, there should be one single entry in the OF world. This way, the DT parsing logic is always identical. At this stage, we call of_parse_phandle_with_args() in: - of_parse_clkspec() - of_clk_get_parent_name() which kinds of defeats the above statement. Furthermore, when this call is done from of_clk_get_parent_name(), we fail to parse the 'clock-ranges' property. Make sure DT world is entered only once by calling of_parse_clkspec() from of_clk_get_parent_name(). Doing so implies that we do not try the "clock-ranges" path if we already found a "clocks" property. Suggested-by: Stephen Boyd Fixes: 4472287a3b2f5 ("clk: Introduce of_clk_get_hw_from_clkspec()") Signed-off-by: Miquel Raynal (Schneider Electric) Reviewed-by: Brian Masney Reviewed-by: Frank Li Signed-off-by: Brian Masney --- drivers/clk/clk.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 632213a38665..cde94166835e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -5321,6 +5321,8 @@ static int of_parse_clkspec(const struct device_node *np, int index, * has a "clock-ranges" property, then we can try one of its * clocks. */ + if (of_property_present(np, "clocks")) + break; np = np->parent; if (np && !of_property_present(np, "clock-ranges")) break; @@ -5466,8 +5468,7 @@ const char *of_clk_get_parent_name(const struct device_node *np, int index) int count; struct clk *clk; - rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index, - &clkspec); + rc = of_parse_clkspec(np, index, NULL, &clkspec); if (rc) return NULL; From aacc54c67869effe89c92c0d54bea40148c53475 Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Fri, 7 Aug 2026 17:24:07 +0200 Subject: [PATCH 067/168] clk: Add support for clock nexus dt bindings A nexus node is some kind of parent device abstracting the outer connections. They are particularly useful for describing connectors-like interfaces but not only. Certain IP blocks will typically include inner blocks and distribute resources to them. In the case of clocks, there is already the concept of clock controller, but this usually indicates some kind of control over the said clock, ie. gate or rate control. When there is none of this, an existing approach is to reference the upper clock, which is wrong from a hardware point of view. Nexus nodes are already part of the device-tree specification and clocks are already mentioned: https://github.com/devicetree-org/devicetree-specification/blob/v0.4/source/chapter2-devicetree-basics.rst#nexus-nodes-and-specifier-mapping Following the introductions of nexus nodes support for interrupts, gpios and pwms, here is the same logic applied again to the clk subsystem, just by transitioning from of_parse_phandle_with_args() to of_parse_phandle_with_args_map(): * Nexus OF support: commit bd6f2fd5a1d5 ("of: Support parsing phandle argument lists through a nexus node") * GPIO adoption: commit c11e6f0f04db ("gpio: Support gpio nexus dt bindings") * PWM adoption: commit e71e46a6f19c ("pwm: Add support for pwm nexus dt bindings") Only expected Nexus property: - clock-map: maps inner clocks to inlet clocks (the other properties have been judged not relevant for clocks) Here is an example: Example: soc_clk: clock-controller { #clock-cells = <1>; }; container: container { #clock-cells = <1>; clock-map = <0 &soc_clk 2>, <1 &soc_clk 6>; child-device { clocks = <&container 1>; /* This is equivalent to <&soc_clk 6> */ }; }; The child device does not need to know about the outer implementation, and only knows about what the nexus provides. The nexus acts as a pass-through, with no extra control. Signed-off-by: Miquel Raynal (Schneider Electric) Reviewed-by: Herve Codina Reviewed-by: Brian Masney Reviewed-by: Frank Li Signed-off-by: Brian Masney --- drivers/clk/clk-conf.c | 12 ++++++------ drivers/clk/clk.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index 550b8ae375a2..da66b9ae3de5 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -25,8 +25,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) node); for (index = 0; index < num_parents; index++) { - rc = of_parse_phandle_with_args(node, "assigned-clock-parents", - "#clock-cells", index, &clkspec); + rc = of_parse_phandle_with_args_map(node, "assigned-clock-parents", + "clock", index, &clkspec); if (rc < 0) { /* skip empty (null) phandles */ if (rc == -ENOENT) @@ -47,8 +47,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) return PTR_ERR(pclk); } - rc = of_parse_phandle_with_args(node, "assigned-clocks", - "#clock-cells", index, &clkspec); + rc = of_parse_phandle_with_args_map(node, "assigned-clocks", + "clock", index, &clkspec); if (rc < 0) goto err; if (clkspec.np == node && !clk_supplier) { @@ -121,8 +121,8 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) rate = rates[index]; if (rate) { - rc = of_parse_phandle_with_args(node, "assigned-clocks", - "#clock-cells", index, &clkspec); + rc = of_parse_phandle_with_args_map(node, "assigned-clocks", + "clock", index, &clkspec); if (rc < 0) { /* skip empty (null) phandles */ if (rc == -ENOENT) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index cde94166835e..f1756fe59372 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -5309,8 +5309,8 @@ static int of_parse_clkspec(const struct device_node *np, int index, */ if (name) index = of_property_match_string(np, "clock-names", name); - ret = of_parse_phandle_with_args(np, "clocks", "#clock-cells", - index, out_args); + ret = of_parse_phandle_with_args_map(np, "clocks", "clock", + index, out_args); if (!ret) break; if (name && index >= 0) From 91b1b8d437abe0cd83210d8f257b785a63047aa9 Mon Sep 17 00:00:00 2001 From: "Miquel Raynal (Schneider Electric)" Date: Fri, 7 Aug 2026 17:24:08 +0200 Subject: [PATCH 068/168] clk: tests: Add Kunit testing for nexus nodes Add a nexus node with a child requesting a mapped clock in the fake DT overlay to verify that the parsing is also correctly working. Create an of_find_node_by_name() like kunit helper to garbage collect the node automatically in case of failed assertion. Suggested-by: Stephen Boyd Signed-off-by: Miquel Raynal (Schneider Electric) Reviewed-by: Frank Li Signed-off-by: Brian Masney --- drivers/clk/clk_kunit_helpers.c | 31 ++++++++++++++++++++++++ drivers/clk/clk_test.c | 15 ++++++++++++ drivers/clk/kunit_clk_parse_clkspec.dtso | 10 ++++++++ include/kunit/clk.h | 2 ++ 4 files changed, 58 insertions(+) diff --git a/drivers/clk/clk_kunit_helpers.c b/drivers/clk/clk_kunit_helpers.c index 68a28e70bb61..ab6b2cffcad6 100644 --- a/drivers/clk/clk_kunit_helpers.c +++ b/drivers/clk/clk_kunit_helpers.c @@ -233,5 +233,36 @@ int of_clk_add_hw_provider_kunit(struct kunit *test, struct device_node *np, } EXPORT_SYMBOL_GPL(of_clk_add_hw_provider_kunit); +KUNIT_DEFINE_ACTION_WRAPPER(of_node_put_wrapper, of_node_put, struct device_node *); + +/** + * clk_of_find_node_by_name_kunit() - Test managed of_find_node_by_name() + * @test: The test context + * @from: Parent device node to start searching from, or NULL to search from root + * @name: The name string to match against + * + * Just like of_find_node_by_name(), except the device_node is managed by + * the test case and is automatically put after the test case concludes. + * + * Return: the device_node on success, NULL if not found, or an error pointer on failure. + */ +struct device_node *clk_of_find_node_by_name_kunit(struct kunit *test, struct device_node *from, + const char *name) +{ + struct device_node *np; + int ret; + + np = of_find_node_by_name(from, name); + if (!np) + return NULL; + + ret = kunit_add_action_or_reset(test, of_node_put_wrapper, np); + if (ret) + return ERR_PTR(ret); + + return np; +} +EXPORT_SYMBOL_GPL(clk_of_find_node_by_name_kunit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("KUnit helpers for clk providers and consumers"); diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index bd424bb8dc27..91998b7474fc 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -3847,10 +3847,25 @@ static void of_clk_get_parent_name_gets_parent_name(struct kunit *test) of_clk_get_parent_name(ctx->cons_np, 0)); } +static void of_clk_get_hw_maps_thru_nexus(struct kunit *test) +{ + struct clk_parse_clkspec_ctx *ctx = test->priv; + struct clk_hw *expected; + struct device_node *np; + + np = clk_of_find_node_by_name_kunit(test, NULL, "kunit-clock-nexus-child"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, np); + expected = of_clk_get_hw(ctx->cons_np, 1, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected); + + KUNIT_EXPECT_PTR_EQ(test, expected, of_clk_get_hw(np, 0, NULL)); +} + static struct kunit_case clk_parse_clkspec_test_cases[] = { KUNIT_CASE(clk_parse_clkspec_with_correct_index_and_name), KUNIT_CASE(clk_parse_clkspec_with_incorrect_index_and_name), KUNIT_CASE(of_clk_get_parent_name_gets_parent_name), + KUNIT_CASE(of_clk_get_hw_maps_thru_nexus), {} }; diff --git a/drivers/clk/kunit_clk_parse_clkspec.dtso b/drivers/clk/kunit_clk_parse_clkspec.dtso index c93feb93e101..a4115216d2aa 100644 --- a/drivers/clk/kunit_clk_parse_clkspec.dtso +++ b/drivers/clk/kunit_clk_parse_clkspec.dtso @@ -18,4 +18,14 @@ kunit-clock-consumer { clocks = <&kunit_clock_provider1 0>, <&kunit_clock_provider2 0>; clock-names = "first_clock", "second_clock"; }; + + kunit_clock_nexus: kunit-clock-nexus { + clocks = <&kunit_clock_provider2 0>; + clock-map = <&kunit_clock_provider2 0>; + #clock-cells = <0>; + + kunit-clock-nexus-child { + clocks = <&kunit_clock_nexus>; + }; + }; }; diff --git a/include/kunit/clk.h b/include/kunit/clk.h index f226044cc78d..0b5ab8e971c9 100644 --- a/include/kunit/clk.h +++ b/include/kunit/clk.h @@ -29,5 +29,7 @@ int of_clk_hw_register_kunit(struct kunit *test, struct device_node *node, int of_clk_add_hw_provider_kunit(struct kunit *test, struct device_node *np, struct clk_hw *(*get)(struct of_phandle_args *clkspec, void *data), void *data); +struct device_node *clk_of_find_node_by_name_kunit(struct kunit *test, struct device_node *from, + const char *name); #endif From 35fdfcec52c21dd41e3181f9d1f814f7e72f62d0 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 25 Aug 2026 10:50:41 +0100 Subject: [PATCH 069/168] clk: renesas: r9a08g046: Add PCIe clocks and reset Add the PCIe module clocks (ACLK, CLKL1PM, CLK_PMU) and the PCIe reset signal for the RZ/G3L (R9A08G046) SoC, along with the P8 fixed clock required as the parent for CLKL1PM. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260825095047.9971-3-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g046-cpg.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clk/renesas/r9a08g046-cpg.c b/drivers/clk/renesas/r9a08g046-cpg.c index 5878423db151..22821321a1d3 100644 --- a/drivers/clk/renesas/r9a08g046-cpg.c +++ b/drivers/clk/renesas/r9a08g046-cpg.c @@ -335,6 +335,7 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = { dtable_8_256, 0, 0, 0, NULL), DEF_G3S_DIV("P3", R9A08G046_CLK_P3, CLK_PLL2_DIV2, G3L_DIVPL2A, G3L_DIVPL2A_STS, dtable_4_128, 0, 0, 0, NULL), + DEF_FIXED("P8", R9A08G046_CLK_P8, CLK_PLL3_DIV2, 1, 8), DEF_G3S_DIV("P13", R9A08G046_CLK_P13, CLK_SEL_RSCI0, G3L_DIV_RSCI0, G3L_DIV_RSCI0_STS, dtable_2_16, 0, 100000000UL, 0, NULL), DEF_G3S_DIV("P14", R9A08G046_CLK_P14, CLK_SEL_RSCI1, G3L_DIV_RSCI1, G3L_DIV_RSCI1_STS, @@ -558,6 +559,12 @@ static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = { MSTOP(BUS_MCPU2, BIT(0))), DEF_MOD("gpio_hclk", R9A08G046_GPIO_HCLK, R9A08G046_OSCCLK, 0x598, 0, MSTOP(BUS_PERI_CPU, BIT(6))), + DEF_MOD("pci_aclk", R9A08G046_PCI_ACLK, R9A08G046_CLK_P1, 0x608, 0, + MSTOP(BUS_PERI_COM, BIT(10))), + DEF_MOD("pci_clkl1pm", R9A08G046_PCI_CLKL1PM, R9A08G046_CLK_P8, 0x608, 1, + MSTOP(BUS_PERI_COM, BIT(10))), + DEF_MOD("pci_clk_pmu", R9A08G046_PCI_CLK_PMU, R9A08G046_CLK_P1, 0x608, 2, + MSTOP(BUS_PERI_COM, BIT(10))), DEF_MOD("rsci0_pclk", R9A08G046_RSCI0_PCLK, R9A08G046_CLK_P0, 0x618, 0, MSTOP(BUS_MCPU2, BIT(7))), DEF_MOD("rsci1_pclk", R9A08G046_RSCI1_PCLK, R9A08G046_CLK_P0, 0x618, 1, @@ -633,6 +640,7 @@ static const struct rzg2l_reset r9a08g046_resets[] = { DEF_RST(R9A08G046_GPIO_RSTN, 0x898, 0), DEF_RST(R9A08G046_GPIO_PORT_RESETN, 0x898, 1), DEF_RST(R9A08G046_GPIO_SPARE_RESETN, 0x898, 2), + DEF_RST(R9A08G046_PCI_ARESETN, 0x908, 0), DEF_RST(R9A08G046_RSCI0_PRESETN, 0x918, 0), DEF_RST(R9A08G046_RSCI1_PRESETN, 0x918, 1), DEF_RST(R9A08G046_RSCI2_PRESETN, 0x918, 2), @@ -671,6 +679,7 @@ static const unsigned int r9a08g046_no_pm_mod_clks[] = { MOD_CLK_BASE + R9A08G046_ETH1_CLK_RMII_I, MOD_CLK_BASE + R9A08G046_ETH1_CLK_TX_I_RMII, MOD_CLK_BASE + R9A08G046_ETH1_CLK_RX_I_RMII, + MOD_CLK_BASE + R9A08G046_PCI_CLKL1PM, }; const struct rzg2l_cpg_info r9a08g046_cpg_info = { From 6924d5d4973cc755c4ff0b87eae49ae5045d0828 Mon Sep 17 00:00:00 2001 From: John Madieu Date: Wed, 2 Sep 2026 10:49:38 +0000 Subject: [PATCH 070/168] clk: renesas: rzv2h: Drop duplicated parent lookup in fixed_mod_status_clk_register() rzv2h_cpg_fixed_mod_status_clk_register() looks up priv->clks[core->parent] twice, with an IS_ERR() check after each lookup. The second lookup is a leftover from an earlier refactor: the value cannot have changed between the two reads, so the second IS_ERR() check is dead code. Drop the duplicated lookup and check. No functional change intended. Signed-off-by: John Madieu Signed-off-by: Ovidiu Panait Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260902104939.25522-2-ovidiu.panait.rb@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzv2h-cpg.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c index 7003d59ac34b..86f6f2f700a6 100644 --- a/drivers/clk/renesas/rzv2h-cpg.c +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -923,9 +923,6 @@ rzv2h_cpg_fixed_mod_status_clk_register(const struct cpg_core_clk *core, return ERR_CAST(parent); parent_name = __clk_get_name(parent); - parent = priv->clks[core->parent]; - if (IS_ERR(parent)) - return ERR_CAST(parent); clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL); if (!clk_hw_data) From edabbfb616a89a0b783d9ef3936c964d2a1143ae Mon Sep 17 00:00:00 2001 From: John Madieu Date: Wed, 2 Sep 2026 10:49:39 +0000 Subject: [PATCH 071/168] clk: renesas: rzv2h: Convert to clk_hw based provider API The driver mixes the clk consumer API with the clk_hw provider API for its internal clock storage and OF lookup callback. Convert it to use clk_hw consistently. No functional change intended. Signed-off-by: John Madieu Signed-off-by: Ovidiu Panait Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260902104939.25522-3-ovidiu.panait.rb@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/rzv2h-cpg.c | 153 ++++++++++++++------------------ 1 file changed, 69 insertions(+), 84 deletions(-) diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c index 86f6f2f700a6..63f13fe4e4b0 100644 --- a/drivers/clk/renesas/rzv2h-cpg.c +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -99,7 +99,7 @@ struct rzv2h_pll_dsi_info { * @dev: CPG device * @base: CPG register block base address * @rmw_lock: protects register accesses - * @clks: Array containing all Core and Module Clocks + * @clks: Array containing all Core and Module clk_hw entries * @num_core_clks: Number of Core Clocks in clks[] * @num_mod_clks: Number of Module Clocks in clks[] * @resets: Array of resets @@ -115,7 +115,7 @@ struct rzv2h_cpg_priv { void __iomem *base; spinlock_t rmw_lock; - struct clk **clks; + struct clk_hw **clks; unsigned int num_core_clks; unsigned int num_mod_clks; struct rzv2h_reset *resets; @@ -332,14 +332,14 @@ static const struct clk_ops rzv2h_cpg_plldsi_div_ops = { .set_rate = rzv2h_cpg_plldsi_div_set_rate, }; -static struct clk * __init +static struct clk_hw * __init rzv2h_cpg_plldsi_div_clk_register(const struct cpg_core_clk *core, struct rzv2h_cpg_priv *priv) { struct rzv2h_plldsi_div_clk *clk_hw_data; - struct clk **clks = priv->clks; + struct clk_hw **clks = priv->clks; struct clk_init_data init = {}; - const struct clk *parent; + const struct clk_hw *parent; const char *parent_name; struct clk_hw *clk_hw; int ret; @@ -356,7 +356,7 @@ rzv2h_cpg_plldsi_div_clk_register(const struct cpg_core_clk *core, clk_hw_data->ddiv = core->cfg.ddiv; clk_hw_data->dtable = core->dtable; - parent_name = __clk_get_name(parent); + parent_name = clk_hw_get_name(parent); init.name = core->name; init.ops = &rzv2h_cpg_plldsi_div_ops; init.flags = core->flag; @@ -370,7 +370,7 @@ rzv2h_cpg_plldsi_div_clk_register(const struct cpg_core_clk *core, if (ret) return ERR_PTR(ret); - return clk_hw->clk; + return clk_hw; } static int rzv2h_cpg_plldsi_determine_rate(struct clk_hw *hw, @@ -577,7 +577,7 @@ static const struct clk_ops rzv2h_cpg_plldsi_smux_ops = { .set_duty_cycle = rzv2h_cpg_plldsi_smux_set_duty_cycle, }; -static struct clk * __init +static struct clk_hw * __init rzv2h_cpg_plldsi_smux_clk_register(const struct cpg_core_clk *core, struct rzv2h_cpg_priv *priv) { @@ -620,7 +620,7 @@ rzv2h_cpg_plldsi_smux_clk_register(const struct cpg_core_clk *core, if (ret) return ERR_PTR(ret); - return clk_hw->clk; + return clk_hw; } static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw) @@ -705,14 +705,14 @@ static const struct clk_ops rzv2h_cpg_pll_ops = { .recalc_rate = rzv2h_cpg_pll_clk_recalc_rate, }; -static struct clk * __init +static struct clk_hw * __init rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core, struct rzv2h_cpg_priv *priv, const struct clk_ops *ops) { struct device *dev = priv->dev; struct clk_init_data init = {}; - const struct clk *parent; + const struct clk_hw *parent; const char *parent_name; struct pll_clk *pll_clk; int ret; @@ -729,7 +729,7 @@ rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core, priv->pll_dsi_info[core->cfg.pll.instance].pll_dsi_limits = core->cfg.pll.limits; - parent_name = __clk_get_name(parent); + parent_name = clk_hw_get_name(parent); init.name = core->name; init.ops = ops; init.flags = 0; @@ -744,7 +744,7 @@ rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core, if (ret) return ERR_PTR(ret); - return pll_clk->hw.clk; + return &pll_clk->hw; } static unsigned long rzv2h_ddiv_recalc_rate(struct clk_hw *hw, @@ -820,7 +820,7 @@ static const struct clk_ops rzv2h_ddiv_clk_divider_ops = { .set_rate = rzv2h_ddiv_set_rate, }; -static struct clk * __init +static struct clk_hw * __init rzv2h_cpg_ddiv_clk_register(const struct cpg_core_clk *core, struct rzv2h_cpg_priv *priv) { @@ -829,7 +829,7 @@ rzv2h_cpg_ddiv_clk_register(const struct cpg_core_clk *core, struct device *dev = priv->dev; u8 shift = cfg_ddiv.shift; u8 width = cfg_ddiv.width; - const struct clk *parent; + const struct clk_hw *parent; const char *parent_name; struct clk_divider *div; struct ddiv_clk *ddiv; @@ -839,7 +839,7 @@ rzv2h_cpg_ddiv_clk_register(const struct cpg_core_clk *core, if (IS_ERR(parent)) return ERR_CAST(parent); - parent_name = __clk_get_name(parent); + parent_name = clk_hw_get_name(parent); if ((shift + width) > 16) return ERR_PTR(-EINVAL); @@ -872,15 +872,15 @@ rzv2h_cpg_ddiv_clk_register(const struct cpg_core_clk *core, if (ret) return ERR_PTR(ret); - return div->hw.clk; + return &div->hw; } -static struct clk * __init +static struct clk_hw * __init rzv2h_cpg_mux_clk_register(const struct cpg_core_clk *core, struct rzv2h_cpg_priv *priv) { struct smuxed mux = core->cfg.smux; - const struct clk_hw *clk_hw; + struct clk_hw *clk_hw; clk_hw = devm_clk_hw_register_mux(priv->dev, core->name, core->parent_names, core->num_parents, @@ -890,7 +890,7 @@ rzv2h_cpg_mux_clk_register(const struct cpg_core_clk *core, if (IS_ERR(clk_hw)) return ERR_CAST(clk_hw); - return clk_hw->clk; + return clk_hw; } static int @@ -906,14 +906,14 @@ rzv2h_clk_ff_mod_status_is_enabled(struct clk_hw *hw) return !!(val & bitmask); } -static struct clk * __init +static struct clk_hw * __init rzv2h_cpg_fixed_mod_status_clk_register(const struct cpg_core_clk *core, struct rzv2h_cpg_priv *priv) { struct rzv2h_ff_mod_status_clk *clk_hw_data; struct clk_init_data init = { }; struct clk_fixed_factor *fix; - const struct clk *parent; + const struct clk_hw *parent; const char *parent_name; int ret; @@ -922,7 +922,7 @@ rzv2h_cpg_fixed_mod_status_clk_register(const struct cpg_core_clk *core, if (IS_ERR(parent)) return ERR_CAST(parent); - parent_name = __clk_get_name(parent); + parent_name = clk_hw_get_name(parent); clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL); if (!clk_hw_data) @@ -946,18 +946,18 @@ rzv2h_cpg_fixed_mod_status_clk_register(const struct cpg_core_clk *core, if (ret) return ERR_PTR(ret); - return clk_hw_data->fix.hw.clk; + return &clk_hw_data->fix.hw; } -static struct clk +static struct clk_hw *rzv2h_cpg_clk_src_twocell_get(struct of_phandle_args *clkspec, void *data) { unsigned int clkidx = clkspec->args[1]; struct rzv2h_cpg_priv *priv = data; struct device *dev = priv->dev; + struct clk_hw *clk_hw; const char *type; - struct clk *clk; switch (clkspec->args[0]) { case CPG_CORE: @@ -966,7 +966,7 @@ static struct clk dev_err(dev, "Invalid %s clock index %u\n", type, clkidx); return ERR_PTR(-EINVAL); } - clk = priv->clks[clkidx]; + clk_hw = priv->clks[clkidx]; break; case CPG_MOD: @@ -975,7 +975,7 @@ static struct clk dev_err(dev, "Invalid %s clock index %u\n", type, clkidx); return ERR_PTR(-EINVAL); } - clk = priv->clks[priv->num_core_clks + clkidx]; + clk_hw = priv->clks[priv->num_core_clks + clkidx]; break; default: @@ -983,25 +983,25 @@ static struct clk return ERR_PTR(-EINVAL); } - if (IS_ERR(clk)) + if (IS_ERR(clk_hw)) dev_err(dev, "Cannot get %s clock %u: %ld\n", type, clkidx, - PTR_ERR(clk)); + PTR_ERR(clk_hw)); else - dev_dbg(dev, "clock (%u, %u) is %pC at %lu Hz\n", - clkspec->args[0], clkspec->args[1], clk, - clk_get_rate(clk)); - return clk; + dev_dbg(dev, "clock (%u, %u) is %s at %lu Hz\n", + clkspec->args[0], clkspec->args[1], + clk_hw_get_name(clk_hw), clk_hw_get_rate(clk_hw)); + return clk_hw; } static void __init rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core, struct rzv2h_cpg_priv *priv) { - struct clk *clk = ERR_PTR(-EOPNOTSUPP), *parent; + struct clk_hw *clk_hw = ERR_PTR(-EOPNOTSUPP), *parent; unsigned int id = core->id, div = core->div; struct device *dev = priv->dev; const char *parent_name; - struct clk_hw *clk_hw; + struct clk *clk; WARN_DEBUG(id >= priv->num_core_clks); WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); @@ -1009,70 +1009,72 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core, switch (core->type) { case CLK_TYPE_IN: clk = of_clk_get_by_name(priv->dev->of_node, core->name); + if (IS_ERR(clk)) { + clk_hw = ERR_CAST(clk); + goto fail; + } + clk_hw = __clk_get_hw(clk); break; case CLK_TYPE_FF: WARN_DEBUG(core->parent >= priv->num_core_clks); parent = priv->clks[core->parent]; if (IS_ERR(parent)) { - clk = parent; + clk_hw = parent; goto fail; } - parent_name = __clk_get_name(parent); + parent_name = clk_hw_get_name(parent); clk_hw = devm_clk_hw_register_fixed_factor(dev, core->name, parent_name, CLK_SET_RATE_PARENT, core->mult, div); - if (IS_ERR(clk_hw)) - clk = ERR_CAST(clk_hw); - else - clk = clk_hw->clk; break; case CLK_TYPE_FF_MOD_STATUS: if (!priv->ff_mod_status_ops) { priv->ff_mod_status_ops = devm_kzalloc(dev, sizeof(*priv->ff_mod_status_ops), GFP_KERNEL); if (!priv->ff_mod_status_ops) { - clk = ERR_PTR(-ENOMEM); + clk_hw = ERR_PTR(-ENOMEM); goto fail; } memcpy(priv->ff_mod_status_ops, &clk_fixed_factor_ops, sizeof(const struct clk_ops)); priv->ff_mod_status_ops->is_enabled = rzv2h_clk_ff_mod_status_is_enabled; } - clk = rzv2h_cpg_fixed_mod_status_clk_register(core, priv); + clk_hw = rzv2h_cpg_fixed_mod_status_clk_register(core, priv); break; case CLK_TYPE_PLL: - clk = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_pll_ops); + clk_hw = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_pll_ops); break; case CLK_TYPE_DDIV: - clk = rzv2h_cpg_ddiv_clk_register(core, priv); + clk_hw = rzv2h_cpg_ddiv_clk_register(core, priv); break; case CLK_TYPE_SMUX: - clk = rzv2h_cpg_mux_clk_register(core, priv); + clk_hw = rzv2h_cpg_mux_clk_register(core, priv); break; case CLK_TYPE_PLLDSI: - clk = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_plldsi_ops); + clk_hw = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_plldsi_ops); break; case CLK_TYPE_PLLDSI_DIV: - clk = rzv2h_cpg_plldsi_div_clk_register(core, priv); + clk_hw = rzv2h_cpg_plldsi_div_clk_register(core, priv); break; case CLK_TYPE_PLLDSI_SMUX: - clk = rzv2h_cpg_plldsi_smux_clk_register(core, priv); + clk_hw = rzv2h_cpg_plldsi_smux_clk_register(core, priv); break; default: goto fail; } - if (IS_ERR(clk)) + if (IS_ERR(clk_hw)) goto fail; - dev_dbg(dev, "Core clock %pC at %lu Hz\n", clk, clk_get_rate(clk)); - priv->clks[id] = clk; + dev_dbg(dev, "Core clock %s at %lu Hz\n", + clk_hw_get_name(clk_hw), clk_hw_get_rate(clk_hw)); + priv->clks[id] = clk_hw; return; fail: - dev_err(dev, "Failed to register core clock %s: %ld\n", - core->name, PTR_ERR(clk)); + dev_err(dev, "Failed to register core clock %s: %ld\n", core->name, + PTR_ERR(clk_hw)); } static void rzv2h_mod_clock_mstop_enable(struct rzv2h_cpg_priv *priv, @@ -1119,15 +1121,10 @@ static void rzv2h_mod_clock_mstop_disable(struct rzv2h_cpg_priv *priv, static int rzv2h_parent_clk_mux_to_index(struct clk_hw *hw) { - struct clk_hw *parent_hw; - struct clk *parent_clk; + struct clk_hw *parent_hw = clk_hw_get_parent(hw); struct clk_mux *mux; u32 val; - /* This will always succeed, so no need to check for IS_ERR() */ - parent_clk = clk_get_parent(hw->clk); - - parent_hw = __clk_get_hw(parent_clk); mux = to_clk_mux(parent_hw); val = readl(mux->reg) >> mux->shift; @@ -1227,8 +1224,8 @@ rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod, struct mod_clock *clock = NULL; struct device *dev = priv->dev; struct clk_init_data init = {}; - struct clk *parent, *clk; const char *parent_name; + struct clk_hw *parent; unsigned int id; int ret; @@ -1239,13 +1236,13 @@ rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod, parent = priv->clks[mod->parent]; if (IS_ERR(parent)) { - clk = parent; + ret = PTR_ERR(parent); goto fail; } clock = devm_kzalloc(dev, sizeof(*clock), GFP_KERNEL); if (!clock) { - clk = ERR_PTR(-ENOMEM); + ret = -ENOMEM; goto fail; } @@ -1255,7 +1252,7 @@ rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod, if (mod->critical) init.flags |= CLK_IS_CRITICAL; - parent_name = __clk_get_name(parent); + parent_name = clk_hw_get_name(parent); init.parent_names = &parent_name; init.num_parents = 1; @@ -1270,12 +1267,10 @@ rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod, clock->mstop_data = mod->mstop_data; ret = devm_clk_hw_register(dev, &clock->hw); - if (ret) { - clk = ERR_PTR(ret); + if (ret) goto fail; - } - priv->clks[id] = clock->hw.clk; + priv->clks[id] = &clock->hw; /* * Ensure the module clocks and MSTOP bits are synchronized when they are @@ -1314,8 +1309,8 @@ rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod, return; fail: - dev_err(dev, "Failed to register module clock %s: %ld\n", - mod->name, PTR_ERR(clk)); + dev_err(dev, "Failed to register module clock %s: %d\n", mod->name, + ret); } static int __rzv2h_cpg_assert(struct reset_controller_dev *rcdev, @@ -1448,7 +1443,7 @@ static bool rzv2h_cpg_is_pm_clk(struct rzv2h_cpg_pd *pd, if (priv->clks[priv->num_core_clks + id] == ERR_PTR(-ENOENT)) return false; - clock = to_mod_clock(__clk_get_hw(priv->clks[priv->num_core_clks + id])); + clock = to_mod_clock(priv->clks[priv->num_core_clks + id]); return !clock->no_pm; } @@ -1547,19 +1542,13 @@ static int __init rzv2h_cpg_add_pm_domains(struct rzv2h_cpg_priv *priv) return of_genpd_add_provider_simple(np, &pd->genpd); } -static void rzv2h_cpg_del_clk_provider(void *data) -{ - of_clk_del_provider(data); -} - static int __init rzv2h_cpg_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; const struct rzv2h_cpg_info *info; struct rzv2h_cpg_priv *priv; unsigned int nclks, i; - struct clk **clks; + struct clk_hw **clks; int error; info = of_device_get_match_data(dev); @@ -1610,11 +1599,7 @@ static int __init rzv2h_cpg_probe(struct platform_device *pdev) for (i = 0; i < info->num_mod_clks; i++) rzv2h_cpg_register_mod_clk(&info->mod_clks[i], priv); - error = of_clk_add_provider(np, rzv2h_cpg_clk_src_twocell_get, priv); - if (error) - return error; - - error = devm_add_action_or_reset(dev, rzv2h_cpg_del_clk_provider, np); + error = devm_of_clk_add_hw_provider(dev, rzv2h_cpg_clk_src_twocell_get, priv); if (error) return error; From 3c120e1c651da5c13b803f4742cc5d929b78a772 Mon Sep 17 00:00:00 2001 From: Aiden Isik Date: Tue, 18 Aug 2026 22:58:35 +0100 Subject: [PATCH 072/168] dt-bindings: clock: Add Exynos5515 SoC Add devicetree documentation for the Exynos5515 SoC's CMUs. Add device tree bindings for the following CMUs: - CMU_TOP - CMU_PERI - CMU_FSYS Signed-off-by: Aiden Isik Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260818-for-next-lucky7-clock-v2-1-cda0cc80f158@member.fsf.org Signed-off-by: Krzysztof Kozlowski --- .../clock/samsung,exynos5515-cmu.yaml | 145 +++++++++++++ .../clock/samsung,exynos5515-cmu.h | 191 ++++++++++++++++++ 2 files changed, 336 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/samsung,exynos5515-cmu.yaml create mode 100644 include/dt-bindings/clock/samsung,exynos5515-cmu.h diff --git a/Documentation/devicetree/bindings/clock/samsung,exynos5515-cmu.yaml b/Documentation/devicetree/bindings/clock/samsung,exynos5515-cmu.yaml new file mode 100644 index 000000000000..1be8962cda1c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/samsung,exynos5515-cmu.yaml @@ -0,0 +1,145 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/samsung,exynos5515-cmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung Exynos5515 SoC clock controller + +maintainers: + - Aiden Isik + - Chanwoo Choi + - Krzysztof Kozlowski + +description: | + Exynos5515 clock controller is comprised of several CMU units, generating + clocks for different domains. Those CMU units are modeled as separate device + tree nodes, and might depend on each other. The root clock in that root tree + is an external clock: OSCCLK (26 MHz). This external clock must be defined + as a fixed-rate clock in dts. + + CMU_TOP is a top-level CMU, where all base clocks are prepared using PLLs and + dividers; all other clocks of function blocks (other CMUs) are usually + derived from CMU_TOP. + + Each clock is assigned an identifier and client nodes can use this identifier + to specify the clock which they consume. All clocks available for usage + in clock consumer nodes are defined as preprocessor macros in + 'include/dt-bindings/clock/samsung,exynos5515-cmu.h' header. + +properties: + compatible: + enum: + - samsung,exynos5515-cmu-fsys + - samsung,exynos5515-cmu-peri + - samsung,exynos5515-cmu-top + + clocks: + minItems: 1 + maxItems: 5 + + clock-names: + minItems: 1 + maxItems: 5 + + "#clock-cells": + const: 1 + + reg: + maxItems: 1 + + samsung,sysreg: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to system registers interface. + +required: + - compatible + - clocks + - clock-names + - "#clock-cells" + - reg + - samsung,sysreg + +allOf: + - if: + properties: + compatible: + contains: + enum: + - samsung,exynos5515-cmu-fsys + + then: + properties: + clocks: + items: + - description: External reference clock (26MHz) + - description: CMU_FSYS BUS clock (from CMU_TOP) + - description: CMU_FSYS MMC card clock (from CMU_TOP) + - description: CMU_FSYS MMC embedded clock (from CMU_TOP) + - description: CMU_FSYS USB20DRD clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: bus + - const: mmc_card + - const: mmc_embd + - const: usb20drd + + - if: + properties: + compatible: + contains: + enum: + - samsung,exynos5515-cmu-peri + + then: + properties: + clocks: + items: + - description: External reference clock (26MHz) + - description: CMU_PERI BUS clock (from CMU_TOP) + - description: CMU_PERI IP clock (from CMU_TOP) + - description: CMU_PERI UART clock (from CMU_TOP) + + clock-names: + items: + - const: oscclk + - const: bus + - const: ip + - const: uart + + - if: + properties: + compatible: + contains: + const: samsung,exynos5515-cmu-top + + then: + properties: + clocks: + items: + - description: External reference clock (26 MHz) + + clock-names: + items: + - const: oscclk + +additionalProperties: false + +examples: + - | + #include + + cmu_top: clock-controller@15410000 { + compatible = "samsung,exynos5515-cmu-top"; + reg = <0x15410000 0x10000>; + #clock-cells = <1>; + + clocks = <&oscclk>; + clock-names = "oscclk"; + samsung,sysreg = <&sysreg_top>; + }; + +... diff --git a/include/dt-bindings/clock/samsung,exynos5515-cmu.h b/include/dt-bindings/clock/samsung,exynos5515-cmu.h new file mode 100644 index 000000000000..2877d3681b55 --- /dev/null +++ b/include/dt-bindings/clock/samsung,exynos5515-cmu.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2026 Aiden Isik + * Author: Aiden Isik + * + * Device Tree binding constants for Exynos5515 clock controller. + */ + +#ifndef _DT_BINDINGS_CLOCK_EXYNOS5515_H +#define _DT_BINDINGS_CLOCK_EXYNOS5515_H + +/* CMU_TOP */ +#define CLK_FOUT_AUD_PLL 1 +#define CLK_FOUT_SHARED0_PLL 2 +#define CLK_FOUT_SHARED1_PLL 3 + +#define CLK_MOUT_CMU_APM_BUS 4 +#define CLK_MOUT_CMU_CORE_BUS 5 +#define CLK_MOUT_CMU_CORE_SSS 6 +#define CLK_MOUT_CMU_CPUCL0_BUSP 7 +#define CLK_MOUT_CMU_CPUCL0_CPU 8 +#define CLK_MOUT_CMU_CPUCL0_DBG 9 +#define CLK_MOUT_CMU_DPU_AUDIF 10 +#define CLK_MOUT_CMU_DPU_AUD_BUS 11 +#define CLK_MOUT_CMU_DPU_AUD_CPU 12 +#define CLK_MOUT_CMU_DPU_BUS 13 +#define CLK_MOUT_CMU_FSYS_BUS 14 +#define CLK_MOUT_CMU_FSYS_MMC_CARD 15 +#define CLK_MOUT_CMU_FSYS_MMC_EMBD 16 +#define CLK_MOUT_CMU_FSYS_USB20DRD 17 +#define CLK_MOUT_CMU_G3D_BUS 18 +#define CLK_MOUT_CMU_MFC_BUS 19 +#define CLK_MOUT_CMU_MIF_BUSP 20 +#define CLK_MOUT_CMU_MIF_SWITCH 21 +#define CLK_MOUT_CMU_MODEM_SHARED1 22 +#define CLK_MOUT_CMU_PERI_BUS 23 +#define CLK_MOUT_CMU_PERI_IP 24 +#define CLK_MOUT_CMU_PERI_UART 25 +#define CLK_MOUT_CMU_CMUREF 26 + +#define CLK_DOUT_AP2CP_SHARED0_PLL 27 +#define CLK_DOUT_AP2CP_SHARED1_PLL 28 +#define CLK_DOUT_AP2CP_SHARED2_PLL 29 +#define CLK_DOUT_CMU_APM_BUS 30 +#define CLK_DOUT_CMU_CMU_BOOST 31 +#define CLK_DOUT_CMU_CORE_BUS 32 +#define CLK_DOUT_CMU_CORE_SSS 33 +#define CLK_DOUT_CMU_CPUCL0_BUSP 34 +#define CLK_DOUT_CMU_CPUCL0_CPU 35 +#define CLK_DOUT_CMU_CPUCL0_DBG 36 +#define CLK_DOUT_CMU_DPU_AUDIF 37 +#define CLK_DOUT_CMU_DPU_AUD_BUS 38 +#define CLK_DOUT_CMU_DPU_AUD_CPU 39 +#define CLK_DOUT_CMU_DPU_BUS 40 +#define CLK_DOUT_CMU_FSYS_BUS 41 +#define CLK_DOUT_CMU_FSYS_MMC_CARD 42 +#define CLK_DOUT_CMU_FSYS_MMC_EMBD 43 +#define CLK_DOUT_CMU_FSYS_USB20DRD 44 +#define CLK_DOUT_CMU_G3D_BUS 45 +#define CLK_DOUT_CMU_MFC_BUS 46 +#define CLK_DOUT_CMU_MIF_BUSP 47 +#define CLK_DOUT_CMU_PERI_BUS 48 +#define CLK_DOUT_CMU_PERI_IP 49 +#define CLK_DOUT_CMU_PERI_UART 50 +#define CLK_DOUT_CMU_CMUREF 51 + +#define CLK_DOUT_SHARED0_DIV2 52 +#define CLK_DOUT_SHARED0_DIV3 53 +#define CLK_DOUT_SHARED0_DIV4 54 +#define CLK_DOUT_SHARED1_DIV2 55 +#define CLK_DOUT_SHARED1_DIV3 56 +#define CLK_DOUT_SHARED1_DIV4 57 +#define CLK_DOUT_AUD_DIV2 58 +#define CLK_DOUT_AUD_DIV3 59 +#define CLK_DOUT_AUD_DIV4 60 + +#define CLK_GOUT_CMU_MIF_SWITCH 61 +#define CLK_GOUT_CMU_APM_BUS 62 +#define CLK_GOUT_CMU_CORE_BUS 63 +#define CLK_GOUT_CMU_CORE_SSS 64 +#define CLK_GOUT_CMU_CPUCL0_BUSP 65 +#define CLK_GOUT_CMU_CPUCL0_CPU 66 +#define CLK_GOUT_CMU_CPUCL0_DBG 67 +#define CLK_GOUT_CMU_DPU_AUDIF 68 +#define CLK_GOUT_CMU_DPU_AUD_BUS 69 +#define CLK_GOUT_CMU_DPU_AUD_CPU 70 +#define CLK_GOUT_CMU_DPU_BUS 71 +#define CLK_GOUT_CMU_FSYS_BUS 72 +#define CLK_GOUT_CMU_FSYS_MMC_CARD 73 +#define CLK_GOUT_CMU_FSYS_MMC_EMBD 74 +#define CLK_GOUT_CMU_FSYS_USB20DRD 75 +#define CLK_GOUT_CMU_G3D_BUS 76 +#define CLK_GOUT_CMU_MFC_BUS 77 +#define CLK_GOUT_CMU_MIF_BUSP 78 +#define CLK_GOUT_CMU_MODEM_SHARED0 79 +#define CLK_GOUT_CMU_MODEM_SHARED1 80 +#define CLK_GOUT_CMU_MODEM_SHARED2 81 +#define CLK_GOUT_CMU_PERI_BUS 82 +#define CLK_GOUT_CMU_PERI_IP 83 +#define CLK_GOUT_CMU_PERI_UART 84 + +/* CMU_PERI */ +#define CLK_MOUT_PLL_PERI_BUS_USER 1 +#define CLK_MOUT_PLL_PERI_IP_USER 2 +#define CLK_MOUT_PLL_PERI_UART_USER 3 +#define CLK_MOUT_PERI_SPI 4 +#define CLK_MOUT_PERI_USI00_USI 5 + +#define CLK_DOUT_PERI_OTP 6 + +#define CLK_DOUT_PERI_I2C_0 7 +#define CLK_DOUT_PERI_I2C_1 8 +#define CLK_DOUT_PERI_I2C_2 9 +#define CLK_DOUT_PERI_I2C_3 10 +#define CLK_DOUT_PERI_SPI 11 +#define CLK_DOUT_PERI_USI00_I2C 12 +#define CLK_DOUT_PERI_USI00_USI 13 + +#define CLK_GOUT_PERI_BUSIF_TMU_PCLK 14 +#define CLK_GOUT_PERI_D_TZPC_PCLK 15 +#define CLK_GOUT_PERI_GPIO_PCLK 16 +#define CLK_GOUT_PERI_I2C_0_IPCLK 17 +#define CLK_GOUT_PERI_I2C_0_PCLK 18 +#define CLK_GOUT_PERI_I2C_1_IPCLK 19 +#define CLK_GOUT_PERI_I2C_1_PCLK 20 +#define CLK_GOUT_PERI_I2C_2_IPCLK 21 +#define CLK_GOUT_PERI_I2C_2_PCLK 22 +#define CLK_GOUT_PERI_I2C_3_IPCLK 23 +#define CLK_GOUT_PERI_I2C_3_PCLK 24 +#define CLK_GOUT_PERI_MCT_PCLK 25 +#define CLK_GOUT_PERI_OTP_OSCCLK 26 +#define CLK_GOUT_PERI_OTP_PCLK 27 +#define CLK_GOUT_PERI_CMU_PCLK 28 +#define CLK_GOUT_PERI_PWM_MOTOR_PCLK 29 +#define CLK_GOUT_PERI_BUS_CLK 30 +#define CLK_GOUT_PERI_I2C_0_CLK 31 +#define CLK_GOUT_PERI_I2C_1_CLK 32 +#define CLK_GOUT_PERI_I2C_2_CLK 33 +#define CLK_GOUT_PERI_I2C_3_CLK 34 +#define CLK_GOUT_PERI_OSCCLK 35 +#define CLK_GOUT_PERI_SPI_CLK 36 +#define CLK_GOUT_PERI_UART_CLK 37 +#define CLK_GOUT_PERI_USI00_I2C_CLK 38 +#define CLK_GOUT_PERI_USI00_USI_CLK 39 +#define CLK_GOUT_PERI_SLH_AXI_MI_P_CLK 40 +#define CLK_GOUT_PERI_SYSREG_PCLK 41 +#define CLK_GOUT_PERI_USI00_I2C_IPCLK 42 +#define CLK_GOUT_PERI_USI00_I2C_PCLK 43 +#define CLK_GOUT_PERI_USI00_USI_IPCLK 44 +#define CLK_GOUT_PERI_USI00_USI_PCLK 45 +#define CLK_GOUT_PERI_USI_SPI_IPCLK 46 +#define CLK_GOUT_PERI_USI_SPI_PCLK 47 +#define CLK_GOUT_PERI_USI_UART_IPCLK 48 +#define CLK_GOUT_PERI_USI_UART_PCLK 49 +#define CLK_GOUT_PERI_WDT0_PCLK 50 +#define CLK_GOUT_PERI_WDT1_PCLK 51 +#define CLK_GOUT_PERI_I2C_0 52 +#define CLK_GOUT_PERI_I2C_1 53 +#define CLK_GOUT_PERI_I2C_2 54 +#define CLK_GOUT_PERI_I2C_3 55 +#define CLK_GOUT_PERI_USI00_I2C 56 + +/* CMU_FSYS */ +#define CLK_MOUT_PLL_FSYS_BUS_USER 1 +#define CLK_MOUT_PLL_FSYS_MMC_CARD_USER 2 +#define CLK_MOUT_PLL_FSYS_MMC_EMBD_USER 3 +#define CLK_MOUT_PLL_FSYS_USB20DRD_USER 4 + +#define CLK_GOUT_FSYS_CMU_PCLK 5 +#define CLK_GOUT_FSYS_MMC_CARD_SDCLKIN 6 +#define CLK_GOUT_FSYS_MMC_EMBD_SDCLKIN 7 +#define CLK_GOUT_FSYS_OSCCLK 8 +#define CLK_GOUT_FSYS_USB20DRD_REFCLK 9 +#define CLK_GOUT_FSYS_USB20DRD_PHY_REFCLK 10 +#define CLK_GOUT_FSYS_D_TZPC_PCLK 11 +#define CLK_GOUT_FSYS_GPIO_PCLK 12 +#define CLK_GOUT_FSYS_MMC_CARD_ACLK 13 +#define CLK_GOUT_FSYS_MMC_EMBD_ACLK 14 +#define CLK_GOUT_FSYS_PPMU_ACLK 15 +#define CLK_GOUT_FSYS_PPMU_PCLK 16 +#define CLK_GOUT_FSYS_BUS_CLK 17 +#define CLK_GOUT_FSYS_SLH_AXI_MI_P_CLK 18 +#define CLK_GOUT_FSYS_SLH_AXI_SI_D_CLK 19 +#define CLK_GOUT_FSYS_SYSREG_PCLK 20 +#define CLK_GOUT_FSYS_USB20DRD_ACLK_PHYCTRL 21 +#define CLK_GOUT_FSYS_USB20DRD_BUS_CLK_EARLY 22 +#define CLK_GOUT_FSYS_US_64TO128_ACLK 23 +#define CLK_GOUT_FSYS_XIU_D_ACLK 24 +#define CLK_GOUT_FSYS_XIU_P_ACLK 25 + +#endif /* _DT_BINDINGS_CLOCK_EXYNOS5515_H */ From 6fb3239a9a58399ea787887ad555b6f6cfadbddb Mon Sep 17 00:00:00 2001 From: Aiden Isik Date: Tue, 18 Aug 2026 22:58:36 +0100 Subject: [PATCH 073/168] clk: samsung: clk-pll: Add support for pll_309 pll_309 (referred to in the downstream kernel sources as frd_309_rpll) is one of two PLLs used in the Exynos5515 SoC. It is an integer/fractional PLL with an FVCO of 600-2400MHz. It has the same locktime (500), and kdiv/mdiv/pdiv/sdiv masks and shifts as pll_531x, so it can be handled in exactly the same way. When defining a PLL, the "con" parameter should be set to the CON3 register, like this: PLL(pll_309, CLK_FOUT_AUD_PLL, "fout_aud_pll", "oscclk", PLL_LOCKTIME_PLL_AUD, PLL_CON3_PLL_AUD, NULL), Signed-off-by: Aiden Isik Link: https://patch.msgid.link/20260818-for-next-lucky7-clock-v2-2-cda0cc80f158@member.fsf.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-pll.c | 1 + drivers/clk/samsung/clk-pll.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index e74552846ba3..8a87c8ef7f80 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -1726,6 +1726,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, else init.ops = &samsung_pll2650xx_clk_ops; break; + case pll_309: case pll_531x: case pll_4311: init.ops = &samsung_pll531x_clk_ops; diff --git a/drivers/clk/samsung/clk-pll.h b/drivers/clk/samsung/clk-pll.h index d6eb3246611b..2457cf47c109 100644 --- a/drivers/clk/samsung/clk-pll.h +++ b/drivers/clk/samsung/clk-pll.h @@ -53,6 +53,7 @@ enum samsung_pll_type { pll_1031x, pll_a9fracm, pll_a9fraco, + pll_309, }; #define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \ From 0ae5dad7d9e6e4b8c8f3611f04fa929e634630e5 Mon Sep 17 00:00:00 2001 From: Aiden Isik Date: Tue, 18 Aug 2026 22:58:37 +0100 Subject: [PATCH 074/168] clk: samsung: Introduce Exynos5515 clock driver CMU_TOP is the top level clock management unit which contains PLLs, muxes, dividers and gates that feed the other clock management units. CMU_PERI provides clocks for USI blocks and their children, PWM, MCT, and watchdog timers. CMU_FSYS provides clocks for MMC, USB, GPIO, etc. More blocks will be added as device drivers which utilise them are added. Signed-off-by: Aiden Isik Link: https://patch.msgid.link/20260818-for-next-lucky7-clock-v2-3-cda0cc80f158@member.fsf.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/Makefile | 1 + drivers/clk/samsung/clk-exynos5515.c | 1484 ++++++++++++++++++++++++++ 2 files changed, 1485 insertions(+) create mode 100644 drivers/clk/samsung/clk-exynos5515.c diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index b3c4ef4e0dbf..b3e994bd525d 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o obj-$(CONFIG_EXYNOS_CLKOUT) += clk-exynos-clkout.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos-arm64.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos2200.o +obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5515.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7870.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7885.o diff --git a/drivers/clk/samsung/clk-exynos5515.c b/drivers/clk/samsung/clk-exynos5515.c new file mode 100644 index 000000000000..ddcef5819034 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos5515.c @@ -0,0 +1,1484 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2026 Aiden Isik + * Author: Aiden Isik + * + * Common Clock Framework support for Exynos5515 SoC. + */ + +#include +#include +#include + +#include + +#include "clk.h" +#include "clk-exynos-arm64.h" +#include "clk-pll.h" + +/* NOTE: Must be equal to the last clock ID increased by one */ +#define CLKS_NR_TOP (CLK_GOUT_CMU_PERI_UART + 1) +#define CLKS_NR_PERI (CLK_GOUT_PERI_USI00_I2C + 1) +#define CLKS_NR_FSYS (CLK_GOUT_FSYS_XIU_P_ACLK + 1) + +#define EXYNOS5515_GATE_DBG_OFFSET 0x4000 +#define EXYNOS5515_DRCG_EN_OFFSET 0x0104 +#define EXYNOS5515_MEMCLK_OFFSET 0x0108 + +/* ---- CMU_TOP ------------------------------------------------------------- */ + +/* + * CMU_TOP: 0x15410000 + * SYSREG_TOP: 0x15430000 + */ + +/* Register Offset definitions for CMU_TOP */ +#define PLL_LOCKTIME_PLL_AUD 0x0000 +#define PLL_LOCKTIME_PLL_SHARED0 0x0004 +#define PLL_LOCKTIME_PLL_SHARED1 0x0008 +#define PLL_CON3_PLL_AUD 0x010c +#define PLL_CON8_PLL_AUD 0x0120 +#define PLL_CON9_PLL_AUD 0x0124 +#define PLL_CON3_PLL_SHARED0 0x014c +#define PLL_CON8_PLL_SHARED0 0x0160 +#define PLL_CON9_PLL_SHARED0 0x0164 +#define PLL_CON3_PLL_SHARED1 0x018c +#define PLL_CON8_PLL_SHARED1 0x01a0 +#define PLL_CON9_PLL_SHARED1 0x01a4 +#define CMU_CMU_TOP_CONTROLLER_OPTION 0x0800 +#define CLK_CON_MUX_MUX_CLKCMU_APM_BUS 0x1000 +#define CLK_CON_MUX_MUX_CLKCMU_CORE_BUS 0x1004 +#define CLK_CON_MUX_MUX_CLKCMU_CORE_SSS 0x1008 +#define CLK_CON_MUX_MUX_CLKCMU_CPUCL0_BUSP 0x100c +#define CLK_CON_MUX_MUX_CLKCMU_CPUCL0_CPU 0x1010 +#define CLK_CON_MUX_MUX_CLKCMU_CPUCL0_DBG 0x1014 +#define CLK_CON_MUX_MUX_CLKCMU_DPU_AUDIF 0x1018 +#define CLK_CON_MUX_MUX_CLKCMU_DPU_AUD_BUS 0x101c +#define CLK_CON_MUX_MUX_CLKCMU_DPU_AUD_CPU 0x1020 +#define CLK_CON_MUX_MUX_CLKCMU_DPU_BUS 0x1024 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS_BUS 0x1028 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS_MMC_CARD 0x102c +#define CLK_CON_MUX_MUX_CLKCMU_FSYS_MMC_EMBD 0x1030 +#define CLK_CON_MUX_MUX_CLKCMU_FSYS_USB20DRD 0x1034 +#define CLK_CON_MUX_MUX_CLKCMU_G3D_BUS 0x1038 +#define CLK_CON_MUX_MUX_CLKCMU_MFC_BUS 0x103c +#define CLK_CON_MUX_MUX_CLKCMU_MIF_BUSP 0x1040 +#define CLK_CON_MUX_MUX_CLKCMU_MIF_SWITCH 0x1044 +#define CLK_CON_MUX_MUX_CLKCMU_MODEM_SHARED1 0x1048 +#define CLK_CON_MUX_MUX_CLKCMU_PERI_BUS 0x104c +#define CLK_CON_MUX_MUX_CLKCMU_PERI_IP 0x1050 +#define CLK_CON_MUX_MUX_CLKCMU_PERI_UART 0x1054 +#define CLK_CON_MUX_MUX_CMU_CMUREF 0x1058 +#define CLK_CON_DIV_AP2CP_SHARED0_PLL_CLK 0x1800 +#define CLK_CON_DIV_AP2CP_SHARED1_PLL_CLK 0x1804 +#define CLK_CON_DIV_AP2CP_SHARED2_PLL_CLK 0x1808 +#define CLK_CON_DIV_CLKCMU_APM_BUS 0x180c +#define CLK_CON_DIV_CLKCMU_CMU_BOOST 0x1810 +#define CLK_CON_DIV_CLKCMU_CORE_BUS 0x1814 +#define CLK_CON_DIV_CLKCMU_CORE_SSS 0x1818 +#define CLK_CON_DIV_CLKCMU_CPUCL0_BUSP 0x181c +#define CLK_CON_DIV_CLKCMU_CPUCL0_CPU 0x1820 +#define CLK_CON_DIV_CLKCMU_CPUCL0_DBG 0x1824 +#define CLK_CON_DIV_CLKCMU_DPU_AUDIF 0x1828 +#define CLK_CON_DIV_CLKCMU_DPU_AUD_BUS 0x182c +#define CLK_CON_DIV_CLKCMU_DPU_AUD_CPU 0x1830 +#define CLK_CON_DIV_CLKCMU_DPU_BUS 0x1834 +#define CLK_CON_DIV_CLKCMU_FSYS_BUS 0x1838 +#define CLK_CON_DIV_CLKCMU_FSYS_MMC_CARD 0x183c +#define CLK_CON_DIV_CLKCMU_FSYS_MMC_EMBD 0x1840 +#define CLK_CON_DIV_CLKCMU_FSYS_USB20DRD 0x1844 +#define CLK_CON_DIV_CLKCMU_G3D_BUS 0x1848 +#define CLK_CON_DIV_CLKCMU_MFC_BUS 0x184c +#define CLK_CON_DIV_CLKCMU_MIF_BUSP 0x1850 +#define CLK_CON_DIV_CLKCMU_PERI_BUS 0x1854 +#define CLK_CON_DIV_CLKCMU_PERI_IP 0x1858 +#define CLK_CON_DIV_CLKCMU_PERI_UART 0x185c +#define CLK_CON_DIV_DIV_CLK_CMU_CMUREF 0x1860 +#define CLK_CON_GAT_CLKCMU_MIF_SWITCH 0x2030 +#define CLK_CON_GAT_GATE_CLKCMU_APM_BUS 0x2034 +#define CLK_CON_GAT_GATE_CLKCMU_CORE_BUS 0x2038 +#define CLK_CON_GAT_GATE_CLKCMU_CORE_SSS 0x203c +#define CLK_CON_GAT_GATE_CLKCMU_CPUCL0_BUSP 0x2040 +#define CLK_CON_GAT_GATE_CLKCMU_CPUCL0_CPU 0x2044 +#define CLK_CON_GAT_GATE_CLKCMU_CPUCL0_DBG 0x2048 +#define CLK_CON_GAT_GATE_CLKCMU_DPU_AUDIF 0x204c +#define CLK_CON_GAT_GATE_CLKCMU_DPU_AUD_BUS 0x2050 +#define CLK_CON_GAT_GATE_CLKCMU_DPU_AUD_CPU 0x2054 +#define CLK_CON_GAT_GATE_CLKCMU_DPU_BUS 0x2058 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS_BUS 0x205c +#define CLK_CON_GAT_GATE_CLKCMU_FSYS_MMC_CARD 0x2060 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS_MMC_EMBD 0x2064 +#define CLK_CON_GAT_GATE_CLKCMU_FSYS_USB20DRD 0x2068 +#define CLK_CON_GAT_GATE_CLKCMU_G3D_BUS 0x206c +#define CLK_CON_GAT_GATE_CLKCMU_MFC_BUS 0x2070 +#define CLK_CON_GAT_GATE_CLKCMU_MIF_BUSP 0x2074 +#define CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED0 0x2078 +#define CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED1 0x207c +#define CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED2 0x2080 +#define CLK_CON_GAT_GATE_CLKCMU_PERI_BUS 0x2084 +#define CLK_CON_GAT_GATE_CLKCMU_PERI_IP 0x2088 +#define CLK_CON_GAT_GATE_CLKCMU_PERI_UART 0x208c + +static const unsigned long top_clk_regs[] __initconst = { + PLL_LOCKTIME_PLL_AUD, + PLL_LOCKTIME_PLL_SHARED0, + PLL_LOCKTIME_PLL_SHARED1, + PLL_CON3_PLL_AUD, + PLL_CON8_PLL_AUD, + PLL_CON9_PLL_AUD, + PLL_CON3_PLL_SHARED0, + PLL_CON8_PLL_SHARED0, + PLL_CON9_PLL_SHARED0, + PLL_CON3_PLL_SHARED1, + PLL_CON8_PLL_SHARED1, + PLL_CON9_PLL_SHARED1, + CMU_CMU_TOP_CONTROLLER_OPTION, + CLK_CON_MUX_MUX_CLKCMU_APM_BUS, + CLK_CON_MUX_MUX_CLKCMU_CORE_BUS, + CLK_CON_MUX_MUX_CLKCMU_CORE_SSS, + CLK_CON_MUX_MUX_CLKCMU_CPUCL0_BUSP, + CLK_CON_MUX_MUX_CLKCMU_CPUCL0_CPU, + CLK_CON_MUX_MUX_CLKCMU_CPUCL0_DBG, + CLK_CON_MUX_MUX_CLKCMU_DPU_AUDIF, + CLK_CON_MUX_MUX_CLKCMU_DPU_AUD_BUS, + CLK_CON_MUX_MUX_CLKCMU_DPU_AUD_CPU, + CLK_CON_MUX_MUX_CLKCMU_DPU_BUS, + CLK_CON_MUX_MUX_CLKCMU_FSYS_BUS, + CLK_CON_MUX_MUX_CLKCMU_FSYS_MMC_CARD, + CLK_CON_MUX_MUX_CLKCMU_FSYS_MMC_EMBD, + CLK_CON_MUX_MUX_CLKCMU_FSYS_USB20DRD, + CLK_CON_MUX_MUX_CLKCMU_G3D_BUS, + CLK_CON_MUX_MUX_CLKCMU_MFC_BUS, + CLK_CON_MUX_MUX_CLKCMU_MIF_BUSP, + CLK_CON_MUX_MUX_CLKCMU_MIF_SWITCH, + CLK_CON_MUX_MUX_CLKCMU_MODEM_SHARED1, + CLK_CON_MUX_MUX_CLKCMU_PERI_BUS, + CLK_CON_MUX_MUX_CLKCMU_PERI_IP, + CLK_CON_MUX_MUX_CLKCMU_PERI_UART, + CLK_CON_MUX_MUX_CMU_CMUREF, + CLK_CON_DIV_AP2CP_SHARED0_PLL_CLK, + CLK_CON_DIV_AP2CP_SHARED1_PLL_CLK, + CLK_CON_DIV_AP2CP_SHARED2_PLL_CLK, + CLK_CON_DIV_CLKCMU_APM_BUS, + CLK_CON_DIV_CLKCMU_CMU_BOOST, + CLK_CON_DIV_CLKCMU_CORE_BUS, + CLK_CON_DIV_CLKCMU_CORE_SSS, + CLK_CON_DIV_CLKCMU_CPUCL0_BUSP, + CLK_CON_DIV_CLKCMU_CPUCL0_CPU, + CLK_CON_DIV_CLKCMU_CPUCL0_DBG, + CLK_CON_DIV_CLKCMU_DPU_AUDIF, + CLK_CON_DIV_CLKCMU_DPU_AUD_BUS, + CLK_CON_DIV_CLKCMU_DPU_AUD_CPU, + CLK_CON_DIV_CLKCMU_DPU_BUS, + CLK_CON_DIV_CLKCMU_FSYS_BUS, + CLK_CON_DIV_CLKCMU_FSYS_MMC_CARD, + CLK_CON_DIV_CLKCMU_FSYS_MMC_EMBD, + CLK_CON_DIV_CLKCMU_FSYS_USB20DRD, + CLK_CON_DIV_CLKCMU_G3D_BUS, + CLK_CON_DIV_CLKCMU_MFC_BUS, + CLK_CON_DIV_CLKCMU_MIF_BUSP, + CLK_CON_DIV_CLKCMU_PERI_BUS, + CLK_CON_DIV_CLKCMU_PERI_IP, + CLK_CON_DIV_CLKCMU_PERI_UART, + CLK_CON_DIV_DIV_CLK_CMU_CMUREF, + CLK_CON_GAT_CLKCMU_MIF_SWITCH, + CLK_CON_GAT_GATE_CLKCMU_APM_BUS, + CLK_CON_GAT_GATE_CLKCMU_CORE_BUS, + CLK_CON_GAT_GATE_CLKCMU_CORE_SSS, + CLK_CON_GAT_GATE_CLKCMU_CPUCL0_BUSP, + CLK_CON_GAT_GATE_CLKCMU_CPUCL0_CPU, + CLK_CON_GAT_GATE_CLKCMU_CPUCL0_DBG, + CLK_CON_GAT_GATE_CLKCMU_DPU_AUDIF, + CLK_CON_GAT_GATE_CLKCMU_DPU_AUD_BUS, + CLK_CON_GAT_GATE_CLKCMU_DPU_AUD_CPU, + CLK_CON_GAT_GATE_CLKCMU_DPU_BUS, + CLK_CON_GAT_GATE_CLKCMU_FSYS_BUS, + CLK_CON_GAT_GATE_CLKCMU_FSYS_MMC_CARD, + CLK_CON_GAT_GATE_CLKCMU_FSYS_MMC_EMBD, + CLK_CON_GAT_GATE_CLKCMU_FSYS_USB20DRD, + CLK_CON_GAT_GATE_CLKCMU_G3D_BUS, + CLK_CON_GAT_GATE_CLKCMU_MFC_BUS, + CLK_CON_GAT_GATE_CLKCMU_MIF_BUSP, + CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED0, + CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED1, + CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED2, + CLK_CON_GAT_GATE_CLKCMU_PERI_BUS, + CLK_CON_GAT_GATE_CLKCMU_PERI_IP, + CLK_CON_GAT_GATE_CLKCMU_PERI_UART, +}; + +static const struct samsung_pll_clock top_pll_clks[] __initconst = { + PLL(pll_309, CLK_FOUT_AUD_PLL, "fout_aud_pll", "oscclk", + PLL_LOCKTIME_PLL_AUD, PLL_CON3_PLL_AUD, NULL), + PLL(pll_309, CLK_FOUT_SHARED0_PLL, "fout_shared0_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED0, PLL_CON3_PLL_SHARED0, NULL), + PLL(pll_309, CLK_FOUT_SHARED1_PLL, "fout_shared1_pll", "oscclk", + PLL_LOCKTIME_PLL_SHARED1, PLL_CON3_PLL_SHARED1, NULL), +}; + +/* Parent clock list for CMU_TOP muxes */ +PNAME(mout_cmu_cmuref_p) = { "oscclk", + "dout_cmu_cmuref" }; + +/* Parent clock list for CMU_TOP muxes: for CMU_APM */ +PNAME(mout_cmu_apm_bus_p) = { "dout_shared0_div2", + "dout_shared0_div3" }; + +/* Parent clock list for CMU_TOP muxes: for CMU_CORE */ +PNAME(mout_cmu_core_bus_p) = { "dout_shared0_div2", + "dout_shared1_div3", + "dout_shared0_div3", + "dout_aud_div3" }; + +PNAME(mout_cmu_core_sss_p) = { "dout_shared0_div2", + "dout_shared1_div3", + "dout_shared0_div3", + "dout_aud_div3"}; + +/* Parent clock list for CMU_TOP muxes: for CMU_CPUCL0 */ +PNAME(mout_cmu_cpucl0_busp_p) = { "dout_shared0_div3", + "dout_shared0_div4" }; + +PNAME(mout_cmu_cpucl0_cpu_p) = { "fout_aud_pll", + "dout_shared1_div2", + "dout_shared0_div2", + "dout_shared1_div3", + "dout_aud_div2", + "dout_shared0_div3", + "dout_shared1_div4", + "dout_shared0_div4" }; + +PNAME(mout_cmu_cpucl0_dbg_p) = { "dout_shared0_div3", + "dout_shared0_div4" }; + +/* Parent clock list for CMU_TOP muxes: for CMU_DPU */ +PNAME(mout_cmu_dpu_audif_p) = { "dout_aud_div2", + "dout_aud_div3" }; + +PNAME(mout_cmu_dpu_aud_bus_p) = { "dout_aud_div2", + "dout_shared0_div3", + "dout_aud_div3", + "dout_shared0_div4" }; + +PNAME(mout_cmu_dpu_aud_cpu_p) = { "fout_aud_pll", + "dout_shared1_div2", + "dout_shared0_div2", + "dout_shared1_div3", + "dout_aud_div2", + "dout_shared0_div3", + "dout_aud_div3", + "dout_aud_div4" }; + +PNAME(mout_cmu_dpu_bus_p) = { "dout_shared1_div3", + "dout_shared0_div3", + "dout_shared0_div4" }; + +/* Parent clock list for CMU_TOP muxes: for CMU_FSYS */ +PNAME(mout_cmu_fsys_bus_p) = { "dout_shared0_div2", + "dout_shared1_div3" }; + +PNAME(mout_cmu_fsys_mmc_card_p) = { "oscclk", + "dout_shared0_div2", + "dout_shared1_div3", + "dout_shared0_div3", + "dout_aud_div2" }; + +PNAME(mout_cmu_fsys_mmc_embd_p) = { "oscclk", + "dout_shared0_div2", + "dout_shared1_div3", + "dout_shared0_div3", + "dout_aud_div2" }; + +PNAME(mout_cmu_fsys_usb20drd_p) = { "oscclk", + "dout_shared0_div4" }; + +/* Parent clock list for CMU_TOP muxes: for CMU_G3D */ +PNAME(mout_cmu_g3d_bus_p) = { "dout_shared1_div2", + "dout_shared0_div2", + "dout_shared1_div3", + "dout_shared0_div3" }; + +/* Parent clock list for CMU_TOP muxes: for CMU_MFC */ +PNAME(mout_cmu_mfc_bus_p) = { "dout_shared1_div3", + "dout_shared0_div3", + "dout_shared1_div4", + "dout_shared0_div4" }; + +/* Parent clock list for CMU_TOP muxes: for CMU_MIF */ +PNAME(mout_cmu_mif_busp_p) = { "dout_shared0_div3", + "dout_shared0_div4" }; + +PNAME(mout_cmu_mif_switch_p) = { "fout_shared1_pll", + "fout_shared0_pll", + "dout_shared1_div2", + "dout_shared0_div2", + "dout_shared1_div3", + "dout_shared0_div3", + "dout_shared1_div4", + "dout_shared0_div4" }; + +/* Parent clock list for CMU_TOP muxes: for CMU_MODEM */ +PNAME(mout_cmu_modem_shared1_p) = { "dout_shared1_div2", + "dout_aud_div2", + "dout_shared1_div3", + "dout_shared0_div3" }; + +/* Parent clock list for CMU_TOP muxes: for CMU_PERI */ +PNAME(mout_cmu_peri_bus_p) = { "dout_shared0_div3", + "dout_shared0_div4" }; + +PNAME(mout_cmu_peri_ip_p) = { "oscclk", + "dout_shared0_div4", + "dout_shared1_div4", + "dout_aud_div3" }; + +PNAME(mout_cmu_peri_uart_p) = { "oscclk", + "dout_shared0_div4", + "dout_shared1_div4", + "dout_aud_div3" }; + +static const struct samsung_mux_clock top_mux_clks[] __initconst = { + /* APM (Active Power Management) */ + MUX(CLK_MOUT_CMU_APM_BUS, "mout_cmu_apm_bus", + mout_cmu_apm_bus_p, + CLK_CON_MUX_MUX_CLKCMU_APM_BUS, + 0, 1), + + /* CMU (Clock Management Unit) */ + MUX(CLK_MOUT_CMU_CMUREF, "mout_cmu_cmuref", + mout_cmu_cmuref_p, + CLK_CON_MUX_MUX_CMU_CMUREF, + 0, 1), + + /* CORE */ + MUX(CLK_MOUT_CMU_CORE_BUS, "mout_cmu_core_bus", + mout_cmu_core_bus_p, + CLK_CON_MUX_MUX_CLKCMU_CORE_BUS, + 0, 2), + MUX(CLK_MOUT_CMU_CORE_SSS, "mout_cmu_core_sss", + mout_cmu_core_sss_p, + CLK_CON_MUX_MUX_CLKCMU_CORE_SSS, + 0, 2), + + /* CPUCL0 (CPU Cluster 0) */ + MUX(CLK_MOUT_CMU_CPUCL0_BUSP, "mout_cmu_cpucl0_busp", + mout_cmu_cpucl0_busp_p, + CLK_CON_MUX_MUX_CLKCMU_CPUCL0_BUSP, + 0, 1), + MUX(CLK_MOUT_CMU_CPUCL0_CPU, "mout_cmu_cpucl0_cpu", + mout_cmu_cpucl0_cpu_p, + CLK_CON_MUX_MUX_CLKCMU_CPUCL0_CPU, + 0, 3), + MUX(CLK_MOUT_CMU_CPUCL0_DBG, "mout_cmu_cpucl0_dbg", + mout_cmu_cpucl0_dbg_p, + CLK_CON_MUX_MUX_CLKCMU_CPUCL0_DBG, + 0, 1), + + /* DPU (Display Processing Unit) */ + MUX(CLK_MOUT_CMU_DPU_AUDIF, "mout_cmu_dpu_audif", + mout_cmu_dpu_audif_p, + CLK_CON_MUX_MUX_CLKCMU_DPU_AUDIF, + 0, 1), + MUX(CLK_MOUT_CMU_DPU_AUD_BUS, "mout_cmu_dpu_aud_bus", + mout_cmu_dpu_aud_bus_p, + CLK_CON_MUX_MUX_CLKCMU_DPU_AUD_BUS, + 0, 2), + MUX(CLK_MOUT_CMU_DPU_AUD_CPU, "mout_cmu_dpu_aud_cpu", + mout_cmu_dpu_aud_cpu_p, + CLK_CON_MUX_MUX_CLKCMU_DPU_AUD_CPU, + 0, 3), + MUX(CLK_MOUT_CMU_DPU_BUS, "mout_cmu_dpu_bus", + mout_cmu_dpu_bus_p, + CLK_CON_MUX_MUX_CLKCMU_DPU_BUS, + 0, 2), + + /* FSYS */ + MUX(CLK_MOUT_CMU_FSYS_BUS, "mout_cmu_fsys_bus", + mout_cmu_fsys_bus_p, + CLK_CON_MUX_MUX_CLKCMU_FSYS_BUS, + 0, 1), + MUX(CLK_MOUT_CMU_FSYS_MMC_CARD, "mout_cmu_fsys_mmc_card", + mout_cmu_fsys_mmc_card_p, + CLK_CON_MUX_MUX_CLKCMU_FSYS_MMC_CARD, + 0, 3), + MUX(CLK_MOUT_CMU_FSYS_MMC_EMBD, "mout_cmu_fsys_mmc_embd", + mout_cmu_fsys_mmc_embd_p, + CLK_CON_MUX_MUX_CLKCMU_FSYS_MMC_EMBD, + 0, 3), + MUX(CLK_MOUT_CMU_FSYS_USB20DRD, "mout_cmu_fsys_usb20drd", + mout_cmu_fsys_usb20drd_p, + CLK_CON_MUX_MUX_CLKCMU_FSYS_USB20DRD, + 0, 1), + + /* G3D */ + MUX(CLK_MOUT_CMU_G3D_BUS, "mout_cmu_g3d_bus", + mout_cmu_g3d_bus_p, + CLK_CON_MUX_MUX_CLKCMU_G3D_BUS, + 0, 2), + + /* MFC */ + MUX(CLK_MOUT_CMU_MFC_BUS, "mout_cmu_mfc_bus", + mout_cmu_mfc_bus_p, + CLK_CON_MUX_MUX_CLKCMU_MFC_BUS, + 0, 2), + + /* MIF */ + MUX(CLK_MOUT_CMU_MIF_BUSP, "mout_cmu_mif_busp", + mout_cmu_mif_busp_p, + CLK_CON_MUX_MUX_CLKCMU_MIF_BUSP, + 0, 1), + MUX(CLK_MOUT_CMU_MIF_SWITCH, "mout_cmu_mif_switch", + mout_cmu_mif_switch_p, + CLK_CON_MUX_MUX_CLKCMU_MIF_SWITCH, + 0, 3), + + /* MODEM */ + MUX(CLK_MOUT_CMU_MODEM_SHARED1, "mout_cmu_modem_shared1", + mout_cmu_modem_shared1_p, + CLK_CON_MUX_MUX_CLKCMU_MODEM_SHARED1, + 0, 2), + + /* PERI */ + MUX(CLK_MOUT_CMU_PERI_BUS, "mout_cmu_peri_bus", + mout_cmu_peri_bus_p, + CLK_CON_MUX_MUX_CLKCMU_PERI_BUS, + 0, 1), + MUX(CLK_MOUT_CMU_PERI_IP, "mout_cmu_peri_ip", + mout_cmu_peri_ip_p, + CLK_CON_MUX_MUX_CLKCMU_PERI_IP, + 0, 2), + MUX(CLK_MOUT_CMU_PERI_UART, "mout_cmu_peri_uart", + mout_cmu_peri_uart_p, + CLK_CON_MUX_MUX_CLKCMU_PERI_UART, + 0, 2), +}; + +static const struct samsung_div_clock top_div_clks[] __initconst = { + /* APM */ + DIV(CLK_DOUT_CMU_APM_BUS, "dout_cmu_apm_bus", + "gout_cmu_apm_bus", + CLK_CON_DIV_CLKCMU_APM_BUS, + 0, 3), + + /* CMU */ + DIV(CLK_DOUT_CMU_CMU_BOOST, "dout_cmu_cmu_boost", + "fout_shared0_pll", + CLK_CON_DIV_CLKCMU_CMU_BOOST, + 0, 3), + DIV(CLK_DOUT_CMU_CMUREF, "dout_cmu_cmuref", + "fout_shared0_pll", + CLK_CON_DIV_DIV_CLK_CMU_CMUREF, + 0, 2), + + /* CORE */ + DIV(CLK_DOUT_CMU_CORE_BUS, "dout_cmu_core_bus", + "gout_cmu_core_bus", + CLK_CON_DIV_CLKCMU_CORE_BUS, + 0, 4), + DIV(CLK_DOUT_CMU_CORE_SSS, "dout_cmu_core_sss", + "gout_cmu_core_sss", + CLK_CON_DIV_CLKCMU_CORE_SSS, + 0, 4), + + /* CPUCL0 */ + DIV(CLK_DOUT_CMU_CPUCL0_BUSP, "dout_cmu_cpucl0_busp", + "gout_cmu_cpucl0_busp", + CLK_CON_DIV_CLKCMU_CPUCL0_BUSP, + 0, 3), + DIV(CLK_DOUT_CMU_CPUCL0_CPU, "dout_cmu_cpucl0_cpu", + "gout_cmu_cpucl0_cpu", + CLK_CON_DIV_CLKCMU_CPUCL0_CPU, + 0, 3), + DIV(CLK_DOUT_CMU_CPUCL0_DBG, "dout_cmu_cpucl0_dbg", + "gout_cmu_cpucl0_dbg", + CLK_CON_DIV_CLKCMU_CPUCL0_DBG, + 0, 3), + + /* DPU */ + DIV(CLK_DOUT_CMU_DPU_AUDIF, "dout_cmu_dpu_audif", + "gout_cmu_dpu_audif", + CLK_CON_DIV_CLKCMU_DPU_AUDIF, + 0, 9), + DIV(CLK_DOUT_CMU_DPU_AUD_BUS, "dout_cmu_dpu_aud_bus", + "gout_cmu_dpu_aud_bus", + CLK_CON_DIV_CLKCMU_DPU_AUD_BUS, + 0, 3), + DIV(CLK_DOUT_CMU_DPU_AUD_CPU, "dout_cmu_dpu_aud_cpu", + "gout_cmu_dpu_aud_cpu", + CLK_CON_DIV_CLKCMU_DPU_AUD_CPU, + 0, 3), + DIV(CLK_DOUT_CMU_DPU_BUS, "dout_cmu_dpu_bus", + "gout_cmu_dpu_bus", + CLK_CON_DIV_CLKCMU_DPU_BUS, + 0, 3), + + /* FSYS */ + DIV(CLK_DOUT_CMU_FSYS_BUS, "dout_cmu_fsys_bus", + "gout_cmu_fsys_bus", + CLK_CON_DIV_CLKCMU_FSYS_BUS, + 0, 4), + DIV(CLK_DOUT_CMU_FSYS_MMC_CARD, "dout_cmu_fsys_mmc_card", + "gout_cmu_fsys_mmc_card", + CLK_CON_DIV_CLKCMU_FSYS_MMC_CARD, + 0, 9), + DIV(CLK_DOUT_CMU_FSYS_MMC_EMBD, "dout_cmu_fsys_mmc_embd", + "gout_cmu_fsys_mmc_embd", + CLK_CON_DIV_CLKCMU_FSYS_MMC_EMBD, + 0, 9), + DIV(CLK_DOUT_CMU_FSYS_USB20DRD, "dout_cmu_fsys_usb20drd", + "gout_cmu_fsys_usb20drd", + CLK_CON_DIV_CLKCMU_FSYS_USB20DRD, + 0, 4), + + /* G3D */ + DIV(CLK_DOUT_CMU_G3D_BUS, "dout_cmu_g3d_bus", + "gout_cmu_g3d_bus", + CLK_CON_DIV_CLKCMU_G3D_BUS, + 0, 3), + + /* MFC */ + DIV(CLK_DOUT_CMU_MFC_BUS, "dout_cmu_mfc_bus", + "gout_cmu_mfc_bus", + CLK_CON_DIV_CLKCMU_MFC_BUS, + 0, 4), + + /* MIF */ + DIV(CLK_DOUT_CMU_MIF_BUSP, "dout_cmu_mif_busp", + "gout_cmu_mif_busp", + CLK_CON_DIV_CLKCMU_MIF_BUSP, + 0, 3), + + /* PERI */ + DIV(CLK_DOUT_CMU_PERI_BUS, "dout_cmu_peri_bus", + "gout_cmu_peri_bus", + CLK_CON_DIV_CLKCMU_PERI_BUS, + 0, 3), + DIV(CLK_DOUT_CMU_PERI_IP, "dout_cmu_peri_ip", + "gout_cmu_peri_ip", + CLK_CON_DIV_CLKCMU_PERI_IP, + 0, 4), + DIV(CLK_DOUT_CMU_PERI_UART, "dout_cmu_peri_uart", + "gout_cmu_peri_uart", + CLK_CON_DIV_CLKCMU_PERI_UART, + 0, 4), + + /* SHARED */ + DIV(CLK_DOUT_AP2CP_SHARED0_PLL, "dout_ap2cp_shared0_pll", + "gout_cmu_modem_shared0", + CLK_CON_DIV_AP2CP_SHARED0_PLL_CLK, + 0, 3), + DIV(CLK_DOUT_AP2CP_SHARED1_PLL, "dout_ap2cp_shared1_pll", + "gout_cmu_modem_shared1", + CLK_CON_DIV_AP2CP_SHARED1_PLL_CLK, + 0, 3), + DIV(CLK_DOUT_AP2CP_SHARED2_PLL, "dout_ap2cp_shared2_pll", + "gout_cmu_modem_shared2", + CLK_CON_DIV_AP2CP_SHARED2_PLL_CLK, + 0, 3), +}; + +static const struct samsung_fixed_factor_clock top_fixed_factor_clks[] __initconst = { + FFACTOR(CLK_DOUT_SHARED0_DIV2, "dout_shared0_div2", "fout_shared0_pll", + 1, 2, 0), + FFACTOR(CLK_DOUT_SHARED0_DIV3, "dout_shared0_div3", "fout_shared0_pll", + 1, 3, 0), + FFACTOR(CLK_DOUT_SHARED0_DIV4, "dout_shared0_div4", "fout_shared0_pll", + 1, 4, 0), + FFACTOR(CLK_DOUT_SHARED1_DIV2, "dout_shared1_div2", "fout_shared1_pll", + 1, 2, 0), + FFACTOR(CLK_DOUT_SHARED1_DIV3, "dout_shared1_div3", "fout_shared1_pll", + 1, 3, 0), + FFACTOR(CLK_DOUT_SHARED1_DIV4, "dout_shared1_div4", "fout_shared1_pll", + 1, 4, 0), + FFACTOR(CLK_DOUT_AUD_DIV2, "dout_aud_div2", "fout_aud_pll", + 1, 2, 0), + FFACTOR(CLK_DOUT_AUD_DIV3, "dout_aud_div3", "fout_aud_pll", + 1, 3, 0), + FFACTOR(CLK_DOUT_AUD_DIV4, "dout_aud_div4", "fout_aud_pll", + 1, 4, 0), +}; + +static const struct samsung_gate_clock top_gate_clks[] __initconst = { + /* APM */ + GATE(CLK_GOUT_CMU_APM_BUS, "gout_cmu_apm_bus", + "mout_cmu_apm_bus", + CLK_CON_GAT_GATE_CLKCMU_APM_BUS, + 21, 0, 0), + + /* CORE */ + GATE(CLK_GOUT_CMU_CORE_BUS, "gout_cmu_core_bus", + "mout_cmu_core_bus", + CLK_CON_GAT_GATE_CLKCMU_CORE_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_CORE_SSS, "gout_cmu_core_sss", + "mout_cmu_core_sss", + CLK_CON_GAT_GATE_CLKCMU_CORE_SSS, + 21, 0, 0), + + /* CPUCL0 */ + GATE(CLK_GOUT_CMU_CPUCL0_BUSP, "gout_cmu_cpucl0_busp", + "mout_cmu_cpucl0_busp", + CLK_CON_GAT_GATE_CLKCMU_CPUCL0_BUSP, + 21, 0, 0), + GATE(CLK_GOUT_CMU_CPUCL0_CPU, "gout_cmu_cpucl0_cpu", + "mout_cmu_cpucl0_cpu", + CLK_CON_GAT_GATE_CLKCMU_CPUCL0_CPU, + 21, 0, 0), + GATE(CLK_GOUT_CMU_CPUCL0_DBG, "gout_cmu_cpucl0_dbg", + "mout_cmu_cpucl0_dbg", + CLK_CON_GAT_GATE_CLKCMU_CPUCL0_DBG, + 21, 0, 0), + + /* DPU */ + GATE(CLK_GOUT_CMU_DPU_AUDIF, "gout_cmu_dpu_audif", + "mout_cmu_dpu_audif", + CLK_CON_GAT_GATE_CLKCMU_DPU_AUDIF, + 21, 0, 0), + GATE(CLK_GOUT_CMU_DPU_AUD_BUS, "gout_cmu_dpu_aud_bus", + "mout_cmu_dpu_aud_bus", + CLK_CON_GAT_GATE_CLKCMU_DPU_AUD_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_DPU_AUD_CPU, "gout_cmu_dpu_aud_cpu", + "mout_cmu_dpu_aud_cpu", + CLK_CON_GAT_GATE_CLKCMU_DPU_AUD_CPU, + 21, 0, 0), + GATE(CLK_GOUT_CMU_DPU_BUS, "gout_cmu_dpu_bus", + "mout_cmu_dpu_bus", + CLK_CON_GAT_GATE_CLKCMU_DPU_BUS, + 21, 0, 0), + + /* FSYS */ + GATE(CLK_GOUT_CMU_FSYS_BUS, "gout_cmu_fsys_bus", + "mout_cmu_fsys_bus", + CLK_CON_GAT_GATE_CLKCMU_FSYS_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS_MMC_CARD, "gout_cmu_fsys_mmc_card", + "mout_cmu_fsys_mmc_card", + CLK_CON_GAT_GATE_CLKCMU_FSYS_MMC_CARD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS_MMC_EMBD, "gout_cmu_fsys_mmc_embd", + "mout_cmu_fsys_mmc_embd", + CLK_CON_GAT_GATE_CLKCMU_FSYS_MMC_EMBD, + 21, 0, 0), + GATE(CLK_GOUT_CMU_FSYS_USB20DRD, "gout_cmu_fsys_usb20drd", + "mout_cmu_fsys_usb20drd", + CLK_CON_GAT_GATE_CLKCMU_FSYS_USB20DRD, + 21, 0, 0), + + /* G3D */ + GATE(CLK_GOUT_CMU_G3D_BUS, "gout_cmu_g3d_bus", + "mout_cmu_g3d_bus", + CLK_CON_GAT_GATE_CLKCMU_G3D_BUS, + 21, 0, 0), + + /* MFC */ + GATE(CLK_GOUT_CMU_MFC_BUS, "gout_cmu_mfc_bus", + "mout_cmu_mfc_bus", + CLK_CON_GAT_GATE_CLKCMU_MFC_BUS, + 21, 0, 0), + + /* MIF */ + GATE(CLK_GOUT_CMU_MIF_SWITCH, "gout_cmu_mif_switch", + "mout_cmu_mif_switch", + CLK_CON_GAT_CLKCMU_MIF_SWITCH, + 21, 0, 0), + GATE(CLK_GOUT_CMU_MIF_BUSP, "gout_cmu_mif_busp", + "mout_cmu_mif_busp", + CLK_CON_GAT_GATE_CLKCMU_MIF_BUSP, + 21, 0, 0), + + /* MODEM */ + GATE(CLK_GOUT_CMU_MODEM_SHARED0, "gout_cmu_modem_shared0", + "fout_shared0_pll", + CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED0, + 21, 0, 0), + GATE(CLK_GOUT_CMU_MODEM_SHARED1, "gout_cmu_modem_shared1", + "mout_cmu_modem_shared1", + CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED1, + 21, 0, 0), + GATE(CLK_GOUT_CMU_MODEM_SHARED2, "gout_cmu_modem_shared2", + "fout_shared0_pll", + CLK_CON_GAT_GATE_CLKCMU_MODEM_SHARED2, + 21, 0, 0), + + /* PERI */ + GATE(CLK_GOUT_CMU_PERI_BUS, "gout_cmu_peri_bus", + "mout_cmu_peri_bus", + CLK_CON_GAT_GATE_CLKCMU_PERI_BUS, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERI_IP, "gout_cmu_peri_ip", + "mout_cmu_peri_ip", + CLK_CON_GAT_GATE_CLKCMU_PERI_IP, + 21, 0, 0), + GATE(CLK_GOUT_CMU_PERI_UART, "gout_cmu_peri_uart", + "mout_cmu_peri_uart", + CLK_CON_GAT_GATE_CLKCMU_PERI_UART, + 21, 0, 0), +}; + +static const unsigned long drcg_sysreg[] __initconst = { + EXYNOS5515_DRCG_EN_OFFSET, +}; + +static const struct samsung_cmu_info top_cmu_info __initconst = { + .pll_clks = top_pll_clks, + .nr_pll_clks = ARRAY_SIZE(top_pll_clks), + .mux_clks = top_mux_clks, + .nr_mux_clks = ARRAY_SIZE(top_mux_clks), + .div_clks = top_div_clks, + .nr_div_clks = ARRAY_SIZE(top_div_clks), + .fixed_factor_clks = top_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(top_fixed_factor_clks), + .gate_clks = top_gate_clks, + .nr_gate_clks = ARRAY_SIZE(top_gate_clks), + .nr_clk_ids = CLKS_NR_TOP, + .clk_regs = top_clk_regs, + .nr_clk_regs = ARRAY_SIZE(top_clk_regs), + .sysreg_clk_regs = drcg_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(drcg_sysreg), + .auto_clock_gate = true, + .gate_dbg_offset = EXYNOS5515_GATE_DBG_OFFSET, + .option_offset = CMU_CMU_TOP_CONTROLLER_OPTION, + .drcg_offset = EXYNOS5515_DRCG_EN_OFFSET, +}; + +static void __init exynos5515_cmu_top_init(struct device_node *np) +{ + exynos_arm64_register_cmu(NULL, np, &top_cmu_info); +} + +/* Register CMU_TOP early, as it's a dependency for other early domains */ +CLK_OF_DECLARE(exynos5515_cmu_top, "samsung,exynos5515-cmu-top", + exynos5515_cmu_top_init); + +/* ---- CMU_PERI ------------------------------------------------------------ */ + +/* + * CMU_PERI: 0x10030000 + * SYSREG_PERI: 0x10020000 + */ + +#define PLL_CON0_MUX_CLKCMU_PERI_BUS_USER 0x0600 +#define PLL_CON1_MUX_CLKCMU_PERI_BUS_USER 0x0604 +#define PLL_CON0_MUX_CLKCMU_PERI_IP_USER 0x0610 +#define PLL_CON1_MUX_CLKCMU_PERI_IP_USER 0x0614 +#define PLL_CON0_MUX_CLKCMU_PERI_UART_USER 0x0620 +#define PLL_CON1_MUX_CLKCMU_PERI_UART_USER 0x0624 +#define PERI_CMU_PERI_CONTROLLER_OPTION 0x0800 +#define CLK_CON_MUX_MUX_CLK_PERI_SPI 0x1000 +#define CLK_CON_MUX_MUX_CLK_PERI_USI00_USI 0x1004 +#define CLK_CON_DIV_CLKCMU_OTP 0x1800 +#define CLK_CON_DIV_DIV_CLK_PERI_I2C_0 0x1804 +#define CLK_CON_DIV_DIV_CLK_PERI_I2C_1 0x1808 +#define CLK_CON_DIV_DIV_CLK_PERI_I2C_2 0x180c +#define CLK_CON_DIV_DIV_CLK_PERI_I2C_3 0x1810 +#define CLK_CON_DIV_DIV_CLK_PERI_SPI 0x1814 +#define CLK_CON_DIV_DIV_CLK_PERI_USI00_I2C 0x1818 +#define CLK_CON_DIV_DIV_CLK_PERI_USI00_USI 0x181c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_BUSIF_TMU_IPCLKPORT_PCLK 0x2000 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_D_TZPC_PERI_IPCLKPORT_PCLK 0x2004 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_GPIO_PERI_IPCLKPORT_PCLK 0x2008 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_0_IPCLKPORT_IPCLK 0x200c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_0_IPCLKPORT_PCLK 0x2010 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_1_IPCLKPORT_IPCLK 0x2014 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_1_IPCLKPORT_PCLK 0x2018 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_2_IPCLKPORT_IPCLK 0x201c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_2_IPCLKPORT_PCLK 0x2020 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_3_IPCLKPORT_IPCLK 0x2024 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_3_IPCLKPORT_PCLK 0x2028 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_MCT_IPCLKPORT_PCLK 0x202c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_OTP_CON_TOP_IPCLKPORT_I_OSCCLK 0x2030 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_OTP_CON_TOP_IPCLKPORT_PCLK 0x2034 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_PERI_CMU_PERI_IPCLKPORT_PCLK 0x2038 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_PWM_MOTOR_IPCLKPORT_I_PCLK_S0 0x203c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_BUS_IPCLKPORT_CLK 0x2040 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_0_IPCLKPORT_CLK 0x2044 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_1_IPCLKPORT_CLK 0x2048 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_2_IPCLKPORT_CLK 0x204c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_3_IPCLKPORT_CLK 0x2050 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_OSCCLK_IPCLKPORT_CLK 0x2054 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_SPI_IPCLKPORT_CLK 0x2058 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_UART_IPCLKPORT_CLK 0x205c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_USI00_I2C_IPCLKPORT_CLK 0x2060 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_USI00_USI_IPCLKPORT_CLK 0x2064 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_SLH_AXI_MI_P_PERI_IPCLKPORT_I_CLK 0x2068 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_SYSREG_PERI_IPCLKPORT_PCLK 0x206c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_I2C_IPCLKPORT_IPCLK 0x2070 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_I2C_IPCLKPORT_PCLK 0x2074 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_USI_IPCLKPORT_IPCLK 0x2078 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_USI_IPCLKPORT_PCLK 0x207c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_USI_SPI_IPCLKPORT_IPCLK 0x2080 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_USI_SPI_IPCLKPORT_PCLK 0x2084 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_USI_UART_IPCLKPORT_IPCLK 0x2088 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_USI_UART_IPCLKPORT_PCLK 0x208c +#define CLK_CON_GAT_CLK_BLK_PERI_UID_WDT0_IPCLKPORT_PCLK 0x2090 +#define CLK_CON_GAT_CLK_BLK_PERI_UID_WDT1_IPCLKPORT_PCLK 0x2094 +#define CLK_CON_GAT_GATE_CLK_PERI_I2C_0 0x2098 +#define CLK_CON_GAT_GATE_CLK_PERI_I2C_1 0x209c +#define CLK_CON_GAT_GATE_CLK_PERI_I2C_2 0x20a0 +#define CLK_CON_GAT_GATE_CLK_PERI_I2C_3 0x20a4 +#define CLK_CON_GAT_GATE_CLK_PERI_USI00_I2C 0x20a8 + +static const unsigned long peri_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_PERI_BUS_USER, + PLL_CON1_MUX_CLKCMU_PERI_BUS_USER, + PLL_CON0_MUX_CLKCMU_PERI_IP_USER, + PLL_CON1_MUX_CLKCMU_PERI_IP_USER, + PLL_CON0_MUX_CLKCMU_PERI_UART_USER, + PLL_CON1_MUX_CLKCMU_PERI_UART_USER, + PERI_CMU_PERI_CONTROLLER_OPTION, + CLK_CON_MUX_MUX_CLK_PERI_SPI, + CLK_CON_MUX_MUX_CLK_PERI_USI00_USI, + CLK_CON_DIV_CLKCMU_OTP, + CLK_CON_DIV_DIV_CLK_PERI_I2C_0, + CLK_CON_DIV_DIV_CLK_PERI_I2C_1, + CLK_CON_DIV_DIV_CLK_PERI_I2C_2, + CLK_CON_DIV_DIV_CLK_PERI_I2C_3, + CLK_CON_DIV_DIV_CLK_PERI_SPI, + CLK_CON_DIV_DIV_CLK_PERI_USI00_I2C, + CLK_CON_DIV_DIV_CLK_PERI_USI00_USI, + CLK_CON_GAT_CLK_BLK_PERI_UID_BUSIF_TMU_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_D_TZPC_PERI_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_GPIO_PERI_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_0_IPCLKPORT_IPCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_0_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_1_IPCLKPORT_IPCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_1_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_2_IPCLKPORT_IPCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_2_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_3_IPCLKPORT_IPCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_3_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_MCT_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_OTP_CON_TOP_IPCLKPORT_I_OSCCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_OTP_CON_TOP_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_PERI_CMU_PERI_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_PWM_MOTOR_IPCLKPORT_I_PCLK_S0, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_BUS_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_0_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_1_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_2_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_3_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_OSCCLK_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_SPI_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_UART_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_USI00_I2C_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_USI00_USI_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_SLH_AXI_MI_P_PERI_IPCLKPORT_I_CLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_SYSREG_PERI_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_I2C_IPCLKPORT_IPCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_I2C_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_USI_IPCLKPORT_IPCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_USI_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_USI_SPI_IPCLKPORT_IPCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_USI_SPI_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_USI_UART_IPCLKPORT_IPCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_USI_UART_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_WDT0_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_PERI_UID_WDT1_IPCLKPORT_PCLK, + CLK_CON_GAT_GATE_CLK_PERI_I2C_0, + CLK_CON_GAT_GATE_CLK_PERI_I2C_1, + CLK_CON_GAT_GATE_CLK_PERI_I2C_2, + CLK_CON_GAT_GATE_CLK_PERI_I2C_3, + CLK_CON_GAT_GATE_CLK_PERI_USI00_I2C, +}; + +/* Parent clock list for CMU_PERI muxes */ +PNAME(mout_pll_peri_bus_user_p) = { "oscclk", + "mout_cmu_peri_bus" }; + +PNAME(mout_pll_peri_ip_user_p) = { "oscclk", + "mout_cmu_peri_ip" }; + +/* Parent clock list for CMU_PERI muxes: for SPI */ +PNAME(mout_peri_spi_p) = { "oscclk", + "mout_pll_peri_ip_user" }; + +/* Parent clock list for CMU_PERI muxes: for UART */ +PNAME(mout_pll_peri_uart_user_p) = { "oscclk", + "mout_cmu_peri_uart" }; + +/* Parent clock list for CMU_PERI muxes: for USI */ +PNAME(mout_peri_usi00_usi_p) = { "oscclk", + "mout_pll_peri_ip_user" }; + +static const struct samsung_mux_clock peri_mux_clks[] __initconst = { + /* BUS */ + MUX(CLK_MOUT_PLL_PERI_BUS_USER, "mout_pll_peri_bus_user", + mout_pll_peri_bus_user_p, + PLL_CON0_MUX_CLKCMU_PERI_BUS_USER, + 4, 1), + + /* IP */ + MUX(CLK_MOUT_PLL_PERI_IP_USER, "mout_pll_peri_ip_user", + mout_pll_peri_ip_user_p, + PLL_CON0_MUX_CLKCMU_PERI_IP_USER, + 4, 1), + + /* SPI */ + MUX(CLK_MOUT_PERI_SPI, "mout_peri_spi", + mout_peri_spi_p, + CLK_CON_MUX_MUX_CLK_PERI_SPI, + 0, 1), + + /* UART */ + MUX(CLK_MOUT_PLL_PERI_UART_USER, "mout_pll_peri_uart_user", + mout_pll_peri_uart_user_p, + PLL_CON0_MUX_CLKCMU_PERI_UART_USER, + 4, 1), + + /* USI (Universal Serial Interface) */ + MUX(CLK_MOUT_PERI_USI00_USI, "mout_peri_usi00_usi", + mout_peri_usi00_usi_p, + CLK_CON_MUX_MUX_CLK_PERI_USI00_USI, + 0, 1), +}; + +static const struct samsung_div_clock peri_div_clks[] __initconst = { + /* I2C */ + DIV(CLK_DOUT_PERI_I2C_0, "dout_peri_i2c_0", + "gout_peri_i2c_0", + CLK_CON_DIV_DIV_CLK_PERI_I2C_0, + 0, 4), + DIV(CLK_DOUT_PERI_I2C_1, "dout_peri_i2c_1", + "gout_peri_i2c_1", + CLK_CON_DIV_DIV_CLK_PERI_I2C_1, + 0, 4), + DIV(CLK_DOUT_PERI_I2C_2, "dout_peri_i2c_2", + "gout_peri_i2c_2", + CLK_CON_DIV_DIV_CLK_PERI_I2C_2, + 0, 4), + DIV(CLK_DOUT_PERI_I2C_3, "dout_peri_i2c_3", + "gout_peri_i2c_3", + CLK_CON_DIV_DIV_CLK_PERI_I2C_3, + 0, 4), + + /* SPI */ + DIV(CLK_DOUT_PERI_SPI, "dout_peri_spi", + "mout_peri_spi", + CLK_CON_DIV_DIV_CLK_PERI_SPI, + 0, 5), + + /* USI */ + DIV(CLK_DOUT_PERI_USI00_I2C, "dout_peri_usi00_i2c", + "gout_peri_usi00_i2c", + CLK_CON_DIV_DIV_CLK_PERI_USI00_I2C, + 0, 4), + DIV(CLK_DOUT_PERI_USI00_USI, "dout_peri_usi00_usi", + "mout_peri_usi00_usi", + CLK_CON_DIV_DIV_CLK_PERI_USI00_USI, + 0, 5), +}; + +static const struct samsung_fixed_factor_clock peri_fixed_factor_clks[] __initconst = { + /* OTP (One-Time Programmable eFuses) */ + FFACTOR(CLK_DOUT_PERI_OTP, "dout_peri_otp", "oscclk", + 1, 8, 0), +}; + +static const struct samsung_gate_clock peri_gate_clks[] __initconst = { + /* BUS */ + GATE(CLK_GOUT_PERI_BUSIF_TMU_PCLK, "gout_peri_busif_tmu_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_BUSIF_TMU_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_BUS_CLK, "gout_peri_bus_clk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_BUS_IPCLKPORT_CLK, + 21, 0, 0), + + /* CMU */ + GATE(CLK_GOUT_PERI_CMU_PCLK, "gout_peri_cmu_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_PERI_CMU_PERI_IPCLKPORT_PCLK, + 21, 0, 0), + + /* GPIO */ + GATE(CLK_GOUT_PERI_GPIO_PCLK, "gout_peri_gpio_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_GPIO_PERI_IPCLKPORT_PCLK, + 21, 0, 0), + + /* I2C */ + GATE(CLK_GOUT_PERI_I2C_0_IPCLK, "gout_peri_i2c_0_ipclk", + "dout_peri_i2c_0", + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_0_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_0_PCLK, "gout_peri_i2c_0_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_0_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_1_IPCLK, "gout_peri_i2c_1_ipclk", + "dout_peri_i2c_1", + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_1_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_1_PCLK, "gout_peri_i2c_1_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_1_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_2_IPCLK, "gout_peri_i2c_2_ipclk", + "dout_peri_i2c_2", + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_2_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_2_PCLK, "gout_peri_i2c_2_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_2_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_3_IPCLK, "gout_peri_i2c_3_ipclk", + "dout_peri_i2c_3", + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_3_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_3_PCLK, "gout_peri_i2c_3_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_I2C_3_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_0_CLK, "gout_peri_i2c_0_clk", + "dout_peri_i2c_0", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_0_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_1_CLK, "gout_peri_i2c_1_clk", + "dout_peri_i2c_1", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_1_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_2_CLK, "gout_peri_i2c_2_clk", + "dout_peri_i2c_2", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_2_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_3_CLK, "gout_peri_i2c_3_clk", + "dout_peri_i2c_3", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_I2C_3_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_0, "gout_peri_i2c_0", + "mout_pll_peri_ip_user", + CLK_CON_GAT_GATE_CLK_PERI_I2C_0, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_1, "gout_peri_i2c_1", + "mout_pll_peri_ip_user", + CLK_CON_GAT_GATE_CLK_PERI_I2C_1, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_2, "gout_peri_i2c_2", + "mout_pll_peri_ip_user", + CLK_CON_GAT_GATE_CLK_PERI_I2C_2, + 21, 0, 0), + GATE(CLK_GOUT_PERI_I2C_3, "gout_peri_i2c_3", + "mout_pll_peri_ip_user", + CLK_CON_GAT_GATE_CLK_PERI_I2C_3, + 21, 0, 0), + + /* MCT (Multi-Core Timer) */ + GATE(CLK_GOUT_PERI_MCT_PCLK, "gout_peri_mct_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_MCT_IPCLKPORT_PCLK, + 21, 0, 0), + + /* OTP */ + GATE(CLK_GOUT_PERI_OTP_OSCCLK, "gout_peri_otp_oscclk", + "oscclk", + CLK_CON_GAT_CLK_BLK_PERI_UID_OTP_CON_TOP_IPCLKPORT_I_OSCCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_OTP_PCLK, "gout_peri_otp_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_OTP_CON_TOP_IPCLKPORT_PCLK, + 21, 0, 0), + + /* OSCCLK */ + GATE(CLK_GOUT_PERI_OSCCLK, "gout_peri_oscclk", + "oscclk", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_OSCCLK_IPCLKPORT_CLK, + 21, 0, 0), + + /* PWM */ + GATE(CLK_GOUT_PERI_PWM_MOTOR_PCLK, "gout_peri_pwm_motor_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_PWM_MOTOR_IPCLKPORT_I_PCLK_S0, + 21, 0, 0), + + /* SPI */ + GATE(CLK_GOUT_PERI_SPI_CLK, "gout_peri_spi_clk", + "dout_peri_spi", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_SPI_IPCLKPORT_CLK, + 21, 0, 0), + + /* SYSREG */ + GATE(CLK_GOUT_PERI_SYSREG_PCLK, "gout_peri_sysreg_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_SYSREG_PERI_IPCLKPORT_PCLK, + 21, 0, 0), + + /* TZ */ + GATE(CLK_GOUT_PERI_D_TZPC_PCLK, "gout_peri_d_tzpc_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_D_TZPC_PERI_IPCLKPORT_PCLK, + 21, 0, 0), + + /* UART */ + GATE(CLK_GOUT_PERI_UART_CLK, "gout_peri_uart_clk", + "mout_pll_peri_uart_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_UART_IPCLKPORT_CLK, + 21, 0, 0), + + /* USI */ + GATE(CLK_GOUT_PERI_USI00_I2C_CLK, "gout_peri_usi00_i2c_clk", + "dout_peri_usi00_i2c", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_USI00_I2C_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI00_USI_CLK, "gout_peri_usi00_usi_clk", + "dout_peri_usi00_usi", + CLK_CON_GAT_CLK_BLK_PERI_UID_RSTNSYNC_CLK_PERI_USI00_USI_IPCLKPORT_CLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI00_I2C_IPCLK, "gout_peri_usi00_i2c_ipclk", + "dout_peri_usi00_i2c", + CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_I2C_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI00_I2C_PCLK, "gout_peri_usi00_i2c_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_I2C_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI00_USI_IPCLK, "gout_peri_usi00_usi_ipclk", + "dout_peri_usi00_usi", + CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_USI_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI00_USI_PCLK, "gout_peri_usi00_usi_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_USI00_USI_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI_SPI_IPCLK, "gout_peri_usi_spi_ipclk", + "dout_peri_spi", + CLK_CON_GAT_CLK_BLK_PERI_UID_USI_SPI_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI_SPI_PCLK, "gout_peri_usi_spi_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_USI_SPI_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI_UART_IPCLK, "gout_peri_usi_uart_ipclk", + "mout_pll_peri_uart_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_USI_UART_IPCLKPORT_IPCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI_UART_PCLK, "gout_peri_usi_uart_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_USI_UART_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_USI00_I2C, "gout_peri_usi00_i2c", + "mout_pll_peri_ip_user", + CLK_CON_GAT_GATE_CLK_PERI_USI00_I2C, + 21, 0, 0), + + /* WDT (Watchdog Timer) */ + GATE(CLK_GOUT_PERI_WDT0_PCLK, "gout_peri_wdt0_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_WDT0_IPCLKPORT_PCLK, + 21, 0, 0), + GATE(CLK_GOUT_PERI_WDT1_PCLK, "gout_peri_wdt1_pclk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_WDT1_IPCLKPORT_PCLK, + 21, 0, 0), + + /* UNKNOWN */ + GATE(CLK_GOUT_PERI_SLH_AXI_MI_P_CLK, "gout_peri_slh_axi_mi_p_clk", + "mout_pll_peri_bus_user", + CLK_CON_GAT_CLK_BLK_PERI_UID_SLH_AXI_MI_P_PERI_IPCLKPORT_I_CLK, + 21, 0, 0), +}; + +static const struct samsung_cmu_info peri_cmu_info __initconst = { + .mux_clks = peri_mux_clks, + .nr_mux_clks = ARRAY_SIZE(peri_mux_clks), + .div_clks = peri_div_clks, + .nr_div_clks = ARRAY_SIZE(peri_div_clks), + .fixed_factor_clks = peri_fixed_factor_clks, + .nr_fixed_factor_clks = ARRAY_SIZE(peri_fixed_factor_clks), + .gate_clks = peri_gate_clks, + .nr_gate_clks = ARRAY_SIZE(peri_gate_clks), + .nr_clk_ids = CLKS_NR_PERI, + .clk_regs = peri_clk_regs, + .nr_clk_regs = ARRAY_SIZE(peri_clk_regs), + .sysreg_clk_regs = drcg_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(drcg_sysreg), + .clk_name = "bus", + .auto_clock_gate = true, + .gate_dbg_offset = EXYNOS5515_GATE_DBG_OFFSET, + .option_offset = PERI_CMU_PERI_CONTROLLER_OPTION, + .drcg_offset = EXYNOS5515_DRCG_EN_OFFSET, +}; + +static void __init exynos5515_cmu_peri_init(struct device_node *np) +{ + exynos_arm64_register_cmu(NULL, np, &peri_cmu_info); +} + +/* Register CMU_PERI early, as it's a dependency for the MCT. */ +CLK_OF_DECLARE(exynos5515_cmu_peri, "samsung,exynos5515-cmu-peri", + exynos5515_cmu_peri_init); + +/* ---- CMU_FSYS ------------------------------------------------------------ */ + +/* + * CMU_FSYS: 0x10400000 + * SYSREG_FSYS: 0x10420000 + */ + +#define PLL_CON0_MUX_CLKCMU_FSYS_BUS_USER 0x0600 +#define PLL_CON1_MUX_CLKCMU_FSYS_BUS_USER 0x0604 +#define PLL_CON0_MUX_CLKCMU_FSYS_MMC_CARD_USER 0x0610 +#define PLL_CON1_MUX_CLKCMU_FSYS_MMC_CARD_USER 0x0614 +#define PLL_CON0_MUX_CLKCMU_FSYS_MMC_EMBD_USER 0x0620 +#define PLL_CON1_MUX_CLKCMU_FSYS_MMC_EMBD_USER 0x0624 +#define PLL_CON0_MUX_CLKCMU_FSYS_USB20DRD_USER 0x0630 +#define PLL_CON1_MUX_CLKCMU_FSYS_USB20DRD_USER 0x0634 +#define FSYS_CMU_FSYS_CONTROLLER_OPTION 0x0800 +#define CLK_CON_GAT_CLK_BLK_FSYS_UID_FSYS_CMU_FSYS_IPCLKPORT_PCLK 0x2000 +#define CLK_CON_GAT_CLK_BLK_FSYS_UID_MMC_CARD_IPCLKPORT_SDCLKIN 0x2004 +#define CLK_CON_GAT_CLK_BLK_FSYS_UID_MMC_EMBD_IPCLKPORT_SDCLKIN 0x2008 +#define CLK_CON_GAT_CLK_BLK_FSYS_UID_RSTNSYNC_CLK_FSYS_OSCCLK_IPCLKPORT_CLK 0x200c +#define CLK_CON_GAT_CLK_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_I_USB20DRD_REF_CLK_50 0x2010 +#define CLK_CON_GAT_CLK_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_I_USB20_PHY_REFCLK_26 0x2014 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_D_TZPC_FSYS_IPCLKPORT_PCLK 0x2018 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_GPIO_FSYS_IPCLKPORT_PCLK 0x201c +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_MMC_CARD_IPCLKPORT_I_ACLK 0x2020 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_MMC_EMBD_IPCLKPORT_I_ACLK 0x2024 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_PPMU_FSYS_IPCLKPORT_ACLK 0x2028 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_PPMU_FSYS_IPCLKPORT_PCLK 0x202c +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_RSTNSYNC_CLK_FSYS_BUS_IPCLKPORT_CLK 0x2030 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_SLH_AXI_MI_P_FSYS_IPCLKPORT_I_CLK 0x2034 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_SLH_AXI_SI_D_FSYS_IPCLKPORT_I_CLK 0x2038 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_SYSREG_FSYS_IPCLKPORT_PCLK 0x203c +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_ACLK_PHYCTRL_20 0x2040 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_BUS_CLK_EARLY 0x2044 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_US_64TO128_FSYS_IPCLKPORT_ACLK 0x2048 +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_XIU_D_FSYS_IPCLKPORT_ACLK 0x204c +#define CLK_CON_GAT_GOUT_BLK_FSYS_UID_XIU_P_FSYS_IPCLKPORT_ACLK 0x2050 + +static const unsigned long fsys_clk_regs[] __initconst = { + PLL_CON0_MUX_CLKCMU_FSYS_BUS_USER, + PLL_CON1_MUX_CLKCMU_FSYS_BUS_USER, + PLL_CON0_MUX_CLKCMU_FSYS_MMC_CARD_USER, + PLL_CON1_MUX_CLKCMU_FSYS_MMC_CARD_USER, + PLL_CON0_MUX_CLKCMU_FSYS_MMC_EMBD_USER, + PLL_CON1_MUX_CLKCMU_FSYS_MMC_EMBD_USER, + PLL_CON0_MUX_CLKCMU_FSYS_USB20DRD_USER, + PLL_CON1_MUX_CLKCMU_FSYS_USB20DRD_USER, + FSYS_CMU_FSYS_CONTROLLER_OPTION, + CLK_CON_GAT_CLK_BLK_FSYS_UID_FSYS_CMU_FSYS_IPCLKPORT_PCLK, + CLK_CON_GAT_CLK_BLK_FSYS_UID_MMC_CARD_IPCLKPORT_SDCLKIN, + CLK_CON_GAT_CLK_BLK_FSYS_UID_MMC_EMBD_IPCLKPORT_SDCLKIN, + CLK_CON_GAT_CLK_BLK_FSYS_UID_RSTNSYNC_CLK_FSYS_OSCCLK_IPCLKPORT_CLK, + CLK_CON_GAT_CLK_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_I_USB20DRD_REF_CLK_50, + CLK_CON_GAT_CLK_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_I_USB20_PHY_REFCLK_26, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_D_TZPC_FSYS_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_GPIO_FSYS_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_MMC_CARD_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_MMC_EMBD_IPCLKPORT_I_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_PPMU_FSYS_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_PPMU_FSYS_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_RSTNSYNC_CLK_FSYS_BUS_IPCLKPORT_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_SLH_AXI_MI_P_FSYS_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_SLH_AXI_SI_D_FSYS_IPCLKPORT_I_CLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_SYSREG_FSYS_IPCLKPORT_PCLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_ACLK_PHYCTRL_20, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_BUS_CLK_EARLY, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_US_64TO128_FSYS_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_XIU_D_FSYS_IPCLKPORT_ACLK, + CLK_CON_GAT_GOUT_BLK_FSYS_UID_XIU_P_FSYS_IPCLKPORT_ACLK, +}; + +/* Parent clock list for CMU_FSYS muxes */ +PNAME(mout_pll_fsys_bus_user_p) = { "oscclk", + "dout_cmu_fsys_bus" }; + +/* Parent clock list for CMU_FSYS muxes: for MMC */ +PNAME(mout_pll_fsys_mmc_card_user_p) = { "oscclk", + "dout_cmu_fsys_mmc_card" }; + +PNAME(mout_pll_fsys_mmc_embd_user_p) = { "oscclk", + "dout_cmu_fsys_mmc_embd" }; + +/* Parent clock list for CMU_FSYS muxes: for USB */ +PNAME(mout_pll_fsys_usb20drd_user_p) = { "oscclk", + "dout_cmu_fsys_usb20drd" }; + +static const struct samsung_mux_clock fsys_mux_clks[] __initconst = { + /* BUS */ + MUX(CLK_MOUT_PLL_FSYS_BUS_USER, "mout_pll_fsys_bus_user", + mout_pll_fsys_bus_user_p, + PLL_CON0_MUX_CLKCMU_FSYS_BUS_USER, + 4, 1), + + /* MMC */ + MUX(CLK_MOUT_PLL_FSYS_MMC_CARD_USER, "mout_pll_fsys_mmc_card_user", + mout_pll_fsys_mmc_card_user_p, + PLL_CON0_MUX_CLKCMU_FSYS_MMC_CARD_USER, + 4, 1), + MUX(CLK_MOUT_PLL_FSYS_MMC_EMBD_USER, "mout_pll_fsys_mmc_embd_user", + mout_pll_fsys_mmc_embd_user_p, + PLL_CON0_MUX_CLKCMU_FSYS_MMC_EMBD_USER, + 4, 1), + + /* USB */ + MUX(CLK_MOUT_PLL_FSYS_USB20DRD_USER, "mout_pll_fsys_usb20drd_user", + mout_pll_fsys_usb20drd_user_p, + PLL_CON0_MUX_CLKCMU_FSYS_USB20DRD_USER, + 4, 1), +}; + +static const struct samsung_gate_clock fsys_gate_clks[] __initconst = { + /* BUS */ + GATE(CLK_GOUT_FSYS_BUS_CLK, "gout_fsys_bus_clk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_RSTNSYNC_CLK_FSYS_BUS_IPCLKPORT_CLK, + 21, 0, 0), + + /* CMU */ + GATE(CLK_GOUT_FSYS_CMU_PCLK, "gout_fsys_cmu_pclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_CLK_BLK_FSYS_UID_FSYS_CMU_FSYS_IPCLKPORT_PCLK, + 21, 0, 0), + + /* GPIO */ + GATE(CLK_GOUT_FSYS_GPIO_PCLK, "gout_fsys_gpio_pclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_GPIO_FSYS_IPCLKPORT_PCLK, + 21, 0, 0), + + /* MMC */ + GATE(CLK_GOUT_FSYS_MMC_CARD_SDCLKIN, "gout_fsys_mmc_card_sdclkin", + "mout_pll_fsys_mmc_card_user", + CLK_CON_GAT_CLK_BLK_FSYS_UID_MMC_CARD_IPCLKPORT_SDCLKIN, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_MMC_EMBD_SDCLKIN, "gout_fsys_mmc_embd_sdclkin", + "mout_pll_fsys_mmc_embd_user", + CLK_CON_GAT_CLK_BLK_FSYS_UID_MMC_EMBD_IPCLKPORT_SDCLKIN, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_MMC_CARD_ACLK, "gout_fsys_mmc_card_aclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_MMC_CARD_IPCLKPORT_I_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_MMC_EMBD_ACLK, "gout_fsys_mmc_embd_aclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_MMC_EMBD_IPCLKPORT_I_ACLK, + 21, 0, 0), + + /* OSCCLK */ + GATE(CLK_GOUT_FSYS_OSCCLK, "gout_fsys_oscclk", + "oscclk", + CLK_CON_GAT_CLK_BLK_FSYS_UID_RSTNSYNC_CLK_FSYS_OSCCLK_IPCLKPORT_CLK, + 21, 0, 0), + + /* PMU */ + GATE(CLK_GOUT_FSYS_PPMU_ACLK, "gout_fsys_ppmu_aclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_PPMU_FSYS_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_PPMU_PCLK, "gout_fsys_ppmu_pclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_PPMU_FSYS_IPCLKPORT_PCLK, + 21, 0, 0), + + /* SYSREG */ + GATE(CLK_GOUT_FSYS_SYSREG_PCLK, "gout_fsys_sysreg_pclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_SYSREG_FSYS_IPCLKPORT_PCLK, + 21, 0, 0), + + /* TZ */ + GATE(CLK_GOUT_FSYS_D_TZPC_PCLK, "gout_fsys_d_tzpc_pclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_D_TZPC_FSYS_IPCLKPORT_PCLK, + 21, 0, 0), + + /* USB */ + GATE(CLK_GOUT_FSYS_USB20DRD_REFCLK, + "gout_fsys_usb20drd_refclk", + "mout_pll_fsys_usb20drd_user", + CLK_CON_GAT_CLK_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_I_USB20DRD_REF_CLK_50, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_USB20DRD_PHY_REFCLK, + "gout_fsys_usb20drd_phy_refclk", + "oscclk", + CLK_CON_GAT_CLK_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_I_USB20_PHY_REFCLK_26, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_USB20DRD_ACLK_PHYCTRL, + "gout_fsys_usb20drd_aclk_phyctrl", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_ACLK_PHYCTRL_20, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_USB20DRD_BUS_CLK_EARLY, + "gout_fsys_usb20drd_bus_clk_early", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_USB20DRD_TOP_IPCLKPORT_BUS_CLK_EARLY, + 21, 0, 0), + + /* UNKNOWN */ + GATE(CLK_GOUT_FSYS_SLH_AXI_MI_P_CLK, "gout_fsys_slh_axi_mi_p_clk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_SLH_AXI_MI_P_FSYS_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_SLH_AXI_SI_D_CLK, "gout_fsys_slh_axi_si_d_clk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_SLH_AXI_SI_D_FSYS_IPCLKPORT_I_CLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_US_64TO128_ACLK, "gout_fsys_us_64to128_aclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_US_64TO128_FSYS_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_XIU_D_ACLK, "gout_fsys_xiu_d_aclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_XIU_D_FSYS_IPCLKPORT_ACLK, + 21, 0, 0), + GATE(CLK_GOUT_FSYS_XIU_P_ACLK, "gout_fsys_xiu_p_aclk", + "mout_pll_fsys_bus_user", + CLK_CON_GAT_GOUT_BLK_FSYS_UID_XIU_P_FSYS_IPCLKPORT_ACLK, + 21, 0, 0), +}; + +static const struct samsung_cmu_info fsys_cmu_info __initconst = { + .mux_clks = fsys_mux_clks, + .nr_mux_clks = ARRAY_SIZE(fsys_mux_clks), + .gate_clks = fsys_gate_clks, + .nr_gate_clks = ARRAY_SIZE(fsys_gate_clks), + .nr_clk_ids = CLKS_NR_FSYS, + .clk_regs = fsys_clk_regs, + .nr_clk_regs = ARRAY_SIZE(fsys_clk_regs), + .sysreg_clk_regs = drcg_sysreg, + .nr_sysreg_clk_regs = ARRAY_SIZE(drcg_sysreg), + .clk_name = "bus", + .auto_clock_gate = true, + .gate_dbg_offset = EXYNOS5515_GATE_DBG_OFFSET, + .option_offset = FSYS_CMU_FSYS_CONTROLLER_OPTION, + .drcg_offset = EXYNOS5515_DRCG_EN_OFFSET, +}; + +/* ----- platform_driver ----- */ + +static int __init exynos5515_cmu_probe(struct platform_device *pdev) +{ + const struct samsung_cmu_info *info; + struct device *dev = &pdev->dev; + + info = of_device_get_match_data(dev); + exynos_arm64_register_cmu(dev, dev->of_node, info); + + return 0; +} + +static const struct of_device_id exynos5515_cmu_of_match[] = { + { + .compatible = "samsung,exynos5515-cmu-fsys", + .data = &fsys_cmu_info, + }, + { }, +}; + +static struct platform_driver exynos5515_cmu_driver __refdata = { + .driver = { + .name = "exynos5515-cmu", + .of_match_table = exynos5515_cmu_of_match, + .suppress_bind_attrs = true, + }, + .probe = exynos5515_cmu_probe, +}; + +static int __init exynos5515_cmu_init(void) +{ + return platform_driver_register(&exynos5515_cmu_driver); +} + +core_initcall(exynos5515_cmu_init); From 91df590e41982844e5b0c2d100cf7339dbbad454 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 3 Sep 2026 14:05:25 +0200 Subject: [PATCH 075/168] clk: renesas: rcar-gen3: Use FIELD_GET() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve readability by using the FIELD_GET() helper instead of open-coding the same operation, and by adding field definitions to get rid of hardcoded values. While at it, move register definitions that are only used inside the rcar-gen3-cpg.c source file out of the rcar-gen3-cpg.h header file. Add comments where appropriate. Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Link: https://patch.msgid.link/17c50847f86b814150573e34cc64913f09598f0f.1788437047.git.geert+renesas@glider.be --- drivers/clk/renesas/rcar-gen3-cpg.c | 15 +++++++++------ drivers/clk/renesas/rcar-gen3-cpg.h | 3 +-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index e5b503332217..bbb76e4fa333 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -36,7 +36,11 @@ #define CPG_PLLnCR_STC_MASK GENMASK(30, 24) /* PLL Circuit Mult. Ratio */ -#define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */ +#define CPG_RPCCKCR 0x238 /* RPC-IF Clock Frequency Control Reg */ +#define CPG_RPCCKCR_DIV_RPCSRC GENMASK(4, 3) /* RPCSRC divider */ + +#define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */ +#define CPG_RCKCR_DIV GENMASK(5, 0) /* RCLK Division Ratio */ /* PLL Clocks */ struct cpg_pll_clk { @@ -395,7 +399,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, * the multiplier value. */ value = readl(base + CPG_PLL4CR); - mult = (((value >> 24) & 0x7f) + 1) * 2; + mult = (FIELD_GET(CPG_PLLnCR_STC_MASK, value) + 1) * 2; break; case CLK_TYPE_GEN3_SDH: @@ -420,7 +424,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, * RINT is default. * Only if EXTALR is populated, we switch to it. */ - value = readl(csn->reg) & 0x3f; + value = readl(csn->reg) & CPG_RCKCR_DIV; if (clk_get_rate(clks[cpg_clk_extalr])) { parent = clks[cpg_clk_extalr]; @@ -496,9 +500,8 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, * MD[4:1] pins and CPG_RPCCKCR[4:3] register value for * which has been set prior to booting the kernel. */ - value = (readl(base + CPG_RPCCKCR) & GENMASK(4, 3)) >> 3; - - switch (value) { + value = readl(base + CPG_RPCCKCR); + switch (FIELD_GET(CPG_RPCCKCR_DIV_RPCSRC, value)) { case 0: div = 5; break; diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index d15a5d1df71c..fa25911b993e 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -76,8 +76,7 @@ struct rcar_gen3_cpg_pll_config { u8 osc_prediv; }; -#define CPG_RPCCKCR 0x238 -#define CPG_RCKCR 0x240 +#define CPG_RCKCR 0x240 /* RCLK Frequency Control Register */ struct clk *rcar_gen3_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, const struct cpg_mssr_info *info, From 8d5fa37307ac1f0612cf17ac0ccabcc258cc1526 Mon Sep 17 00:00:00 2001 From: Karl Mehltretter Date: Thu, 10 Sep 2026 05:30:00 +0200 Subject: [PATCH 076/168] clk: mediatek: reset: Fix device registration kernel-doc The comment for mtk_register_reset_controller_with_dev() names the older helper and documents np rather than dev. The new helper takes a struct device and obtains its device node internally. Use the actual function and parameter names and clarify that failures return negative error codes. Fixes: 761bc64003e3 ("clk: mediatek: reset: Add new register reset function with device") Assisted-by: LLM Signed-off-by: Karl Mehltretter Reviewed-by: Chen-Yu Tsai Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Brian Masney --- drivers/clk/mediatek/reset.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/mediatek/reset.h b/drivers/clk/mediatek/reset.h index 562ffd290a22..b09cdcab0c4b 100644 --- a/drivers/clk/mediatek/reset.h +++ b/drivers/clk/mediatek/reset.h @@ -60,11 +60,11 @@ struct mtk_clk_rst_data { }; /** - * mtk_register_reset_controller - Register mediatek clock reset controller with device - * @np: Pointer to device. + * mtk_register_reset_controller_with_dev - Register a MediaTek reset controller + * @dev: Device used to manage the reset controller resources. * @desc: Constant pointer to description of clock reset. * - * Return: 0 on success and errorno otherwise. + * Return: 0 on success, negative errno otherwise. */ int mtk_register_reset_controller_with_dev(struct device *dev, const struct mtk_clk_rst_desc *desc); From ad0252c5615a47d2c97de84bbc2570d25bbd0512 Mon Sep 17 00:00:00 2001 From: Hemanth Selam Date: Fri, 4 Sep 2026 16:39:57 +0530 Subject: [PATCH 077/168] clk: tegra: fix typos in comments Fix typos in comments, reported by scripts/checkpatch.pl using the misspelling list in scripts/spelling.txt. Only touches comments, no code changes. Assisted-by: Cursor:claude-opus-5 Signed-off-by: Hemanth Selam Signed-off-by: Brian Masney --- drivers/clk/tegra/clk.h | 2 +- include/linux/clk/ti.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 73efd2ff37c9..afa93ba505ab 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -255,7 +255,7 @@ struct tegra_clk_pll; * @set_gain: Callback to adjust N div for SDM enabled * PLL's based on fractional divider value. * @calc_rate: Callback used to change how out of table - * rates (dividers and multipler) are calculated. + * rates (dividers and multiplier) are calculated. * @adjust_vco: Callback to adjust the programming range of the * divider range (if SDM is present) * @set_defaults: Callback which will try to initialize PLL diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 54a3fa370004..61c4abf19995 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -51,7 +51,7 @@ struct clk_omap_reg { * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg * @dcc_mask: mask of the DPLL DCC correction bitfield @mult_div1_reg - * @dcc_rate: rate atleast which DCC @dcc_mask must be set + * @dcc_rate: rate at least which DCC @dcc_mask must be set * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg From a2ef401bdfd19aa41d0e3e1b630a12fbc01ac184 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 3 Sep 2026 12:09:25 +0200 Subject: [PATCH 078/168] clk: rs9: Add clock index range check to rs9_of_clk_get() rs9_of_clk_get() does not validate the clock index in the passed DT clock specifier. If DT specifies an incorrect and out-of-range index, this will access memory beyond the end of the clk_dif[] array. Fix by this adding a range check to rs9_of_clk_get(). Fixes: 892e0ddea1aa6f70 ("clk: rs9: Add Renesas 9-series PCIe clock generator driver") Signed-off-by: Geert Uytterhoeven Reviewed-by: Marek Vasut Signed-off-by: Brian Masney --- drivers/clk/clk-renesas-pcie.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c index 564550c80389..f3376c29007a 100644 --- a/drivers/clk/clk-renesas-pcie.c +++ b/drivers/clk/clk-renesas-pcie.c @@ -276,6 +276,11 @@ rs9_of_clk_get(struct of_phandle_args *clkspec, void *data) struct rs9_driver_data *rs9 = data; unsigned int idx = clkspec->args[0]; + if (idx >= rs9->chip_info->num_clks) { + pr_err("%s: Invalid clock index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } + return rs9->clk_dif[idx]; } From 07f4bac13786a80cd3e6547051376ea65da2f4c5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 3 Sep 2026 12:09:26 +0200 Subject: [PATCH 079/168] clk: rs9: Convert to clk_hw_onecell_data and of_clk_hw_onecell_get() Convert the rs9 clock driver to use the of_clk_hw_onecell_get() helper, which requires using the clk_hw_onecell_data structure. Embedding that structure in the rs9_driver_data structure has the benefit that the clock array always has the correct size, and thus can no longer become out of sync when adding support for new rs9 variants. Signed-off-by: Geert Uytterhoeven Reviewed-by: Marek Vasut Signed-off-by: Brian Masney --- drivers/clk/clk-renesas-pcie.c | 44 ++++++++++++++-------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c index f3376c29007a..e2b441f99cca 100644 --- a/drivers/clk/clk-renesas-pcie.c +++ b/drivers/clk/clk-renesas-pcie.c @@ -63,10 +63,11 @@ struct rs9_driver_data { struct i2c_client *client; struct regmap *regmap; const struct rs9_chip_info *chip_info; - struct clk_hw *clk_dif[8]; u8 pll_amplitude; u8 pll_ssc; u8 clk_dif_sr; + /* must be last */ + struct clk_hw_onecell_data onecell; }; /* @@ -270,37 +271,28 @@ static void rs9_update_config(struct rs9_driver_data *rs9) } } -static struct clk_hw * -rs9_of_clk_get(struct of_phandle_args *clkspec, void *data) -{ - struct rs9_driver_data *rs9 = data; - unsigned int idx = clkspec->args[0]; - - if (idx >= rs9->chip_info->num_clks) { - pr_err("%s: Invalid clock index %u\n", __func__, idx); - return ERR_PTR(-EINVAL); - } - - return rs9->clk_dif[idx]; -} - static int rs9_probe(struct i2c_client *client) { + const struct rs9_chip_info *chip_info; unsigned char name[5] = "DIF0"; struct rs9_driver_data *rs9; unsigned int vid, did; struct clk_hw *hw; int i, ret; - rs9 = devm_kzalloc(&client->dev, sizeof(*rs9), GFP_KERNEL); + chip_info = i2c_get_match_data(client); + if (!chip_info) + return -EINVAL; + + rs9 = devm_kzalloc(&client->dev, struct_size(rs9, onecell.hws, + chip_info->num_clks), GFP_KERNEL); if (!rs9) return -ENOMEM; i2c_set_clientdata(client, rs9); rs9->client = client; - rs9->chip_info = i2c_get_match_data(client); - if (!rs9->chip_info) - return -EINVAL; + rs9->chip_info = chip_info; + rs9->onecell.num = chip_info->num_clks; /* Fetch common configuration from DT (if specified) */ ret = rs9_get_common_config(rs9); @@ -308,7 +300,7 @@ static int rs9_probe(struct i2c_client *client) return ret; /* Fetch DIFx output configuration from DT (if specified) */ - for (i = 0; i < rs9->chip_info->num_clks; i++) { + for (i = 0; i < rs9->onecell.num; i++) { ret = rs9_get_output_config(rs9, i); if (ret) return ret; @@ -334,24 +326,24 @@ static int rs9_probe(struct i2c_client *client) return ret; vid &= RS9_REG_VID_MASK; - if (vid != RS9_REG_VID_IDT || did != rs9->chip_info->did) + if (vid != RS9_REG_VID_IDT || did != chip_info->did) return dev_err_probe(&client->dev, -ENODEV, "Incorrect VID/DID: %#02x, %#02x. Expected %#02x, %#02x\n", - vid, did, RS9_REG_VID_IDT, - rs9->chip_info->did); + vid, did, RS9_REG_VID_IDT, chip_info->did); /* Register clock */ - for (i = 0; i < rs9->chip_info->num_clks; i++) { + for (i = 0; i < rs9->onecell.num; i++) { snprintf(name, 5, "DIF%d", i); hw = devm_clk_hw_register_fixed_factor_index(&client->dev, name, 0, 0, 4, 1); if (IS_ERR(hw)) return PTR_ERR(hw); - rs9->clk_dif[i] = hw; + rs9->onecell.hws[i] = hw; } - ret = devm_of_clk_add_hw_provider(&client->dev, rs9_of_clk_get, rs9); + ret = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_onecell_get, + &rs9->onecell); if (!ret) rs9_update_config(rs9); From 061aca8aa0be5de74a4b267588bbcfb8beca0ecb Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Fri, 4 Sep 2026 14:46:57 -0700 Subject: [PATCH 080/168] clk: nuvoton: build with any architecture The directory's Kconfig already has COMPILE_TEST. This allows it to work. Signed-off-by: Rosen Penev Signed-off-by: Brian Masney --- drivers/clk/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d56abaad9883..2d8f60254373 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -149,7 +149,7 @@ endif obj-y += mstar/ obj-y += mvebu/ obj-$(CONFIG_ARCH_MXS) += mxs/ -obj-$(CONFIG_ARCH_MA35) += nuvoton/ +obj-y += nuvoton/ obj-$(CONFIG_COMMON_CLK_NXP) += nxp/ obj-$(CONFIG_COMMON_CLK_PISTACHIO) += pistachio/ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ From 276741aac3b56ba50bef59715ba18ba3f0b953a2 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sun, 6 Sep 2026 11:36:04 +0800 Subject: [PATCH 081/168] clk: s2mps11: Propagate OF provider registration failures s2mps11_clk_probe() ignores of_clk_add_hw_provider() failures, stores driver data and returns success even though DT consumers cannot acquire the registered clocks. Return the provider error through the existing lookup cleanup path. Skip empty lookup slots while unwinding because S2MPS14 omits its CP clock. The issue was found by our static-analysis tool and manually reviewed. Fixes: b228fad50c00 ("clk: s2mps11: Migrate to clk_hw based OF and registration APIs") Assisted-by: LLM Signed-off-by: Pengpeng Hou Signed-off-by: Brian Masney --- drivers/clk/clk-s2mps11.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c index fa5ac8f673f6..94969d97d6e9 100644 --- a/drivers/clk/clk-s2mps11.c +++ b/drivers/clk/clk-s2mps11.c @@ -192,8 +192,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev) clk_data->hws[i] = &s2mps11_clks[i].hw; } - of_clk_add_hw_provider(s2mps11_clks->clk_np, of_clk_hw_onecell_get, - clk_data); + ret = of_clk_add_hw_provider(s2mps11_clks->clk_np, + of_clk_hw_onecell_get, clk_data); + if (ret) + goto err_reg; platform_set_drvdata(pdev, s2mps11_clks); @@ -201,8 +203,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev) err_reg: of_node_put(s2mps11_clks[0].clk_np); - while (--i >= 0) - clkdev_drop(s2mps11_clks[i].lookup); + while (--i >= 0) { + if (s2mps11_clks[i].lookup) + clkdev_drop(s2mps11_clks[i].lookup); + } return ret; } From 8d90c0eeef104553d6b9137becd7f58b468aaa0b Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 17 Aug 2026 20:25:34 +0100 Subject: [PATCH 082/168] clk: renesas: r9a09g077: Register SYSC regmap Register a syscon regmap for the System Controller (SYSC) integrated into the RZ/T2H and RZ/N2H CPG block. Unlike traditional Renesas CPG/MSSR implementations, the RZ/T2H and RZ/N2H CPG block also integrates the SYSC, which provides low-power management, clock monitoring, write protection and peripheral configuration registers shared by multiple drivers. Implement the RZ/T2H-specific .post_init() callback to create and register a syscon regmap covering the SYSC register space using the CPG device node. For backward compatibility, return without registering the regmap when the mapped resources correspond to older Device Trees that expose only the legacy 64 KiB CPG register window. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260817192540.423994-2-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/Kconfig | 2 + drivers/clk/renesas/r9a09g077-cpg.c | 142 +++++++++++++++++++++++++ drivers/clk/renesas/renesas-cpg-mssr.c | 3 + drivers/clk/renesas/renesas-cpg-mssr.h | 1 + 4 files changed, 148 insertions(+) diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 17b95a2e96fb..46b929e9872b 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -223,11 +223,13 @@ config CLK_R9A09G077 bool "RZ/T2H clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSSR select CLK_RZV2H_CPG_LIB + select MFD_SYSCON config CLK_R9A09G087 bool "RZ/N2H clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSSR select CLK_RZV2H_CPG_LIB + select MFD_SYSCON config CLK_SH73A0 bool "SH-Mobile AG5 clock support" if COMPILE_TEST diff --git a/drivers/clk/renesas/r9a09g077-cpg.c b/drivers/clk/renesas/r9a09g077-cpg.c index 5640c2035e5a..5a0e7df1eb06 100644 --- a/drivers/clk/renesas/r9a09g077-cpg.c +++ b/drivers/clk/renesas/r9a09g077-cpg.c @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include #include @@ -15,7 +17,11 @@ #include #include #include +#include #include +#include +#include +#include #include #include @@ -87,6 +93,20 @@ MODULE_IMPORT_NS("RZV2H_CPG"); #define CPG_PLL_MON(x) ((x) - 0x10) #define CPG_PLL_MON_LOCK BIT(0) +/* Size of each mapped CPG/MSSR register region (base0, base1) */ +#define RZT2H_CPG_REG_SIZE 0x20000 +/* This is the size of two SYSC regions combined */ +#define RZT2H_SYSC_SIZE 0x20000 +#define RZT2H_SYSC_OFFSET 0x10000 +#define RZT2H_SYSC_BLOCK_MASK BIT(16) +#define RZT2H_SYSC_OFFSET_MASK GENMASK(15, 0) +#define RZT2H_SYSC_BLOCK(x) FIELD_GET(RZT2H_SYSC_BLOCK_MASK, x) +#define RZT2H_SYSC_REG_OFFSET(x) FIELD_GET(RZT2H_SYSC_OFFSET_MASK, x) + +struct r9a09g077_sysc_reg { + void __iomem *base[2]; +}; + enum rzt2h_clk_types { CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM, /* Clock with divider */ CLK_TYPE_RZT2H_MUX, /* Clock with clock source selector */ @@ -875,6 +895,126 @@ r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, } } +static int r9a09g077_regmap_read(void *context, unsigned int reg, unsigned int *val) +{ + struct r9a09g077_sysc_reg *sysc = context; + void __iomem *base = sysc->base[RZT2H_SYSC_BLOCK(reg)]; + + *val = readl(base + RZT2H_SYSC_REG_OFFSET(reg)); + + return 0; +} + +static int r9a09g077_regmap_write(void *context, unsigned int reg, unsigned int val) +{ + struct r9a09g077_sysc_reg *sysc = context; + void __iomem *base = sysc->base[RZT2H_SYSC_BLOCK(reg)]; + + writel(val, base + RZT2H_SYSC_REG_OFFSET(reg)); + + return 0; +} + +static const struct regmap_bus r9a09g077_sys_regmap_bus = { + .reg_write = r9a09g077_regmap_write, + .reg_read = r9a09g077_regmap_read, +}; + +static bool r9a09g077_writeable_readable_sysc(struct device *dev, unsigned int reg) +{ + unsigned int offset = RZT2H_SYSC_REG_OFFSET(reg); + + switch (RZT2H_SYSC_BLOCK(reg)) { + case 0: + switch (offset) { + /* ELOPA/B and GTIOCSEL */ + case 0x0000 ... 0x0008: + /* Encoder config */ + case 0x1000 ... 0x1164: + /* PCIe config */ + case 0x2000 ... 0x2024: + case 0x2030 ... 0x2054: + case 0x2060: + /* xSPI config */ + case 0x3000 ... 0x300C: + case 0x3100 ... 0x310C: + /* MD_MON */ + case 0x4100: + /* PRCRN */ + case 0x4200: + return true; + + default: + return false; + } + case 1: + switch (offset) { + /* WDTDCRm */ + case 0x5100 ... 0x5114: + /* PRCRS */ + case 0x6000: + return true; + + default: + return false; + } + default: + return false; + } +} + +static int r9a09g077_post_init(struct device *dev, struct cpg_mssr_pub *pub) +{ + struct regmap_config *regmap_cfg __free(kfree) = kzalloc_obj(*regmap_cfg); + struct r9a09g077_sysc_reg *sysc_reg; + struct regmap *regmap; + struct resource res; + int ret; + + /* + * Return early if the SYSC sizes are not as expected, for backwards + * compatibility with older device trees that only expose the 64 KiB + * CPG register window. + */ + ret = of_address_to_resource(dev->of_node, 0, &res); + if (ret) + return ret; + if (resource_size(&res) != RZT2H_CPG_REG_SIZE) + return 0; + + ret = of_address_to_resource(dev->of_node, 1, &res); + if (ret) + return ret; + if (resource_size(&res) != RZT2H_CPG_REG_SIZE) + return 0; + + if (!regmap_cfg) + return -ENOMEM; + + sysc_reg = devm_kzalloc(dev, sizeof(*sysc_reg), GFP_KERNEL); + if (!sysc_reg) + return -ENOMEM; + + /* Only allow access in the SYSC regions */ + sysc_reg->base[0] = pub->base0 + RZT2H_SYSC_OFFSET; + sysc_reg->base[1] = pub->base1 + RZT2H_SYSC_OFFSET; + + regmap_cfg->name = "rzt2h_sysc"; + regmap_cfg->reg_bits = 32; + regmap_cfg->reg_stride = 4; + regmap_cfg->val_bits = 32; + regmap_cfg->fast_io = true; + regmap_cfg->max_register = RZT2H_SYSC_SIZE - 1; + regmap_cfg->readable_reg = r9a09g077_writeable_readable_sysc; + regmap_cfg->writeable_reg = r9a09g077_writeable_readable_sysc; + + regmap = devm_regmap_init(dev, &r9a09g077_sys_regmap_bus, sysc_reg, regmap_cfg); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return of_syscon_register_regmap(dev->of_node, regmap); +} + const struct cpg_mssr_info r9a09g077_cpg_mssr_info = { /* Core Clocks */ .core_clks = r9a09g077_core_clks, @@ -889,4 +1029,6 @@ const struct cpg_mssr_info r9a09g077_cpg_mssr_info = { .reg_layout = CLK_REG_LAYOUT_RZ_T2H, .cpg_clk_register = r9a09g077_cpg_clk_register, + + .post_init = r9a09g077_post_init, }; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 80f4403ea2ba..f2feac1cc74f 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -1414,6 +1414,9 @@ static int __init cpg_mssr_probe(struct platform_device *pdev) error = cpg_mssr_reset_controller_register(priv); + if (!error && info->post_init) + error = info->post_init(priv->dev, &priv->pub); + reserve_exit: cpg_mssr_reserved_exit(priv); diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index ad11ab5f0069..5bef6f34dcb2 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -178,6 +178,7 @@ struct cpg_mssr_info { /* Callbacks */ int (*init)(struct device *dev); + int (*post_init)(struct device *dev, struct cpg_mssr_pub *pub); struct clk *(*cpg_clk_register)(struct device *dev, const struct cpg_core_clk *core, const struct cpg_mssr_info *info, From 6b838130d2759008f8e8a80093c9eb6fcd435707 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 14 Sep 2026 16:20:39 +0200 Subject: [PATCH 083/168] MAINTAINERS: Add Angelo as MediaTek Clock Drivers submaintainer As asked multiple times by both Stephen Boyd and Brian Masney, add an entry for MediaTek Clock Drivers with myself as the submaintainer. Signed-off-by: AngeloGioacchino Del Regno Signed-off-by: Brian Masney --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3a19da74d00c..dd2742284dd8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16613,6 +16613,17 @@ M: Sean Wang S: Maintained F: drivers/media/rc/mtk-cir.c +MEDIATEK CLOCK DRIVERS +M: AngeloGioacchino Del Regno +L: linux-clk@vger.kernel.org +L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mediatek/linux.git +F: Documentation/devicetree/bindings/clock/mediatek,* +F: drivers/clk/mediatek/ +F: include/dt-bindings/clock/mediatek,*.h +F: include/dt-bindings/clock/mt*-clk.h + MEDIATEK DMA DRIVER M: Sean Wang L: dmaengine@vger.kernel.org From 4539402e0b34c8c239208d5f5b90248c040fee89 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Fri, 24 Jul 2026 11:03:58 +0200 Subject: [PATCH 084/168] clk: ti: clean-up simple provider misuse of the consumer API Clock provider should not be using the consumer interface. In other words, a provider should not be dealing with struct clk. This change targets occurrences for which the provider uses the consumer interface and corresponding clk_hw interface exist. Reviewed-by: Brian Masney Reviewed-by: Thierry Reding Link: https://patch.msgid.link/20260724-clk-provider-simple-clean-v2-7-56f306156d25@baylibre.com Signed-off-by: Jerome Brunet --- drivers/clk/ti/clockdomain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index c897ad7e681e..aedbe78bf1e4 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -104,7 +104,7 @@ int omap2_init_clk_clkdm(struct clk_hw *hw) if (!clk->clkdm_name) return 0; - clk_name = __clk_get_name(hw->clk); + clk_name = clk_hw_get_name(hw); clkdm = ti_clk_ll_ops->clkdm_lookup(clk->clkdm_name); if (clkdm) { From 904e5ef5ac48495ed439ca37dde7f0ce1e9c4af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Wed, 16 Sep 2026 14:08:54 +0200 Subject: [PATCH 085/168] clk: eyeq: Use devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert eqc_probe() from the open-coded platform_get_resource() + ioremap() sequence to devm_platform_ioremap_resource(). Besides less code, this requests the memory region so the OLB registers are properly reserved in the iomem_resource tree. Move devm_platform_ioremap_resource() before checking for device match data, so OLBs bound without match data also get their memory region mapped and reserved. Unregister the clocks before devres unmaps the region if the clock provider registration fails. Suggested-by: Vladimir Kondratiev Signed-off-by: Benoît Monin Signed-off-by: Brian Masney --- drivers/clk/clk-eyeq.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c index cf37feccc734..3c00be00889a 100644 --- a/drivers/clk/clk-eyeq.c +++ b/drivers/clk/clk-eyeq.c @@ -513,21 +513,16 @@ static int eqc_probe(struct platform_device *pdev) const struct eqc_match_data *data; struct clk_hw_onecell_data *cells; unsigned int i, clk_count; - struct resource *res; void __iomem *base; int ret; + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + data = device_get_match_data(dev); if (!data) - return 0; /* No clocks nor auxdevs, we are done. */ - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - base = ioremap(res->start, resource_size(res)); - if (!base) - return -ENOMEM; + return 0; /* No clocks nor auxdevs, stop here but keep resource reserved */ /* Init optional auxiliary devices. */ eqc_auxdev_create_optional(dev, base, data->reset_auxdev_name); @@ -559,7 +554,20 @@ static int eqc_probe(struct platform_device *pdev) dev_warn(dev, "failed probing clock %s: %d\n", clk->name, ret); } - return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells); + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells); + if (ret) { + for (i = 0; i < data->clk_count; i++) { + const struct eqc_clock *clk = &data->clks[i]; + struct clk_hw *hw = cells->hws[clk->index]; + + if (!IS_ERR_OR_NULL(hw) && clk->unregister) + clk->unregister(hw); + } + + kfree(cells); + } + + return ret; } #define DIV(_index, _parent_idx, _name, _parent_name, \ From 2b3e81a40ecf860c107dc47c119412746368591c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Monin?= Date: Wed, 16 Sep 2026 14:08:55 +0200 Subject: [PATCH 086/168] clk: eyeq: Add mobileye,eyeq6h-central-olb compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an entry for mobileye,eyeq6h-central-olb without match data: its clocks are all registered by the early init and it has no auxiliary devices, so probe() now reserves its region and stops there. Signed-off-by: Benoît Monin Signed-off-by: Brian Masney --- drivers/clk/clk-eyeq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c index 3c00be00889a..ae0faee31689 100644 --- a/drivers/clk/clk-eyeq.c +++ b/drivers/clk/clk-eyeq.c @@ -1183,6 +1183,7 @@ static const struct of_device_id eqc_match_table[] = { { .compatible = "mobileye,eyeq5-olb", .data = &eqc_eyeq5_match_data }, { .compatible = "mobileye,eyeq6l-olb", .data = &eqc_eyeq6l_match_data }, { .compatible = "mobileye,eyeq6lplus-olb", .data = &eqc_eyeq6lplus_match_data }, + { .compatible = "mobileye,eyeq6h-central-olb" /* no data, early only */ }, { .compatible = "mobileye,eyeq6h-west-olb", .data = &eqc_eyeq6h_west_match_data }, { .compatible = "mobileye,eyeq6h-east-olb", .data = &eqc_eyeq6h_east_match_data }, { .compatible = "mobileye,eyeq6h-south-olb", .data = &eqc_eyeq6h_south_match_data }, From 7a4cc47d715f08309089d40b8c29fb0ba79917db Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Thu, 13 Aug 2026 23:36:50 +0800 Subject: [PATCH 087/168] clk: si521xx: correct the SI52147 OF output enable map The SI52147 data sheet assigns DIFF0 through DIFF3 output-enable bits to 0x17 in control register 1. The OF match data uses 0x15, leaving the DIFF2 bit out of the map, while the I2C ID table already uses the documented value. Use 0x17 for the SI52147 OF entry so both enumeration paths expose the documented outputs. Fixes: edc12763a3a29 ("clk: si521xx: Clock driver for Skyworks Si521xx I2C PCIe clock generators") Assisted-by: Codex:gpt-5 Signed-off-by: Pengpeng Hou Signed-off-by: Brian Masney --- drivers/clk/clk-si521xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c index cd0553796125..6e3c8e6ccc8d 100644 --- a/drivers/clk/clk-si521xx.c +++ b/drivers/clk/clk-si521xx.c @@ -374,7 +374,7 @@ MODULE_DEVICE_TABLE(i2c, si521xx_id); static const struct of_device_id clk_si521xx_of_match[] = { { .compatible = "skyworks,si52144", .data = (void *)SI521XX_OE_MAP(0x5, 0xc0) }, { .compatible = "skyworks,si52146", .data = (void *)SI521XX_OE_MAP(0x15, 0xe0) }, - { .compatible = "skyworks,si52147", .data = (void *)SI521XX_OE_MAP(0x15, 0xf8) }, + { .compatible = "skyworks,si52147", .data = (void *)SI521XX_OE_MAP(0x17, 0xf8) }, { } }; MODULE_DEVICE_TABLE(of, clk_si521xx_of_match); From 92d0998090d1716ee6b47174c10eb9415a12fca8 Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sun, 6 Sep 2026 11:39:24 +0800 Subject: [PATCH 088/168] clk: milbeaut: Return divider update timeouts m10v_clk_divider_set_rate() logs when the hardware does not clear its write-valid request, but still returns success to the clock framework. It also uses the sleeping poll helper while holding the divider spinlock. Use the atomic poll helper under the lock and return its timeout so the rate change is not reported as successful before the hardware accepts it. The issue was found by our static-analysis tool and manually reviewed. Fixes: 6a6ba5b55a72 ("clock: milbeaut: Add Milbeaut M10V clock controller") Assisted-by: gpt 5 Signed-off-by: Pengpeng Hou Signed-off-by: Brian Masney --- drivers/clk/clk-milbeaut.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk-milbeaut.c b/drivers/clk/clk-milbeaut.c index 485540b95528..29c1e5f68c7a 100644 --- a/drivers/clk/clk-milbeaut.c +++ b/drivers/clk/clk-milbeaut.c @@ -410,8 +410,8 @@ static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct m10v_clk_divider *divider = to_m10v_div(hw); - int value; unsigned long flags = 0; + int value, ret = 0; u32 val; u32 write_en = BIT(divider->width - 1); @@ -433,8 +433,10 @@ static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, if (divider->write_valid_reg) { writel(M10V_DCHREQ, divider->write_valid_reg); - if (readl_poll_timeout(divider->write_valid_reg, val, - !val, M10V_UPOLL_RATE, M10V_UTIMEOUT)) + ret = readl_poll_timeout_atomic(divider->write_valid_reg, val, + !val, M10V_UPOLL_RATE, + M10V_UTIMEOUT); + if (ret) pr_err("%s:%s couldn't stabilize\n", __func__, clk_hw_get_name(hw)); } @@ -444,7 +446,7 @@ static int m10v_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, else __release(divider->lock); - return 0; + return ret; } static const struct clk_ops m10v_clk_divider_ops = { From 4457ee2f99f7286d037ccde8c107481b6105fc15 Mon Sep 17 00:00:00 2001 From: Karl Mehltretter Date: Sun, 12 Jul 2026 18:03:01 +0200 Subject: [PATCH 089/168] clk: aspeed: ast2700: select AUXILIARY_BUS The AST2700 clock driver also exposes the SoC reset controller: it hands its register base to a reset auxiliary device via devm_auxiliary_device_create(), which the separate ASPEED reset driver (RESET_ASPEED) then binds to. That create call needs the auxiliary bus core (AUXILIARY_BUS), not the reset driver itself, but COMMON_CLK_AST2700 does not select AUXILIARY_BUS. It builds today only because RESET_ASPEED selects AUXILIARY_BUS and is normally enabled alongside the clock driver. On a randconfig with COMMON_CLK_AST2700=y and RESET_ASPEED=n, nothing pulls the auxiliary bus in and the kernel fails to link: ld: drivers/clk/aspeed/clk-ast2700.o: in function `ast2700_soc_clk_probe': clk-ast2700.c:(.text+0x147c): undefined reference to `__devm_auxiliary_device_create' Select AUXILIARY_BUS directly, as other clock drivers that create auxiliary devices do, so it builds regardless of the reset driver. Fixes: fdc1eb624ddc ("clk: aspeed: add AST2700 clock driver") Signed-off-by: Karl Mehltretter Reviewed-by: Brian Masney Reviewed-by: Andrew Jeffery Signed-off-by: Brian Masney --- drivers/clk/aspeed/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/aspeed/Kconfig b/drivers/clk/aspeed/Kconfig index ef50481c31ff..2f505eb3ca95 100644 --- a/drivers/clk/aspeed/Kconfig +++ b/drivers/clk/aspeed/Kconfig @@ -15,6 +15,7 @@ config COMMON_CLK_ASPEED config COMMON_CLK_AST2700 bool "Clock driver for AST2700 SoC" depends on ARCH_ASPEED || COMPILE_TEST + select AUXILIARY_BUS help This driver provides support for clock on AST2700 SoC. The driver is responsible for managing the various clocks required From e9e54518246f84aa07a12930a9f3d6f5b060eca2 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Fri, 11 Sep 2026 17:05:27 -0700 Subject: [PATCH 090/168] clk: actions: owl-pll: cast delay to unsigned long for udelay() The 'delay' field in struct owl_pll_hw is u8, but udelay() internally compares its argument against MAX_UDELAY_MS * 1000 (2000). Since a u8 can never exceed 255, the compiler warns of a tautological comparison that is always false: drivers/clk/actions/owl-pll.c:189:2: error: result of comparison of constant 2000 with expression of type 'u8' is always false Cast the delay value to unsigned long to widen the type and silence the W=1 warning without changing behavior. Assisted-by: LLM Signed-off-by: Rosen Penev Signed-off-by: Brian Masney --- drivers/clk/actions/owl-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/actions/owl-pll.c b/drivers/clk/actions/owl-pll.c index 869690b79cc1..5e30ce35f2f5 100644 --- a/drivers/clk/actions/owl-pll.c +++ b/drivers/clk/actions/owl-pll.c @@ -186,7 +186,7 @@ static int owl_pll_set_rate(struct clk_hw *hw, unsigned long rate, regmap_write(common->regmap, pll_hw->reg, reg); - udelay(pll_hw->delay); + udelay((unsigned long)pll_hw->delay); return 0; } From e98e3d712023859af7cd78bb7fdb87ea3a9ffb83 Mon Sep 17 00:00:00 2001 From: Triet Hoang Date: Fri, 18 Sep 2026 11:41:30 +0700 Subject: [PATCH 091/168] clk: raspberrypi: Handle cpufreq device registration failure Check the return value of platform_device_register_data() when registering the raspberrypi-cpufreq device and propagate the error if registration fails. This prevents the clock driver from reporting a successful probe when the cpufreq device could not be registered. Signed-off-by: Triet Hoang Reviewed-by: Stefan Wahren Fixes: e2bb18347c8e5 ("clk: raspberrypi: register platform device for raspberrypi-cpufreq") Signed-off-by: Brian Masney --- drivers/clk/bcm/clk-raspberrypi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index f1a99de6de4f..9882f243d681 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -553,6 +553,8 @@ static int raspberrypi_clk_probe(struct platform_device *pdev) rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq", -1, NULL, 0); + if (IS_ERR(rpi->cpufreq)) + return PTR_ERR(rpi->cpufreq); return 0; } From d27364c5db4f507cd9f3e7fb77c472fd69207256 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Mon, 11 May 2026 18:09:38 -0700 Subject: [PATCH 092/168] clk: pistachio: Use flexible array for clock table Store the clock lookup table in the Pistachio clock provider allocation instead of allocating it separately. This ties the table lifetime directly to the provider and removes a separate allocation failure path while preserving the clk_onecell_data lookup interface. Assisted-by: Codex:GPT-5.5 Signed-off-by: Rosen Penev Signed-off-by: Brian Masney --- drivers/clk/pistachio/clk.c | 15 ++++----------- drivers/clk/pistachio/clk.h | 1 + 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/clk/pistachio/clk.c b/drivers/clk/pistachio/clk.c index 80c722c77a1b..03e28779011f 100644 --- a/drivers/clk/pistachio/clk.c +++ b/drivers/clk/pistachio/clk.c @@ -17,28 +17,21 @@ pistachio_clk_alloc_provider(struct device_node *node, unsigned int num_clks) { struct pistachio_clk_provider *p; - p = kzalloc_obj(*p); + p = kzalloc_flex(*p, clks, num_clks); if (!p) return p; - p->clk_data.clks = kzalloc_objs(struct clk *, num_clks); - if (!p->clk_data.clks) - goto free_provider; + p->clk_data.clks = p->clks; p->clk_data.clk_num = num_clks; p->node = node; p->base = of_iomap(node, 0); if (!p->base) { pr_err("Failed to map clock provider registers\n"); - goto free_clks; + kfree(p); + return NULL; } return p; - -free_clks: - kfree(p->clk_data.clks); -free_provider: - kfree(p); - return NULL; } void pistachio_clk_register_provider(struct pistachio_clk_provider *p) diff --git a/drivers/clk/pistachio/clk.h b/drivers/clk/pistachio/clk.h index 2f4ffbd98282..1b9b311b9656 100644 --- a/drivers/clk/pistachio/clk.h +++ b/drivers/clk/pistachio/clk.h @@ -142,6 +142,7 @@ struct pistachio_clk_provider { struct device_node *node; void __iomem *base; struct clk_onecell_data clk_data; + struct clk *clks[]; }; extern struct pistachio_clk_provider * From c90a50d07f0c38c62ce13a60806ab5e3b841f70f Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Tue, 15 Sep 2026 07:01:03 +0000 Subject: [PATCH 093/168] clk: versatile: clk-icst: Fix node reference leak in of_syscon_icst_setup() of_get_parent() takes a reference on the syscon parent node. The reference is intentionally kept on the success path, but the error paths return without dropping it, leaking the node reference. Release the reference before returning on the error paths. Fixes: d430819d69a5 ("clk: versatile-icst: add device tree support") Signed-off-by: Wentao Liang Reviewed-by: Linus Walleij Signed-off-by: Brian Masney --- drivers/clk/versatile/clk-icst.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 97a1bfd6cf0e..37334afee040 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -516,16 +516,19 @@ static void __init of_syscon_icst_setup(struct device_node *np) map = syscon_node_to_regmap(parent); if (IS_ERR(map)) { pr_err("no regmap for syscon ICST clock parent\n"); + of_node_put(parent); return; } if (of_property_read_u32(np, "reg", &icst_desc.vco_offset) && of_property_read_u32(np, "vco-offset", &icst_desc.vco_offset)) { pr_err("no VCO register offset for ICST clock\n"); + of_node_put(parent); return; } if (of_property_read_u32(np, "lock-offset", &icst_desc.lock_offset)) { pr_err("no lock register offset for ICST clock\n"); + of_node_put(parent); return; } @@ -552,6 +555,7 @@ static void __init of_syscon_icst_setup(struct device_node *np) ctype = ICST_INTEGRATOR_CP_CM_MEM; } else { pr_err("unknown ICST clock %pOF\n", np); + of_node_put(parent); return; } From 54d0b6903921d121fa750546f2b38cc3f5c7e64f Mon Sep 17 00:00:00 2001 From: Slavin Liu Date: Sun, 13 Sep 2026 20:51:12 +0800 Subject: [PATCH 094/168] clk: starfive: jh7110: reject oscillator lookup errors Clock lookup may fail while allocating a consumer reference. Return a notifier error rather than passing ERR_PTR as the new clock parent. Detected by static analysis and reviewed with AI-assisted source auditing. Fixes: 538d5477b252 ("clk: starfive: jh7110-sys: Add notifier for PLL0 clock") Assisted-by: LLM Signed-off-by: Slavin Liu Signed-off-by: Brian Masney --- drivers/clk/starfive/clk-starfive-jh7110-sys.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/starfive/clk-starfive-jh7110-sys.c b/drivers/clk/starfive/clk-starfive-jh7110-sys.c index 03c17cd2032f..847c0a39e5ab 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c @@ -390,6 +390,9 @@ static int jh7110_pll0_clk_notifier_cb(struct notifier_block *nb, if (action == PRE_RATE_CHANGE) { struct clk *osc = clk_get(priv->dev, "osc"); + if (IS_ERR(osc)) + return notifier_from_errno(PTR_ERR(osc)); + priv->original_clk = clk_get_parent(cpu_root); ret = clk_set_parent(cpu_root, osc); clk_put(osc); From 802a1a97c41dff82a557223f7a43655fc02920bd Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Tue, 15 Sep 2026 00:05:43 +0100 Subject: [PATCH 095/168] clk: samsung: acpm: introduce driver data for SoC-specific clocks Currently, the ACPM clock driver hardcodes the GS101 clock variant arrays and counts directly in probe() routine. To support additional other SoCs (for instance Exynos850 SoC) that use the same ACPM protocol but have different clock trees, the driver needs to be more flexible. Introduce driver data attached to the platform_device_id table. Update the probe function to dynamically extract the clock lists, number of clocks, its names and mailbox channel id based on the matching device ID. Reviewed-by: Tudor Ambarus Signed-off-by: Alexey Klimov Link: https://patch.msgid.link/20260915-exynos850-acpm-clk-v2-1-ffad4a6b3fb1@linaro.org [krzk: Drop unneeded mod_devicetable.h] Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-acpm.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/clk/samsung/clk-acpm.c b/drivers/clk/samsung/clk-acpm.c index 7680bc8c5275..7ad151f61a79 100644 --- a/drivers/clk/samsung/clk-acpm.c +++ b/drivers/clk/samsung/clk-acpm.c @@ -101,6 +101,8 @@ static int acpm_clk_register(struct device *dev, struct acpm_clk *aclk, static int acpm_clk_probe(struct platform_device *pdev) { + const struct acpm_clk_driver_data *drv_data; + const struct platform_device_id *id; struct acpm_handle *acpm_handle; struct clk_hw_onecell_data *clk_data; struct clk_hw **hws; @@ -114,8 +116,14 @@ static int acpm_clk_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(acpm_handle), "Failed to get acpm handle\n"); - count = acpm_clk_gs101.nr_clks; - mbox_chan_id = acpm_clk_gs101.mbox_chan_id; + id = platform_get_device_id(pdev); + if (!id || !id->driver_data) + return -ENODEV; + + drv_data = (const struct acpm_clk_driver_data *)id->driver_data; + + count = drv_data->nr_clks; + mbox_chan_id = drv_data->mbox_chan_id; clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, count), GFP_KERNEL); @@ -142,8 +150,7 @@ static int acpm_clk_probe(struct platform_device *pdev) hws[i] = &aclk->hw; - err = acpm_clk_register(dev, aclk, - acpm_clk_gs101.clks[i].name); + err = acpm_clk_register(dev, aclk, drv_data->clks[i].name); if (err) return dev_err_probe(dev, err, "Failed to register clock\n"); @@ -154,7 +161,7 @@ static int acpm_clk_probe(struct platform_device *pdev) } static const struct platform_device_id acpm_clk_id[] = { - { .name = "gs101-acpm-clk" }, + { .name = "gs101-acpm-clk", (kernel_ulong_t)&acpm_clk_gs101 }, { } }; MODULE_DEVICE_TABLE(platform, acpm_clk_id); From 13634cde9771811488847ef76cd64a785599fdb5 Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Tue, 15 Sep 2026 00:05:44 +0100 Subject: [PATCH 096/168] clk: samsung: acpm: add Exynos850 support The Exynos850 SoC utilizes the APM co-processor for clock management via ACPM, similar to the GS101 SoC. Add the Exynos850-specific clock variant array (including mif, int, cpucl0, cpucl1, g3d, aud, cam, disp, and cp) and wire it up to the driver data infrastructure. Add the "exynos850-acpm-clk" device ID to enable dynamic instantiation of these clocks during probe(). Unlike GS101, the ACPM firmware on Exynos850 does not implement a dynamic rate read call over ACPM IPC. To return sane clock rate in ->recalc_rate introduce a SoC-specific ->get_rate() driver data callback. For Exynos850, this falls back to reading the upstream parent CMU clock rate. When ->get_rate() is set, populate pdata.fw_name during clock registration to let clock framework to link the parent clock. Signed-off-by: Alexey Klimov Link: https://patch.msgid.link/20260915-exynos850-acpm-clk-v2-2-ffad4a6b3fb1@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/clk/samsung/clk-acpm.c | 46 ++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/clk/samsung/clk-acpm.c b/drivers/clk/samsung/clk-acpm.c index 7ad151f61a79..e5a2d3ab34cb 100644 --- a/drivers/clk/samsung/clk-acpm.c +++ b/drivers/clk/samsung/clk-acpm.c @@ -21,6 +21,7 @@ struct acpm_clk { struct clk_hw hw; unsigned int mbox_chan_id; struct acpm_handle *handle; + const struct acpm_clk_driver_data *drv_data; }; struct acpm_clk_variant { @@ -31,6 +32,8 @@ struct acpm_clk_driver_data { const struct acpm_clk_variant *clks; unsigned int nr_clks; unsigned int mbox_chan_id; + /* For SoCs where ACPM firmware doesn't implement get_rate call */ + unsigned long (*get_rate)(struct clk_hw *clk, unsigned long parent_rate); }; #define to_acpm_clk(clk) container_of(clk, struct acpm_clk, hw) @@ -40,6 +43,18 @@ struct acpm_clk_driver_data { .name = cname, \ } +static const struct acpm_clk_variant exynos850_acpm_clks[] = { + ACPM_CLK("mif"), + ACPM_CLK("int"), + ACPM_CLK("cpucl0"), + ACPM_CLK("cpucl1"), + ACPM_CLK("g3d"), + ACPM_CLK("aud"), + ACPM_CLK("cam"), + ACPM_CLK("disp"), + ACPM_CLK("cp"), +}; + static const struct acpm_clk_variant gs101_acpm_clks[] = { ACPM_CLK("mif"), ACPM_CLK("int"), @@ -57,6 +72,19 @@ static const struct acpm_clk_variant gs101_acpm_clks[] = { ACPM_CLK("bo"), }; +static unsigned long bypass_acpm_exynos850_get_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate; +} + +static const struct acpm_clk_driver_data acpm_clk_exynos850 = { + .clks = exynos850_acpm_clks, + .nr_clks = ARRAY_SIZE(exynos850_acpm_clks), + .mbox_chan_id = 0, + .get_rate = bypass_acpm_exynos850_get_rate, +}; + static const struct acpm_clk_driver_data acpm_clk_gs101 = { .clks = gs101_acpm_clks, .nr_clks = ARRAY_SIZE(gs101_acpm_clks), @@ -68,6 +96,9 @@ static unsigned long acpm_clk_recalc_rate(struct clk_hw *hw, { struct acpm_clk *clk = to_acpm_clk(hw); + if (clk->drv_data->get_rate) + return clk->drv_data->get_rate(hw, parent_rate); + return clk->handle->ops->dvfs.get_rate(clk->handle, clk->mbox_chan_id, clk->id); } @@ -88,14 +119,23 @@ static const struct clk_ops acpm_clk_ops = { }; static int acpm_clk_register(struct device *dev, struct acpm_clk *aclk, - const char *name) + const char *name, const struct acpm_clk_driver_data *drv_data) { struct clk_init_data init = {}; + struct clk_parent_data pdata = {}; init.name = name; init.ops = &acpm_clk_ops; aclk->hw.init = &init; + /* If get_rate is set, the SoC relies on parent topology */ + if (drv_data->get_rate) { + pdata.fw_name = name; + init.parent_data = &pdata; + init.num_parents = 1; + init.flags = CLK_GET_RATE_NOCACHE; + } + return devm_clk_hw_register(dev, &aclk->hw); } @@ -144,13 +184,14 @@ static int acpm_clk_probe(struct platform_device *pdev) * The code assumes the clock IDs start from zero, * are sequential and do not have gaps. */ + aclk->drv_data = drv_data; aclk->id = i; aclk->handle = acpm_handle; aclk->mbox_chan_id = mbox_chan_id; hws[i] = &aclk->hw; - err = acpm_clk_register(dev, aclk, drv_data->clks[i].name); + err = acpm_clk_register(dev, aclk, drv_data->clks[i].name, drv_data); if (err) return dev_err_probe(dev, err, "Failed to register clock\n"); @@ -161,6 +202,7 @@ static int acpm_clk_probe(struct platform_device *pdev) } static const struct platform_device_id acpm_clk_id[] = { + { .name = "exynos850-acpm-clk", (kernel_ulong_t)&acpm_clk_exynos850 }, { .name = "gs101-acpm-clk", (kernel_ulong_t)&acpm_clk_gs101 }, { } }; From c6a0f5f53cb997196e56acaf50321f2fc40d657b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 16 Sep 2026 01:53:52 +0000 Subject: [PATCH 097/168] clk: renesas: rcar-gen4: Tidy up DEF_GEN4_Z() Current DEF_GEN4_Z() is using .offset to get "reg" and "pos", but the offset positions and calculations differ from intuition (the registers are located in the order B -> C0 -> C1, but it is using C0 -> C1 -> B). Tidy them up. Include CLK_TYPE_GEN4_Z in DEF_GEN4_Z(), as it is duplicated everywhere else. Signed-off-by: Kuninori Morimoto Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/87a4pivu4v.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a779a0-cpg-mssr.c | 6 +++--- drivers/clk/renesas/r8a779f0-cpg-mssr.c | 4 ++-- drivers/clk/renesas/r8a779g0-cpg-mssr.c | 2 +- drivers/clk/renesas/r8a779h0-cpg-mssr.c | 8 ++++---- drivers/clk/renesas/rcar-gen4-cpg.c | 25 +++++++++++-------------- drivers/clk/renesas/rcar-gen4-cpg.h | 14 ++++++++++++-- 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index d67dff05d9f4..a18a51dab64f 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -99,9 +99,9 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN4_RPCSRC, CLK_PLL5), /* Core Clock Outputs */ - DEF_GEN4_Z("z0", R8A779A0_CLK_Z0, CLK_TYPE_GEN4_Z, CLK_PLL20, 2, 0), - DEF_GEN4_Z("z1", R8A779A0_CLK_Z1, CLK_TYPE_GEN4_Z, CLK_PLL21, 2, 8), - DEF_GEN4_Z("zg", R8A779A0_CLK_ZG, CLK_TYPE_GEN4_Z, CLK_PLL4, 2, 88), + DEF_GEN4_Z("z0", R8A779A0_CLK_Z0, CLK_PLL20, 2, CPG_FRQCRC0, 0), + DEF_GEN4_Z("z1", R8A779A0_CLK_Z1, CLK_PLL21, 2, CPG_FRQCRC0, 8), + DEF_GEN4_Z("zg", R8A779A0_CLK_ZG, CLK_PLL4, 2, CPG_FRQCRB, 24), DEF_FIXED("zx", R8A779A0_CLK_ZX, CLK_PLL20_DIV2, 2, 1), DEF_FIXED("s1d1", R8A779A0_CLK_S1D1, CLK_S1, 1, 1), DEF_FIXED("s1d2", R8A779A0_CLK_S1D2, CLK_S1, 2, 1), diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c index f33342314b2e..1264c3fc50aa 100644 --- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c @@ -79,8 +79,8 @@ static const struct cpg_core_clk r8a779f0_core_clks[] __initconst = { DEF_BASE(".rpcsrc", CLK_RPCSRC, CLK_TYPE_GEN4_RPCSRC, CLK_PLL5), /* Core Clock Outputs */ - DEF_GEN4_Z("z0", R8A779F0_CLK_Z0, CLK_TYPE_GEN4_Z, CLK_PLL2, 2, 0), - DEF_GEN4_Z("z1", R8A779F0_CLK_Z1, CLK_TYPE_GEN4_Z, CLK_PLL2, 2, 8), + DEF_GEN4_Z("z0", R8A779F0_CLK_Z0, CLK_PLL2, 2, CPG_FRQCRC0, 0), + DEF_GEN4_Z("z1", R8A779F0_CLK_Z1, CLK_PLL2, 2, CPG_FRQCRC0, 8), DEF_FIXED("s0d2", R8A779F0_CLK_S0D2, CLK_S0, 2, 1), DEF_FIXED("s0d3", R8A779F0_CLK_S0D3, CLK_S0, 3, 1), DEF_FIXED("s0d4", R8A779F0_CLK_S0D4, CLK_S0, 4, 1), diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c index 54ba76ff5ab0..eaa5f930e06f 100644 --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c @@ -96,7 +96,7 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = { DEF_FIXED(".vc", CLK_VC, CLK_PLL5_DIV2, 3, 1), /* Core Clock Outputs */ - DEF_GEN4_Z("z0", R8A779G0_CLK_Z0, CLK_TYPE_GEN4_Z, CLK_PLL2, 2, 0), + DEF_GEN4_Z("z0", R8A779G0_CLK_Z0, CLK_PLL2, 2, CPG_FRQCRC0, 0), DEF_FIXED("s0d2", R8A779G0_CLK_S0D2, CLK_S0, 2, 1), DEF_FIXED("s0d3", R8A779G0_CLK_S0D3, CLK_S0, 3, 1), DEF_FIXED("s0d4", R8A779G0_CLK_S0D4, CLK_S0, 4, 1), diff --git a/drivers/clk/renesas/r8a779h0-cpg-mssr.c b/drivers/clk/renesas/r8a779h0-cpg-mssr.c index ffea06d77d5e..cde59cd35295 100644 --- a/drivers/clk/renesas/r8a779h0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779h0-cpg-mssr.c @@ -99,10 +99,10 @@ static const struct cpg_core_clk r8a779h0_core_clks[] __initconst = { DEF_RATE(".oco", CLK_OCO, 32768), /* Core Clock Outputs */ - DEF_GEN4_Z("zc0", R8A779H0_CLK_ZC0, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 0), - DEF_GEN4_Z("zc1", R8A779H0_CLK_ZC1, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 8), - DEF_GEN4_Z("zc2", R8A779H0_CLK_ZC2, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 32), - DEF_GEN4_Z("zc3", R8A779H0_CLK_ZC3, CLK_TYPE_GEN4_Z, CLK_PLL2, 4, 40), + DEF_GEN4_Z("zc0", R8A779H0_CLK_ZC0, CLK_PLL2, 4, CPG_FRQCRC0, 0), + DEF_GEN4_Z("zc1", R8A779H0_CLK_ZC1, CLK_PLL2, 4, CPG_FRQCRC0, 8), + DEF_GEN4_Z("zc2", R8A779H0_CLK_ZC2, CLK_PLL2, 4, CPG_FRQCRC1, 0), + DEF_GEN4_Z("zc3", R8A779H0_CLK_ZC3, CLK_PLL2, 4, CPG_FRQCRC1, 8), DEF_FIXED("s0d2", R8A779H0_CLK_S0D2, CLK_S0, 2, 1), DEF_FIXED("s0d3", R8A779H0_CLK_S0D3, CLK_S0, 3, 1), DEF_FIXED("s0d4", R8A779H0_CLK_S0D4, CLK_S0, 4, 1), diff --git a/drivers/clk/renesas/rcar-gen4-cpg.c b/drivers/clk/renesas/rcar-gen4-cpg.c index 96922789e02a..dd973e4feb1b 100644 --- a/drivers/clk/renesas/rcar-gen4-cpg.c +++ b/drivers/clk/renesas/rcar-gen4-cpg.c @@ -259,10 +259,7 @@ static struct clk * __init cpg_pll_clk_register(const char *name, /* * Z0, Z1 and ZG Clock */ -#define CPG_FRQCRB 0x00000804 #define CPG_FRQCRB_KICK BIT(31) -#define CPG_FRQCRC0 0x00000808 -#define CPG_FRQCRC1 0x000008e0 struct cpg_z_clk { struct clk_hw hw; @@ -384,17 +381,17 @@ static struct clk * __init cpg_z_clk_register(const char *name, init.parent_names = &parent_name; init.num_parents = 1; - if (offset < 32) { - zclk->reg = reg + CPG_FRQCRC0; - } else if (offset < 64) { - zclk->reg = reg + CPG_FRQCRC1; - offset -= 32; - } else if (offset < 96) { - zclk->reg = reg + CPG_FRQCRB; - offset -= 64; - } else { - return ERR_PTR(-EINVAL); - } + /* + * offset 0xAAABB + * AAA : reg + * BB : pos + * + * see + * DEF_GEN4_Z() + */ + zclk->reg = reg + (offset >> FRQCR_offset); + offset &= 0x1f; /* 0 - 31 */ + zclk->kick_reg = reg + CPG_FRQCRB; zclk->hw.init = &init; zclk->mask = GENMASK(offset + 4, offset); diff --git a/drivers/clk/renesas/rcar-gen4-cpg.h b/drivers/clk/renesas/rcar-gen4-cpg.h index 6c8280b37c37..3556cf31ee8f 100644 --- a/drivers/clk/renesas/rcar-gen4-cpg.h +++ b/drivers/clk/renesas/rcar-gen4-cpg.h @@ -58,8 +58,15 @@ enum rcar_gen4_clk_types { #define DEF_GEN4_PLL_V9_24(_name, _idx, _id, _parent) \ DEF_BASE(_name, _id, CLK_TYPE_GEN4_PLL_V9_24, _parent, .offset = _idx) -#define DEF_GEN4_Z(_name, _id, _type, _parent, _div, _offset) \ - DEF_BASE(_name, _id, _type, _parent, .div = _div, .offset = _offset) +/* + * offset 0xAAABB + * AAA : reg + * BB : pos + */ +#define FRQCR_offset 8 +#define DEF_GEN4_Z(_name, _id, _parent, _div, reg, pos) \ + DEF_BASE(_name, _id, CLK_TYPE_GEN4_Z, _parent, .div = _div, \ + .offset = ((reg) << FRQCR_offset) | (pos)) struct rcar_gen4_cpg_pll_config { u8 extal_div; @@ -70,6 +77,9 @@ struct rcar_gen4_cpg_pll_config { u8 osc_prediv; }; +#define CPG_FRQCRB 0x804 /* Frequency Control Register B */ +#define CPG_FRQCRC0 0x808 /* Frequency Control Register C0 */ +#define CPG_FRQCRC1 0x8e0 /* Frequency Control Register C1 */ #define CPG_SD0CKCR 0x870 /* SD-IF0 Clock Frequency Control Register */ #define CPG_CANFDCKCR 0x878 /* CAN-FD Clock Frequency Control Register */ #define CPG_MSOCKCR 0x87c /* MSIOF Clock Frequency Control Register */ From b3973f385a7e735f3827aae70b618b465b828772 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 16 Sep 2026 01:53:57 +0000 Subject: [PATCH 098/168] clk: renesas: r8a779g0: Add ZG clocks Add ZG related clocks for GSX. Signed-off-by: Anh Nguyen Signed-off-by: Kuninori Morimoto Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/878q52vu4q.wl-kuninori.morimoto.gx@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r8a779g0-cpg-mssr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c index eaa5f930e06f..9a649f2524d9 100644 --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c @@ -97,6 +97,7 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = { /* Core Clock Outputs */ DEF_GEN4_Z("z0", R8A779G0_CLK_Z0, CLK_PLL2, 2, CPG_FRQCRC0, 0), + DEF_GEN4_Z("zg", R8A779G0_CLK_ZG, CLK_PLL4, 2, CPG_FRQCRB, 24), DEF_FIXED("s0d2", R8A779G0_CLK_S0D2, CLK_S0, 2, 1), DEF_FIXED("s0d3", R8A779G0_CLK_S0D3, CLK_S0, 3, 1), DEF_FIXED("s0d4", R8A779G0_CLK_S0D4, CLK_S0, 4, 1), @@ -163,6 +164,7 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { + DEF_MOD("rgx", 0, R8A779G0_CLK_ZG), DEF_MOD("isp0", 16, R8A779G0_CLK_S0D2_VIO), DEF_MOD("isp1", 17, R8A779G0_CLK_S0D2_VIO), DEF_MOD("avb0", 211, R8A779G0_CLK_S0D4_HSC), From 11952173d8a180ac05641775f80bd6946327478f Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 15 Sep 2026 14:52:23 +0200 Subject: [PATCH 099/168] dt-bindings: clock: airoha: Add PHY binding for Serdes port Add PHY cell property for Serdes port selection. Currently supported only for Airoha AN7581 SoC, that support up to 4 Serdes port. The Serdes port can support both PCIe, USB3 or Ethernet mode. - PCIe1 Serdes can support PCIe or Ethernet mode. - PCIe2 Serdes can support PCIe or Ethernet mode. - USB1 Serdes can support USB3 or HSGMII mode. - USB2 Serdes can support USB3 or PCIe mode. Add bindings to permit correct reference of the Serdes ports in DT. Values are just symbolic and enumerates the Serdes port with a specific number for precise reference. The available Serdes port can be selected following the dt-binding header in [2]. [2] Signed-off-by: Christian Marangi Reviewed-by: Rob Herring (Arm) Signed-off-by: Brian Masney --- .../bindings/clock/airoha,en7523-scu.yaml | 24 ++++++++++++++++--- include/dt-bindings/soc/airoha,scu-ssr.h | 11 +++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 include/dt-bindings/soc/airoha,scu-ssr.h diff --git a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml index eb24a5687639..fc37786ac7ed 100644 --- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml +++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml @@ -23,6 +23,7 @@ description: | All these identifiers can be found in: [1]: . + [2]: . The clocks are provided inside a system controller node. @@ -50,6 +51,12 @@ properties: description: ID of the controller reset line const: 1 + '#phy-cells': + description: + The first cell indicates the serdes phy number, see [2] for the + available serdes port. + const: 1 + required: - compatible - reg @@ -65,12 +72,23 @@ allOf: reg: minItems: 2 + '#phy-cells': false + - if: properties: compatible: - enum: - - airoha,en7581-scu - - econet,en751221-scu + const: econet,en751221-scu + then: + properties: + reg: + maxItems: 1 + + '#phy-cells': false + + - if: + properties: + compatible: + const: airoha,en7581-scu then: properties: reg: diff --git a/include/dt-bindings/soc/airoha,scu-ssr.h b/include/dt-bindings/soc/airoha,scu-ssr.h new file mode 100644 index 000000000000..33c64844ada3 --- /dev/null +++ b/include/dt-bindings/soc/airoha,scu-ssr.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ + +#ifndef __DT_BINDINGS_AIROHA_SCU_SSR_H +#define __DT_BINDINGS_AIROHA_SCU_SSR_H + +#define AIROHA_SCU_SERDES_PCIE1 0 +#define AIROHA_SCU_SERDES_PCIE2 1 +#define AIROHA_SCU_SERDES_USB1 2 +#define AIROHA_SCU_SERDES_USB2 3 + +#endif /* __DT_BINDINGS_AIROHA_SCU_SSR_H */ From 4e39820b601221997cb2220edc830f92367cdfc2 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Tue, 15 Sep 2026 14:52:24 +0200 Subject: [PATCH 100/168] clk: en7523: Add support for selecting the Serdes port in SCU In the SCU register for clock and reset, there are also some register to select the Serdes port mode. The Airoha AN7581 SoC have 4 different Serdes that can switch between PCIe, USB or Ethernet mode. Add a simple PHY provider that expose the .set_mode OP to toggle the requested mode for the Serdes port. Reviewed-by: Brian Masney Signed-off-by: Christian Marangi Signed-off-by: Brian Masney --- drivers/clk/Kconfig | 1 + drivers/clk/clk-en7523.c | 218 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 216 insertions(+), 3 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 252f6a1f21b8..e0cc4ebafb5e 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -221,6 +221,7 @@ config COMMON_CLK_EN7523 bool "Clock driver for Airoha/EcoNet SoC system clocks" depends on OF depends on ARCH_AIROHA || ECONET || COMPILE_TEST + select GENERIC_PHY default ARCH_AIROHA help This driver provides the fixed clocks and gates present on Airoha diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c index 5c45aacb6409..24fdec2e6198 100644 --- a/drivers/clk/clk-en7523.c +++ b/drivers/clk/clk-en7523.c @@ -6,14 +6,18 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include #include #include +#include #define RST_NR_PER_BANK 32 @@ -40,9 +44,22 @@ #define REG_HIR_MASK GENMASK(31, 16) /* EN7581 */ #define REG_NP_SCU_PCIC 0x88 +#define REG_NP_SCU_SSR3 0x94 +#define REG_SSUSB_HSGMII_SEL_MASK BIT(29) +#define REG_SSUSB_HSGMII_SEL_HSGMII FIELD_PREP_CONST(REG_SSUSB_HSGMII_SEL_MASK, 0x0) +#define REG_SSUSB_HSGMII_SEL_USB FIELD_PREP_CONST(REG_SSUSB_HSGMII_SEL_MASK, 0x1) #define REG_NP_SCU_SSTR 0x9c #define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13) +#define REG_PCIE_XSI0_SEL_PCIE FIELD_PREP_CONST(REG_PCIE_XSI0_SEL_MASK, 0x0) +#define REG_PCIE_XSI0_SEL_XFI FIELD_PREP_CONST(REG_PCIE_XSI0_SEL_MASK, 0x1) +#define REG_PCIE_XSI0_SEL_HSGMII FIELD_PREP_CONST(REG_PCIE_XSI0_SEL_MASK, 0x2) #define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11) +#define REG_PCIE_XSI1_SEL_PCIE FIELD_PREP_CONST(REG_PCIE_XSI1_SEL_MASK, 0x0) +#define REG_PCIE_XSI1_SEL_XFI FIELD_PREP_CONST(REG_PCIE_XSI1_SEL_MASK, 0x1) +#define REG_PCIE_XSI1_SEL_HSGMII FIELD_PREP_CONST(REG_PCIE_XSI1_SEL_MASK, 0x2) +#define REG_USB_PCIE_SEL_MASK BIT(3) +#define REG_USB_PCIE_SEL_PCIE FIELD_PREP_CONST(REG_USB_PCIE_SEL_MASK, 0x0) +#define REG_USB_PCIE_SEL_USB FIELD_PREP_CONST(REG_USB_PCIE_SEL_MASK, 0x1) #define REG_CRYPTO_CLKSRC2 0x20c /* EN751221 */ #define EN751221_REG_SPI_DIV 0x0cc @@ -82,6 +99,8 @@ enum en_hir { HIR_MAX = 14, }; +#define EN_SERDES_PHY_NUM 4 + struct en_clk_desc { int id; const char *name; @@ -114,6 +133,18 @@ struct en_rst_data { struct reset_controller_dev rcdev; }; +struct en_serdes_phy_instance { + struct phy *phy; + unsigned int serdes_port; +}; + +struct en_clk_priv { + void __iomem *base; + /* protect SCU register */ + spinlock_t lock; + struct en_serdes_phy_instance *serdes_phys[EN_SERDES_PHY_NUM]; +}; + struct en_clk_soc_data { u32 num_clocks; const struct clk_ops pcie_ops; @@ -847,12 +878,179 @@ static int en7581_reset_register(struct device *dev, void __iomem *base, return devm_reset_controller_register(dev, &rst_data->rcdev); } +static int en7581_serdes_phy_set_mode(struct phy *phy, enum phy_mode mode, + int submode) +{ + struct en_serdes_phy_instance *instance = phy_get_drvdata(phy); + struct en_clk_priv *priv = dev_get_drvdata(phy->dev.parent); + u32 reg, mask, sel, val; + unsigned long flags; + + switch (instance->serdes_port) { + case AIROHA_SCU_SERDES_PCIE1: + reg = REG_NP_SCU_SSTR; + mask = REG_PCIE_XSI0_SEL_MASK; + + if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_PCIE) + return -EINVAL; + + if (mode == PHY_MODE_ETHERNET) { + switch (submode) { + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_10GBASER: + sel = REG_PCIE_XSI0_SEL_XFI; + break; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + sel = REG_PCIE_XSI0_SEL_HSGMII; + break; + default: + return -EINVAL; + } + } else { + sel = REG_PCIE_XSI0_SEL_PCIE; + } + + break; + case AIROHA_SCU_SERDES_PCIE2: + reg = REG_NP_SCU_SSTR; + mask = REG_PCIE_XSI1_SEL_MASK; + + if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_PCIE) + return -EINVAL; + + if (mode == PHY_MODE_ETHERNET) { + switch (submode) { + case PHY_INTERFACE_MODE_USXGMII: + case PHY_INTERFACE_MODE_10GBASER: + sel = REG_PCIE_XSI1_SEL_XFI; + break; + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + sel = REG_PCIE_XSI1_SEL_HSGMII; + break; + default: + return -EINVAL; + } + } else { + sel = REG_PCIE_XSI1_SEL_PCIE; + } + + break; + case AIROHA_SCU_SERDES_USB1: + reg = REG_NP_SCU_SSR3; + mask = REG_SSUSB_HSGMII_SEL_MASK; + + if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_USB_DEVICE && + mode != PHY_MODE_USB_DEVICE_SS) + return -EINVAL; + + if (mode == PHY_MODE_ETHERNET) + sel = REG_SSUSB_HSGMII_SEL_HSGMII; + else + sel = REG_SSUSB_HSGMII_SEL_USB; + + break; + case AIROHA_SCU_SERDES_USB2: + reg = REG_NP_SCU_SSTR; + mask = REG_USB_PCIE_SEL_MASK; + + if (mode != PHY_MODE_PCIE && mode != PHY_MODE_USB_DEVICE && + mode != PHY_MODE_USB_DEVICE_SS) + return -EINVAL; + + if (mode == PHY_MODE_PCIE) + sel = REG_USB_PCIE_SEL_PCIE; + else + sel = REG_USB_PCIE_SEL_USB; + + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&priv->lock, flags); + val = readl(priv->base + reg); + val &= ~mask; + val |= sel; + writel(val, priv->base + reg); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static const struct phy_ops en7581_serdes_phy_ops = { + .set_mode = en7581_serdes_phy_set_mode, + .owner = THIS_MODULE, +}; + +static struct phy *en7581_serdes_phy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct en_clk_priv *priv = dev_get_drvdata(dev); + struct en_serdes_phy_instance *instance; + unsigned int serdes_port; + + if (args->args_count != 1) { + dev_err(dev, "invalid number of cells in 'phy' property\n"); + return ERR_PTR(-EINVAL); + } + + serdes_port = args->args[0]; + if (serdes_port >= EN_SERDES_PHY_NUM) { + dev_err(dev, "invalid serdes port: %d\n", serdes_port); + return ERR_PTR(-EINVAL); + } + + instance = priv->serdes_phys[serdes_port]; + if (!instance) { + dev_err(dev, "failed to find appropriate serdes phy\n"); + return ERR_PTR(-EINVAL); + } + + return instance->phy; +} + +static int en7581_serdes_phy_register(struct device *dev) +{ + struct en_clk_priv *priv = dev_get_drvdata(dev); + struct phy_provider *phy_provider; + int i; + + for (i = 0; i < EN_SERDES_PHY_NUM; i++) { + struct en_serdes_phy_instance *instance; + + instance = devm_kzalloc(dev, sizeof(*instance), + GFP_KERNEL); + if (!instance) + return -ENOMEM; + + instance->phy = devm_phy_create(dev, NULL, + &en7581_serdes_phy_ops); + if (IS_ERR(instance->phy)) + return dev_err_probe(dev, PTR_ERR(instance->phy), "failed to create phy\n"); + + instance->serdes_port = i; + priv->serdes_phys[i] = instance; + + phy_set_drvdata(instance->phy, instance); + } + + phy_provider = devm_of_phy_provider_register(dev, en7581_serdes_phy_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + static int en7581_clk_hw_init(struct platform_device *pdev, struct clk_hw_onecell_data *clk_data) { + struct en_clk_priv *priv = platform_get_drvdata(pdev); struct regmap *map; void __iomem *base; u32 val; + int ret; map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu"); if (IS_ERR(map)) @@ -862,6 +1060,8 @@ static int en7581_clk_hw_init(struct platform_device *pdev, if (IS_ERR(base)) return PTR_ERR(base); + priv->base = base; + en7581_register_clocks(&pdev->dev, clk_data, map, base); val = readl(base + REG_NP_SCU_SSTR); @@ -876,9 +1076,12 @@ static int en7581_clk_hw_init(struct platform_device *pdev, val &= ~REG_PCIE_HB_RST; writel(val, base + REG_RST_CTRL1); - return en7581_reset_register(&pdev->dev, base, en7581_rst_map, - ARRAY_SIZE(en7581_rst_map), - en7581_rst_ofs); + ret = en7581_reset_register(&pdev->dev, base, en7581_rst_map, + ARRAY_SIZE(en7581_rst_map), en7581_rst_ofs); + if (ret) + return ret; + + return en7581_serdes_phy_register(&pdev->dev); } static enum en_hir get_hw_id(void __iomem *np_base) @@ -985,16 +1188,25 @@ static int en7523_clk_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; const struct en_clk_soc_data *soc_data; struct clk_hw_onecell_data *clk_data; + struct en_clk_priv *priv; int r; soc_data = device_get_match_data(&pdev->dev); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hws, soc_data->num_clocks), GFP_KERNEL); if (!clk_data) return -ENOMEM; + platform_set_drvdata(pdev, priv); + clk_data->num = soc_data->num_clocks; r = soc_data->hw_init(pdev, clk_data); if (r) From 45a68afbd4b632538a0956ba783fca45b8ceb446 Mon Sep 17 00:00:00 2001 From: Georgios Androutsopoulos Date: Tue, 8 Sep 2026 18:56:15 -0400 Subject: [PATCH 101/168] rust: clk: document overflow panics in `Hertz` constructors `Hertz::from_khz()`, `from_mhz()` and `from_ghz()` multiply their argument by 1_000, 1_000_000 and 1_000_000_000 respectively without checking for overflow. When `CONFIG_RUST_OVERFLOW_CHECKS` is enabled, each panics once its argument exceeds `c_ulong::MAX` divided by that factor. None of the three documents this. The panic occurs only at runtime, when the argument is not a constant expression. Add the missing `# Panics` sections stating the bound for each unit. Fixes: d01d70205601 ("rust: clk: Add initial abstractions") Signed-off-by: Georgios Androutsopoulos Reviewed-by: Alexandre Courbot Acked-by: Miguel Ojeda Signed-off-by: Brian Masney --- rust/kernel/clk.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs index 7abbd0767d8c..f04f5c4a03d6 100644 --- a/rust/kernel/clk.rs +++ b/rust/kernel/clk.rs @@ -35,16 +35,31 @@ impl Hertz { const GHZ_TO_HZ: c_ulong = 1_000_000_000; /// Create a new instance from kilohertz (kHz) + /// + /// # Panics + /// + /// Panics if `CONFIG_RUST_OVERFLOW_CHECKS` is enabled and `khz` is greater + /// than `c_ulong::MAX / 1_000`. pub const fn from_khz(khz: c_ulong) -> Self { Self(khz * Self::KHZ_TO_HZ) } /// Create a new instance from megahertz (MHz) + /// + /// # Panics + /// + /// Panics if `CONFIG_RUST_OVERFLOW_CHECKS` is enabled and `mhz` is greater + /// than `c_ulong::MAX / 1_000_000`. pub const fn from_mhz(mhz: c_ulong) -> Self { Self(mhz * Self::MHZ_TO_HZ) } /// Create a new instance from gigahertz (GHz) + /// + /// # Panics + /// + /// Panics if `CONFIG_RUST_OVERFLOW_CHECKS` is enabled and `ghz` is greater + /// than `c_ulong::MAX / 1_000_000_000`. pub const fn from_ghz(ghz: c_ulong) -> Self { Self(ghz * Self::GHZ_TO_HZ) } From 48138c57fc8adff248e8ec6c6f414f011f1b6bfe Mon Sep 17 00:00:00 2001 From: Ayman Chaudhry Date: Mon, 21 Sep 2026 13:44:25 +0000 Subject: [PATCH 102/168] dt-bindings: clock: Add r8a774a3 CPG Core Clock definitions Add all the Renesas RZ/G2M v3.0 (a.k.a. R8A774A3) SoC Clock Pulse Generator Core Clock Outputs, as listed in Table 11.3 ("List of Clocks [RZ/G2M V1.3, RZ/G2M V3.0]") of the RZ/G2 Hardware User's Manual. Signed-off-by: Ayman Chaudhry Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260921134432.50338-6-ayman.chaudhry.kc@renesas.com Signed-off-by: Geert Uytterhoeven --- .../clock/renesas,r8a774a3-cpg-mssr.h | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 include/dt-bindings/clock/renesas,r8a774a3-cpg-mssr.h diff --git a/include/dt-bindings/clock/renesas,r8a774a3-cpg-mssr.h b/include/dt-bindings/clock/renesas,r8a774a3-cpg-mssr.h new file mode 100644 index 000000000000..09121a30e066 --- /dev/null +++ b/include/dt-bindings/clock/renesas,r8a774a3-cpg-mssr.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + */ +#ifndef __DT_BINDINGS_CLOCK_RENESAS_R8A774A3_CPG_MSSR_H__ +#define __DT_BINDINGS_CLOCK_RENESAS_R8A774A3_CPG_MSSR_H__ + +#include + +/* r8a774a3 CPG Core Clocks */ +#define R8A774A3_CLK_Z 0 +#define R8A774A3_CLK_Z2 1 +#define R8A774A3_CLK_ZG 2 +#define R8A774A3_CLK_ZTR 3 +#define R8A774A3_CLK_ZTRD2 4 +#define R8A774A3_CLK_ZT 5 +#define R8A774A3_CLK_ZX 6 +#define R8A774A3_CLK_S0D1 7 +#define R8A774A3_CLK_S0D2 8 +#define R8A774A3_CLK_S0D3 9 +#define R8A774A3_CLK_S0D4 10 +#define R8A774A3_CLK_S0D6 11 +#define R8A774A3_CLK_S0D8 12 +#define R8A774A3_CLK_S0D12 13 +#define R8A774A3_CLK_S1D2 14 +#define R8A774A3_CLK_S1D4 15 +#define R8A774A3_CLK_S2D1 16 +#define R8A774A3_CLK_S2D2 17 +#define R8A774A3_CLK_S2D4 18 +#define R8A774A3_CLK_S3D1 19 +#define R8A774A3_CLK_S3D2 20 +#define R8A774A3_CLK_S3D4 21 +#define R8A774A3_CLK_LB 22 +#define R8A774A3_CLK_CL 23 +#define R8A774A3_CLK_ZB3 24 +#define R8A774A3_CLK_ZB3D2 25 +#define R8A774A3_CLK_ZB3D4 26 +#define R8A774A3_CLK_CR 27 +#define R8A774A3_CLK_CRD2 28 +#define R8A774A3_CLK_SD0H 29 +#define R8A774A3_CLK_SD0 30 +#define R8A774A3_CLK_SD1H 31 +#define R8A774A3_CLK_SD1 32 +#define R8A774A3_CLK_SD2H 33 +#define R8A774A3_CLK_SD2 34 +#define R8A774A3_CLK_SD3H 35 +#define R8A774A3_CLK_SD3 36 +#define R8A774A3_CLK_RPC 37 +#define R8A774A3_CLK_RPCD2 38 +#define R8A774A3_CLK_MSO 39 +#define R8A774A3_CLK_CANFD 40 +#define R8A774A3_CLK_HDMI 41 +#define R8A774A3_CLK_CSI0 42 +#define R8A774A3_CLK_CP 43 +#define R8A774A3_CLK_CPEX 44 +#define R8A774A3_CLK_R 45 +#define R8A774A3_CLK_OSC 46 + +#endif /* __DT_BINDINGS_CLOCK_RENESAS_R8A774A3_CPG_MSSR_H__ */ From e018c27e6052ec58de3c1e7b340521ef162a8b81 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 14 Sep 2026 17:50:23 +0100 Subject: [PATCH 103/168] clk: renesas: r9a08g046: Propagate clk rate for ETH TX mux clocks Add CLK_SET_RATE_PARENT flag to the sel_eth0_tx and sel_eth1_tx mux clocks so that rate-setting requests on these clocks propagate up to their parent clocks. Without this flag, a clk_set_rate() call on the downstream GBETH clocks has no effect on the actual PLL/divider chain feeding the TX clock, leaving the requested rate unapplied. Fixes: d55a0dfec40b ("clk: renesas: r9a08g046: Add GBETH clocks and resets") Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260914165026.184612-1-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g046-cpg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/renesas/r9a08g046-cpg.c b/drivers/clk/renesas/r9a08g046-cpg.c index 22821321a1d3..1f706190280f 100644 --- a/drivers/clk/renesas/r9a08g046-cpg.c +++ b/drivers/clk/renesas/r9a08g046-cpg.c @@ -307,10 +307,12 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = { DEF_MUX(".sel_rspi0", CLK_SEL_RSPI0, G3L_SEL_RSPI0, sel_rsci_rspi), DEF_MUX(".sel_rspi1", CLK_SEL_RSPI1, G3L_SEL_RSPI1, sel_rsci_rspi), DEF_MUX(".sel_rspi2", CLK_SEL_RSPI2, G3L_SEL_RSPI2, sel_rsci_rspi), - DEF_MUX(".sel_eth0_tx", CLK_SEL_ETH0_TX, G3L_SEL_ETH0_TX, sel_eth0_tx), + DEF_MUX_FLAGS(".sel_eth0_tx", CLK_SEL_ETH0_TX, G3L_SEL_ETH0_TX, sel_eth0_tx, + CLK_SET_RATE_PARENT), DEF_MUX(".sel_eth0_rx", CLK_SEL_ETH0_RX, G3L_SEL_ETH0_RX, sel_eth0_rx), DEF_MUX(".sel_eth0_rm", CLK_SEL_ETH0_RM, G3L_SEL_ETH0_RM, sel_eth0_rm), - DEF_MUX(".sel_eth1_tx", CLK_SEL_ETH1_TX, G3L_SEL_ETH1_TX, sel_eth1_tx), + DEF_MUX_FLAGS(".sel_eth1_tx", CLK_SEL_ETH1_TX, G3L_SEL_ETH1_TX, sel_eth1_tx, + CLK_SET_RATE_PARENT), DEF_MUX(".sel_eth1_rx", CLK_SEL_ETH1_RX, G3L_SEL_ETH1_RX, sel_eth1_rx), DEF_MUX(".sel_eth1_rm", CLK_SEL_ETH1_RM, G3L_SEL_ETH1_RM, sel_eth1_rm), DEF_DIV(".div_eth0_tr", CLK_ETH0_TR, CLK_PLL6, G3L_SDIV_ETH_A, dtable_4_200), From 3f05aafb0f6ec61b159ec49b57da1653691357eb Mon Sep 17 00:00:00 2001 From: Biju Das Date: Mon, 21 Sep 2026 14:19:43 +0100 Subject: [PATCH 104/168] clk: renesas: r9a08g046: Add CANFD clocks and resets Add the P4 and P4_DIV2 core clocks, CANFD module clocks (canfd_pclk, canfd_clk_ram), and CANFD resets (RSTP_N, RSTC_N) for the RZ/G3L (R9A08G046) SoC, needed to enable the CANFD driver on this SoC. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260921131951.187981-2-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g046-cpg.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/clk/renesas/r9a08g046-cpg.c b/drivers/clk/renesas/r9a08g046-cpg.c index 1f706190280f..5da7364477ae 100644 --- a/drivers/clk/renesas/r9a08g046-cpg.c +++ b/drivers/clk/renesas/r9a08g046-cpg.c @@ -162,6 +162,7 @@ enum clk_ids { CLK_ETH1_TR, CLK_ETH1_RM, CLK_M2_DIV7, + CLK_P4_DIV2, CLK_SD0_DIV2, CLK_SD1_DIV2, CLK_SD2_DIV2, @@ -337,6 +338,8 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = { dtable_8_256, 0, 0, 0, NULL), DEF_G3S_DIV("P3", R9A08G046_CLK_P3, CLK_PLL2_DIV2, G3L_DIVPL2A, G3L_DIVPL2A_STS, dtable_4_128, 0, 0, 0, NULL), + DEF_FIXED("P4", R9A08G046_CLK_P4, CLK_PLL2_DIV2, 1, 5), + DEF_FIXED(".p4_div2", CLK_P4_DIV2, R9A08G046_CLK_P4, 1, 2), DEF_FIXED("P8", R9A08G046_CLK_P8, CLK_PLL3_DIV2, 1, 8), DEF_G3S_DIV("P13", R9A08G046_CLK_P13, CLK_SEL_RSCI0, G3L_DIV_RSCI0, G3L_DIV_RSCI0_STS, dtable_2_16, 0, 100000000UL, 0, NULL), @@ -559,6 +562,10 @@ static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = { MSTOP(BUS_MCPU1, BIT(15))), DEF_MOD("rspi2_tclk", R9A08G046_RSPI2_TCLK, R9A08G046_CLK_P19, 0x590, 10, MSTOP(BUS_MCPU2, BIT(0))), + DEF_MOD("canfd_pclk", R9A08G046_CANFD_PCLK, CLK_P4_DIV2, 0x594, 0, + MSTOP(BUS_MCPU2, BIT(9))), + DEF_MOD("canfd_clk_ram", R9A08G046_CANFD_CLK_RAM, R9A08G046_CLK_P4, 0x594, 1, + MSTOP(BUS_MCPU2, BIT(9))), DEF_MOD("gpio_hclk", R9A08G046_GPIO_HCLK, R9A08G046_OSCCLK, 0x598, 0, MSTOP(BUS_PERI_CPU, BIT(6))), DEF_MOD("pci_aclk", R9A08G046_PCI_ACLK, R9A08G046_CLK_P1, 0x608, 0, @@ -639,6 +646,8 @@ static const struct rzg2l_reset r9a08g046_resets[] = { DEF_RST(R9A08G046_RSPI0_TRESETN, 0x890, 8), DEF_RST(R9A08G046_RSPI1_TRESETN, 0x890, 9), DEF_RST(R9A08G046_RSPI2_TRESETN, 0x890, 10), + DEF_RST(R9A08G046_CANFD_RSTP_N, 0x894, 0), + DEF_RST(R9A08G046_CANFD_RSTC_N, 0x894, 1), DEF_RST(R9A08G046_GPIO_RSTN, 0x898, 0), DEF_RST(R9A08G046_GPIO_PORT_RESETN, 0x898, 1), DEF_RST(R9A08G046_GPIO_SPARE_RESETN, 0x898, 2), From a73364bb8d799a818f310a80e1edf18dd047339b Mon Sep 17 00:00:00 2001 From: Ayman Chaudhry Date: Mon, 21 Sep 2026 13:44:26 +0000 Subject: [PATCH 105/168] clk: renesas: Add support for RZ/G2M v3.0 Add initial support for the Renesas RZ/G2M v3.0 (a.k.a. R8A774A3) SoC, including basic core clocks, and SCIF2 (serial console) and INTC-AP (GIC) module clocks. The RZ/G2M v3.0 CPG is similar to RZ/G2M v1.3, however it lacks some modules such as the FCPCI. Signed-off-by: Ayman Chaudhry Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260921134432.50338-7-ayman.chaudhry.kc@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/Kconfig | 5 + drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/r8a774a3-cpg-mssr.c | 168 ++++++++++++++++++++++++ drivers/clk/renesas/renesas-cpg-mssr.c | 6 + drivers/clk/renesas/renesas-cpg-mssr.h | 1 + 5 files changed, 181 insertions(+) create mode 100644 drivers/clk/renesas/r8a774a3-cpg-mssr.c diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 46b929e9872b..a02ca6b096c0 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -13,6 +13,7 @@ config CLK_RENESAS select CLK_R8A7745 if ARCH_R8A7745 select CLK_R8A77470 if ARCH_R8A77470 select CLK_R8A774A1 if ARCH_R8A774A1 + select CLK_R8A774A3 if ARCH_R8A774A3 select CLK_R8A774B1 if ARCH_R8A774B1 select CLK_R8A774C0 if ARCH_R8A774C0 select CLK_R8A774E1 if ARCH_R8A774E1 @@ -93,6 +94,10 @@ config CLK_R8A774A1 bool "RZ/G2M clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG +config CLK_R8A774A3 + bool "RZ/G2M v3.0 clock support" if COMPILE_TEST + select CLK_RCAR_GEN3_CPG + config CLK_R8A774B1 bool "RZ/G2N clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 658f8aac5127..5c1b798118db 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_CLK_R8A7743) += r8a7743-cpg-mssr.o obj-$(CONFIG_CLK_R8A7745) += r8a7745-cpg-mssr.o obj-$(CONFIG_CLK_R8A77470) += r8a77470-cpg-mssr.o obj-$(CONFIG_CLK_R8A774A1) += r8a774a1-cpg-mssr.o +obj-$(CONFIG_CLK_R8A774A3) += r8a774a3-cpg-mssr.o obj-$(CONFIG_CLK_R8A774B1) += r8a774b1-cpg-mssr.o obj-$(CONFIG_CLK_R8A774C0) += r8a774c0-cpg-mssr.o obj-$(CONFIG_CLK_R8A774E1) += r8a774e1-cpg-mssr.o diff --git a/drivers/clk/renesas/r8a774a3-cpg-mssr.c b/drivers/clk/renesas/r8a774a3-cpg-mssr.c new file mode 100644 index 000000000000..64c5106a9a54 --- /dev/null +++ b/drivers/clk/renesas/r8a774a3-cpg-mssr.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * r8a774a3 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2026 Renesas Electronics Corp. + * + * Based on r8a7796-cpg-mssr.c + * + * Copyright (C) 2016 Glider bvba + */ + +#include +#include +#include +#include + +#include + +#include "renesas-cpg-mssr.h" +#include "rcar-gen3-cpg.h" + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R8A774A3_CLK_OSC, + + /* External Input Clocks */ + CLK_EXTAL, + CLK_EXTALR, + + /* Internal Core Clocks */ + CLK_MAIN, + CLK_PLL0, + CLK_PLL1, + CLK_PLL2, + CLK_PLL3, + CLK_PLL4, + CLK_PLL1_DIV2, + CLK_PLL1_DIV4, + CLK_S0, + CLK_S1, + CLK_S2, + CLK_S3, + + /* Module Clocks */ + MOD_CLK_BASE +}; + +static const struct cpg_core_clk r8a774a3_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + DEF_INPUT("extalr", CLK_EXTALR), + + /* Internal Core Clocks */ + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL), + DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN), + DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN), + DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN), + + DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), + DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1), + DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1), + + /* Core Clock Outputs */ + DEF_GEN3_Z("z", R8A774A3_CLK_Z, CLK_TYPE_GEN3_Z, CLK_PLL0, 2, 8), + DEF_GEN3_Z("z2", R8A774A3_CLK_Z2, CLK_TYPE_GEN3_Z, CLK_PLL2, 2, 0), + DEF_FIXED("s0d3", R8A774A3_CLK_S0D3, CLK_S0, 3, 1), + DEF_FIXED("s3d1", R8A774A3_CLK_S3D1, CLK_S3, 1, 1), + DEF_FIXED("s3d4", R8A774A3_CLK_S3D4, CLK_S3, 4, 1), +}; + +static const struct mssr_mod_clk r8a774a3_mod_clks[] __initconst = { + DEF_MOD("scif2", 310, R8A774A3_CLK_S3D4), + DEF_MOD("intc-ap", 408, R8A774A3_CLK_S0D3), +}; + +static const unsigned int r8a774a3_crit_mod_clks[] __initconst = { + MOD_CLK_ID(408), /* INTC-AP (GIC) */ +}; + +/* + * CPG Clock Data + */ + +/* + * MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4 OSC + * 14 13 19 17 (MHz) + *------------------------------------------------------------------------- + * 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144 /16 + * 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144 /16 + * 0 0 1 0 Prohibited setting + * 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144 /16 + * 0 1 0 0 20 x 1 x150 x160 x120 x160 x120 /19 + * 0 1 0 1 20 x 1 x150 x160 x120 x106 x120 /19 + * 0 1 1 0 Prohibited setting + * 0 1 1 1 20 x 1 x150 x160 x120 x160 x120 /19 + * 1 0 0 0 25 x 1 x120 x128 x96 x128 x96 /24 + * 1 0 0 1 25 x 1 x120 x128 x96 x84 x96 /24 + * 1 0 1 0 Prohibited setting + * 1 0 1 1 25 x 1 x120 x128 x96 x128 x96 /24 + * 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144 /32 + * 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144 /32 + * 1 1 1 0 Prohibited setting + * 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144 /32 + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \ + (((md) & BIT(13)) >> 11) | \ + (((md) & BIT(19)) >> 18) | \ + (((md) & BIT(17)) >> 17)) + +static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = { + /* EXTAL div PLL1 mult/div PLL3 mult/div OSC prediv */ + { 1, 192, 1, 192, 1, 16, }, + { 1, 192, 1, 128, 1, 16, }, + { 0, /* Prohibited setting */ }, + { 1, 192, 1, 192, 1, 16, }, + { 1, 160, 1, 160, 1, 19, }, + { 1, 160, 1, 106, 1, 19, }, + { 0, /* Prohibited setting */ }, + { 1, 160, 1, 160, 1, 19, }, + { 1, 128, 1, 128, 1, 24, }, + { 1, 128, 1, 84, 1, 24, }, + { 0, /* Prohibited setting */ }, + { 1, 128, 1, 128, 1, 24, }, + { 2, 192, 1, 192, 1, 32, }, + { 2, 192, 1, 128, 1, 32, }, + { 0, /* Prohibited setting */ }, + { 2, 192, 1, 192, 1, 32, }, +}; + +static int __init r8a774a3_cpg_mssr_init(struct device *dev) +{ + const struct rcar_gen3_cpg_pll_config *cpg_pll_config; + u32 cpg_mode; + int error; + + error = rcar_rst_read_mode_pins(&cpg_mode); + if (error) + return error; + + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + if (!cpg_pll_config->extal_div) { + dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode); + return -EINVAL; + } + + return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode); +} + +const struct cpg_mssr_info r8a774a3_cpg_mssr_info __initconst = { + /* Core Clocks */ + .core_clks = r8a774a3_core_clks, + .num_core_clks = ARRAY_SIZE(r8a774a3_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Module Clocks */ + .mod_clks = r8a774a3_mod_clks, + .num_mod_clks = ARRAY_SIZE(r8a774a3_mod_clks), + .num_hw_mod_clks = 12 * 32, + + /* Critical Module Clocks */ + .crit_mod_clks = r8a774a3_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r8a774a3_crit_mod_clks), + + /* Callbacks */ + .init = r8a774a3_cpg_mssr_init, + .cpg_clk_register = rcar_gen3_cpg_clk_register, +}; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index f2feac1cc74f..1c41268cb9eb 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -944,6 +944,12 @@ static const struct of_device_id cpg_mssr_match[] = { .data = &r8a774a1_cpg_mssr_info, }, #endif +#ifdef CONFIG_CLK_R8A774A3 + { + .compatible = "renesas,r8a774a3-cpg-mssr", + .data = &r8a774a3_cpg_mssr_info, + }, +#endif #ifdef CONFIG_CLK_R8A774B1 { .compatible = "renesas,r8a774b1-cpg-mssr", diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index 5bef6f34dcb2..dc3015b3032d 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -191,6 +191,7 @@ extern const struct cpg_mssr_info r8a7743_cpg_mssr_info; extern const struct cpg_mssr_info r8a7745_cpg_mssr_info; extern const struct cpg_mssr_info r8a77470_cpg_mssr_info; extern const struct cpg_mssr_info r8a774a1_cpg_mssr_info; +extern const struct cpg_mssr_info r8a774a3_cpg_mssr_info; extern const struct cpg_mssr_info r8a774b1_cpg_mssr_info; extern const struct cpg_mssr_info r8a774c0_cpg_mssr_info; extern const struct cpg_mssr_info r8a774e1_cpg_mssr_info; From a088fa8ab4dd2d15bbd1be0addf2f398a8a3a1bc Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 22 Sep 2026 05:26:53 +0100 Subject: [PATCH 106/168] clk: renesas: r9a08g046: Add TSU and ADC1 clocks and resets Add clock P20 (PLL2_DIV2/8), module clocks for ADC1 (ADCLK, PCLK) and TSU (PCLK), along with the corresponding module resets for ADC1 and TSU on the RZ/G3S (R9A08G046) SoC. Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260922042707.116378-2-biju.das.jz@bp.renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/clk/renesas/r9a08g046-cpg.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/clk/renesas/r9a08g046-cpg.c b/drivers/clk/renesas/r9a08g046-cpg.c index 5da7364477ae..b58057db9c4d 100644 --- a/drivers/clk/renesas/r9a08g046-cpg.c +++ b/drivers/clk/renesas/r9a08g046-cpg.c @@ -355,6 +355,7 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = { dtable_1_8, 0, 200000000UL, 0, NULL), DEF_G3S_DIV("P19", R9A08G046_CLK_P19, CLK_SEL_RSPI2, G3L_DIV_RSPI2, G3L_DIV_RSPI2_STS, dtable_1_8, 0, 200000000UL, 0, NULL), + DEF_FIXED("P20", R9A08G046_CLK_P20, CLK_PLL2_DIV2, 1, 8), DEF_G3S_DIV("SD0", R9A08G046_CLK_SD0, CLK_SEL_SDHI0, G3L_DIV_SDHI0, G3L_DIV_SDHI0_STS, dtable_1_4, 800000000UL, 600000000UL, CLK_SET_RATE_PARENT, rzg3s_cpg_div_clk_notifier), @@ -568,6 +569,12 @@ static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = { MSTOP(BUS_MCPU2, BIT(9))), DEF_MOD("gpio_hclk", R9A08G046_GPIO_HCLK, R9A08G046_OSCCLK, 0x598, 0, MSTOP(BUS_PERI_CPU, BIT(6))), + DEF_MOD("adc1_adclk", R9A08G046_ADC1_ADCLK, R9A08G046_CLK_P20, 0x5a8, 2, + MSTOP(BUS_PERI_VIDEO, BIT(14))), + DEF_MOD("adc1_pclk", R9A08G046_ADC1_PCLK, R9A08G046_CLK_P20, 0x5a8, 3, + MSTOP(BUS_PERI_VIDEO, BIT(14))), + DEF_MOD("tsu_pclk", R9A08G046_TSU_PCLK, R9A08G046_CLK_P20, 0x5ac, 0, + MSTOP(BUS_PERI_VIDEO, BIT(15))), DEF_MOD("pci_aclk", R9A08G046_PCI_ACLK, R9A08G046_CLK_P1, 0x608, 0, MSTOP(BUS_PERI_COM, BIT(10))), DEF_MOD("pci_clkl1pm", R9A08G046_PCI_CLKL1PM, R9A08G046_CLK_P8, 0x608, 1, @@ -651,6 +658,9 @@ static const struct rzg2l_reset r9a08g046_resets[] = { DEF_RST(R9A08G046_GPIO_RSTN, 0x898, 0), DEF_RST(R9A08G046_GPIO_PORT_RESETN, 0x898, 1), DEF_RST(R9A08G046_GPIO_SPARE_RESETN, 0x898, 2), + DEF_RST(R9A08G046_ADC1_PRESETN, 0x8a8, 2), + DEF_RST(R9A08G046_ADC1_ADRST_N, 0x8a8, 3), + DEF_RST(R9A08G046_TSU_PRESETN, 0x8ac, 0), DEF_RST(R9A08G046_PCI_ARESETN, 0x908, 0), DEF_RST(R9A08G046_RSCI0_PRESETN, 0x918, 0), DEF_RST(R9A08G046_RSCI1_PRESETN, 0x918, 1), From eebf9f18cf6368a40ba8c64d8e6627022ec5bc7e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 23 Sep 2026 11:12:18 +0200 Subject: [PATCH 107/168] clk: renesas: rzg2l: Fix internal clock names By convention, internal clock names start with a dot and use lower-case. Fix the outliers. Signed-off-by: Geert Uytterhoeven Link: https://patch.msgid.link/8254a5b1dccf33252042a366a3839a70020d6487.1790154594.git.geert+renesas@glider.be --- drivers/clk/renesas/r9a07g043-cpg.c | 12 ++++++------ drivers/clk/renesas/r9a07g044-cpg.c | 12 ++++++------ drivers/clk/renesas/r9a08g045-cpg.c | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c index 59d6ee2e888f..f7e32abc5d0b 100644 --- a/drivers/clk/renesas/r9a07g043-cpg.c +++ b/drivers/clk/renesas/r9a07g043-cpg.c @@ -119,7 +119,7 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { DEF_FIXED(".pll3_400", CLK_PLL3_400, CLK_PLL3, 1, 4), DEF_FIXED(".pll3_533", CLK_PLL3_533, CLK_PLL3, 1, 3), DEF_MUX_RO(".sel_pll3_3", CLK_SEL_PLL3_3, SEL_PLL3_3, sel_pll3_3), - DEF_DIV("divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3, DIVPL3C, dtable_1_32), + DEF_DIV(".divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3, DIVPL3C, dtable_1_32), #ifdef CONFIG_ARM64 DEF_FIXED(".pll5", CLK_PLL5, CLK_EXTAL, 125, 1), DEF_FIXED(".pll5_500", CLK_PLL5_500, CLK_PLL5, 1, 6), @@ -135,7 +135,7 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { DEF_FIXED("P0_DIV2", R9A07G043_CLK_P0_DIV2, R9A07G043_CLK_P0, 1, 2), DEF_FIXED("TSU", R9A07G043_CLK_TSU, CLK_PLL2_DIV2_10, 1, 1), DEF_DIV("P1", R9A07G043_CLK_P1, CLK_PLL3_DIV2_4, DIVPL3B, dtable_1_32), - DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A07G043_CLK_P1, 1, 2), + DEF_FIXED(".p1_div2", CLK_P1_DIV2, R9A07G043_CLK_P1, 1, 2), DEF_DIV("P2", R9A07G043_CLK_P2, CLK_PLL3_DIV2_4_2, DIVPL3A, dtable_1_32), DEF_FIXED("M0", R9A07G043_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), DEF_FIXED("ZT", R9A07G043_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1), @@ -151,12 +151,12 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_sdhi, mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), - DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4), - DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4), + DEF_FIXED(".sd0_div4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4), + DEF_FIXED(".sd1_div4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4), #ifdef CONFIG_ARM64 DEF_FIXED("M2", R9A07G043_CLK_M2, CLK_PLL3_533, 1, 2), - DEF_FIXED("M2_DIV2", CLK_M2_DIV2, R9A07G043_CLK_M2, 1, 2), - DEF_DSI_DIV("DSI_DIV", CLK_DSI_DIV, CLK_PLL5_FOUTPOSTDIV, CLK_SET_RATE_PARENT), + DEF_FIXED(".m2_div2", CLK_M2_DIV2, R9A07G043_CLK_M2, 1, 2), + DEF_DSI_DIV(".dsi_div", CLK_DSI_DIV, CLK_PLL5_FOUTPOSTDIV, CLK_SET_RATE_PARENT), DEF_FIXED("M3", R9A07G043_CLK_M3, CLK_DSI_DIV, 1, 1), #endif }; diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c index 913cca6dd46f..3b6d0bd1ec13 100644 --- a/drivers/clk/renesas/r9a07g044-cpg.c +++ b/drivers/clk/renesas/r9a07g044-cpg.c @@ -187,7 +187,7 @@ static const struct { DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4), DEF_FIXED(".pll3_div2_4_2", CLK_PLL3_DIV2_4_2, CLK_PLL3_DIV2_4, 1, 2), DEF_MUX_RO(".sel_pll3_3", CLK_SEL_PLL3_3, SEL_PLL3_3, sel_pll3_3), - DEF_DIV("divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3, DIVPL3C, dtable_1_32), + DEF_DIV(".divpl3c", CLK_DIV_PLL3_C, CLK_SEL_PLL3_3, DIVPL3C, dtable_1_32), DEF_FIXED(".pll5_250", CLK_PLL5_250, CLK_PLL5_FOUT3, 1, 2), DEF_FIXED(".pll6_250", CLK_PLL6_250, CLK_PLL6, 1, 2), @@ -204,7 +204,7 @@ static const struct { DEF_FIXED("P0_DIV2", R9A07G044_CLK_P0_DIV2, R9A07G044_CLK_P0, 1, 2), DEF_FIXED("TSU", R9A07G044_CLK_TSU, CLK_PLL2_DIV2_10, 1, 1), DEF_DIV("P1", R9A07G044_CLK_P1, CLK_PLL3_DIV2_4, DIVPL3B, dtable_1_32), - DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A07G044_CLK_P1, 1, 2), + DEF_FIXED(".p1_div2", CLK_P1_DIV2, R9A07G044_CLK_P1, 1, 2), DEF_DIV("P2", R9A07G044_CLK_P2, CLK_PLL3_DIV2_4_2, DIVPL3A, dtable_1_32), DEF_FIXED("M0", R9A07G044_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), DEF_FIXED("ZT", R9A07G044_CLK_ZT, CLK_PLL3_DIV2_4_2, 1, 1), @@ -215,13 +215,13 @@ static const struct { mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI1_STS, sel_sdhi, mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier), - DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), - DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), + DEF_FIXED(".sd0_div4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4), + DEF_FIXED(".sd1_div4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4), DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8), DEF_FIXED("M1", R9A07G044_CLK_M1, CLK_PLL5_FOUTPOSTDIV, 1, 1), DEF_FIXED("M2", R9A07G044_CLK_M2, CLK_PLL3_533, 1, 2), - DEF_FIXED("M2_DIV2", CLK_M2_DIV2, R9A07G044_CLK_M2, 1, 2), - DEF_DSI_DIV("DSI_DIV", CLK_DSI_DIV, CLK_SEL_PLL5_4, CLK_SET_RATE_PARENT), + DEF_FIXED(".m2_div2", CLK_M2_DIV2, R9A07G044_CLK_M2, 1, 2), + DEF_DSI_DIV(".dsi_div", CLK_DSI_DIV, CLK_SEL_PLL5_4, CLK_SET_RATE_PARENT), DEF_FIXED("M3", R9A07G044_CLK_M3, CLK_DSI_DIV, 1, 1), DEF_FIXED("M4", R9A07G044_CLK_M4, CLK_DIV_DSI_LPCLK, 1, 1), }, diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c index ea2a6a71aebd..4e1cd3177ecd 100644 --- a/drivers/clk/renesas/r9a08g045-cpg.c +++ b/drivers/clk/renesas/r9a08g045-cpg.c @@ -167,14 +167,14 @@ static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = { DEF_FIXED("M0", R9A08G045_CLK_M0, CLK_PLL3_DIV2_4, 1, 1), DEF_G3S_DIV("P1", R9A08G045_CLK_P1, CLK_PLL3_DIV2_4, DIVPL3A, G3S_DIVPL3A_STS, dtable_1_32, 0, 0, 0, NULL), - DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A08G045_CLK_P1, 1, 2), + DEF_FIXED(".p1_div2", CLK_P1_DIV2, R9A08G045_CLK_P1, 1, 2), DEF_G3S_DIV("P2", R9A08G045_CLK_P2, CLK_PLL3_DIV2_8, DIVPL3B, G3S_DIVPL3B_STS, dtable_1_32, 0, 0, 0, NULL), DEF_G3S_DIV("P3", R9A08G045_CLK_P3, CLK_PLL3_DIV2_4, DIVPL3C, G3S_DIVPL3C_STS, dtable_1_32, 0, 0, 0, NULL), - DEF_FIXED("P3_DIV2", CLK_P3_DIV2, R9A08G045_CLK_P3, 1, 2), + DEF_FIXED(".p3_div2", CLK_P3_DIV2, R9A08G045_CLK_P3, 1, 2), DEF_FIXED("P4", R9A08G045_CLK_P4, CLK_PLL2_DIV2, 1, 5), - DEF_FIXED("P4_DIV2", CLK_P4_DIV2, R9A08G045_CLK_P4, 1, 2), + DEF_FIXED(".p4_div2", CLK_P4_DIV2, R9A08G045_CLK_P4, 1, 2), DEF_FIXED("P5", R9A08G045_CLK_P5, CLK_PLL2_DIV2, 1, 4), DEF_FIXED("ZT", R9A08G045_CLK_ZT, CLK_PLL3_DIV2_8, 1, 1), DEF_FIXED("S0", R9A08G045_CLK_S0, CLK_SEL_PLL4, 1, 2), From a1f2029b89ccd7bef54e187384417db4d72d0a11 Mon Sep 17 00:00:00 2001 From: Bill Wendling Date: Tue, 22 Sep 2026 11:06:01 +0000 Subject: [PATCH 108/168] clk: tegra: annotate struct tegra210_clk_emc_provider with __counted_by_ptr Annotate the "configs" pointer field of "struct tegra210_clk_emc_provider" with the "__counted_by_ptr" attribute, allowing the compiler to perform runtime bounds checking on accesses to "configs" based on the value of "num_configs". The "emc->provider.configs = devm_kcalloc(...)" call uses "emc->num_timings" for the number of elements, which is then assigned to "emc->provider.num_configs" before any accesses to "configs". The "num_configs" field isn't modified after assignment. Cc: codemender-patching+linux@google.com Assisted-by: LLM Signed-off-by: Bill Wendling Reviewed-by: Gustavo A. R. Silva Reviewed-by: Kees Cook Signed-off-by: Brian Masney --- include/linux/clk/tegra.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 3650e926e93f..f1034e14c1a4 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -170,7 +170,7 @@ struct tegra210_clk_emc_provider { struct module *owner; struct device *dev; - struct tegra210_clk_emc_config *configs; + struct tegra210_clk_emc_config *configs __counted_by_ptr(num_configs); unsigned int num_configs; int (*set_rate)(struct device *dev, From b4243850393f2f24e21b9f4b2c56233e60c904b4 Mon Sep 17 00:00:00 2001 From: Aamir Ahmed Date: Sat, 5 Sep 2026 21:48:07 +0100 Subject: [PATCH 109/168] clk: mvebu: ap-cpu-clk: Assign .num before accessing .hws Commit f316cdff8d67 ("clk: Annotate struct clk_hw_onecell_data with __counted_by") annotated the hws member of 'struct clk_hw_onecell_data' with __counted_by, which informs the bounds sanitizer (UBSAN_BOUNDS) about the number of elements in .hws[], so that it can warn when .hws[] is accessed out of bounds. As noted in that change, the __counted_by member must be initialized with the number of elements before the first array access happens, otherwise there will be a warning from each access prior to the initialization because the number of elements is zero. This occurs in ap_cpu_clock_probe(), which reads .hws[] to skip clusters that have already been set up and writes it inside the CPU node loop, but only assigns .num after the loop. With CONFIG_UBSAN_BOUNDS and a compiler that implements __counted_by (GCC 15.1+ or Clang 20.1+), this triggers an array-index-out-of-bounds report during probe of the AP806 and AP807 CPU clocks, and with CONFIG_UBSAN_TRAP the first access traps. Initialize .num with nclusters, the number of elements .hws[] was allocated with, right after the allocation. For the in-tree AP806 and AP807 device trees, which list the CPU nodes in ascending order, this is exactly the value the old assignment produced. It is also the correct value for any other node order, since of_clk_hw_onecell_get() rejects indices at or beyond .num. Cc: stable@vger.kernel.org Fixes: f316cdff8d67 ("clk: Annotate struct clk_hw_onecell_data with __counted_by") Assisted-by: LLM Signed-off-by: Aamir Ahmed Signed-off-by: Brian Masney --- drivers/clk/mvebu/ap-cpu-clk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/mvebu/ap-cpu-clk.c b/drivers/clk/mvebu/ap-cpu-clk.c index 721cad421867..b1c6fceb91b2 100644 --- a/drivers/clk/mvebu/ap-cpu-clk.c +++ b/drivers/clk/mvebu/ap-cpu-clk.c @@ -284,6 +284,8 @@ static int ap_cpu_clock_probe(struct platform_device *pdev) if (!ap_cpu_data) return -ENOMEM; + ap_cpu_data->num = nclusters; + for_each_of_cpu_node(dn) { char *clk_name = "cpu-cluster-0"; struct clk_init_data init = {}; @@ -333,8 +335,6 @@ static int ap_cpu_clock_probe(struct platform_device *pdev) ap_cpu_data->hws[cluster_index] = &ap_cpu_clk[cluster_index].hw; } - ap_cpu_data->num = cluster_index + 1; - ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ap_cpu_data); if (ret) dev_err(dev, "failed to register OF clock provider\n"); From a1d0465f027d341c6855324a5c63e54780ce20f3 Mon Sep 17 00:00:00 2001 From: Peijie Shao Date: Wed, 9 Sep 2026 21:14:12 +0800 Subject: [PATCH 110/168] clk: clocking-wizard: Fix overflow in clockout0 divisor calculation On 32-bit platforms (e.g., Zynq 7000 series), parent_rate * 1000 may overflow, leading to incorrect divisor calculation. The issue was first found on Zynq7020 with "parent_rate=1GHz" and "xlnx,nr-outputs=2". Cast parent_rate to u64 and use the ULL version of DIV_ROUND* instead. Signed-off-by: Peijie Shao Signed-off-by: Brian Masney --- drivers/clk/xilinx/clk-xlnx-clock-wizard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c index 25bd71822dd6..71abd46b3593 100644 --- a/drivers/clk/xilinx/clk-xlnx-clock-wizard.c +++ b/drivers/clk/xilinx/clk-xlnx-clock-wizard.c @@ -881,10 +881,10 @@ static int clk_wzrd_dynamic_reconfig_f(struct clk_hw *hw, unsigned long rate, struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); void __iomem *div_addr = divider->base + divider->offset; - rate_div = DIV_ROUND_DOWN_ULL(parent_rate * 1000, rate); + rate_div = DIV_ROUND_DOWN_ULL((u64)parent_rate * 1000, rate); clockout0_div = rate_div / 1000; - pre = DIV_ROUND_CLOSEST((parent_rate * 1000), rate); + pre = DIV_ROUND_CLOSEST_ULL((u64)parent_rate * 1000, rate); f = (u32)(pre - (clockout0_div * 1000)); f = f & WZRD_CLKOUT_FRAC_MASK; f = f << WZRD_CLKOUT_DIVIDE_WIDTH; From faa5022a9b122262152e7328142a6f628d2bea9d Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Fri, 25 Sep 2026 13:49:43 +0800 Subject: [PATCH 111/168] MAINTAINERS: name the clk/linux clk-next branch The T: entry for COMMON CLK FRAMEWORK names clk/linux without a branch. The repository's HEAD points to branch master, which mainline already contains. linux-next merges the clk-next branch of this repository (Next/Trees). Name that branch in the entry. Signed-off-by: Matthias Goergens Reviewed-by: Jerome Brunet Signed-off-by: Brian Masney --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index dd2742284dd8..3a729f7326f0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6500,7 +6500,7 @@ M: Jerome Brunet L: linux-clk@vger.kernel.org S: Maintained Q: http://patchwork.kernel.org/project/linux-clk/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next F: Documentation/devicetree/bindings/clock/ F: drivers/clk/ F: include/dt-bindings/clock/ From af384d6e0573b416a7a28e0ab6300d797cae369d Mon Sep 17 00:00:00 2001 From: Michal Wilczynski Date: Tue, 15 Sep 2026 17:32:22 +0200 Subject: [PATCH 112/168] clk: starfive: jh7110-vout: Allow pixel clock rate propagation The dc8200_pix0 and dc8200_pix1 MUXes feed the display controller, and the rate they carry is ultimately produced by the HDMI PHY, which registers hdmitx0_pixelclk as a clock provider. Add CLK_SET_RATE_PARENT to both MUXes so a rate requested on them reaches that parent, instead of being clamped to whatever rate the parent already happens to run at. Co-developed-by: Dominique Belhachemi Signed-off-by: Dominique Belhachemi Reviewed-by: Joshua Peisach Signed-off-by: Michal Wilczynski Signed-off-by: Brian Masney --- drivers/clk/starfive/clk-starfive-jh7110-vout.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c index bad20d5d794a..aeba42cd3c44 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-vout.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c @@ -40,10 +40,12 @@ static const struct jh71x0_clk_data jh7110_voutclk_data[] = { JH71X0_GATE(JH7110_VOUTCLK_DC8200_AXI, "dc8200_axi", 0, JH7110_VOUTCLK_VOUT_TOP_AXI), JH71X0_GATE(JH7110_VOUTCLK_DC8200_CORE, "dc8200_core", 0, JH7110_VOUTCLK_VOUT_TOP_AXI), JH71X0_GATE(JH7110_VOUTCLK_DC8200_AHB, "dc8200_ahb", 0, JH7110_VOUTCLK_VOUT_TOP_AHB), - JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", 0, 2, + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX0, "dc8200_pix0", + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 2, JH7110_VOUTCLK_DC8200_PIX, JH7110_VOUTCLK_HDMITX0_PIXELCLK), - JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", 0, 2, + JH71X0_GMUX(JH7110_VOUTCLK_DC8200_PIX1, "dc8200_pix1", + CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT, 2, JH7110_VOUTCLK_DC8200_PIX, JH7110_VOUTCLK_HDMITX0_PIXELCLK), /* LCD */ From 21cbd7ec29930f8e7e156e18b81736f099f03849 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 25 Sep 2026 10:56:14 +0200 Subject: [PATCH 113/168] clk: renesas: r8a78000: Add SGASYNCD8_PERW_BUS Add support for the SGASYNCD8_PERW_BUS clock, which is a fixed 133 MHz clock serving as the functional clock parent for I2C cores 1 to 8. Signed-off-by: Wolfram Sang Signed-off-by: Geert Uytterhoeven Link: https://patch.msgid.link/8c4912ada9c3d6776ae64d3896ffc1f45a98c51a.1790326477.git.geert+renesas@glider.be --- drivers/clk/renesas/r8a78000-cpg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/renesas/r8a78000-cpg.c b/drivers/clk/renesas/r8a78000-cpg.c index 7946f9d0b423..b8024e76743e 100644 --- a/drivers/clk/renesas/r8a78000-cpg.c +++ b/drivers/clk/renesas/r8a78000-cpg.c @@ -23,12 +23,14 @@ struct clk_map { enum fixed_clk { FIXED_CLK_66M, + FIXED_CLK_133M, FIXED_CLK_266M, NUM_FIXED_CLKS }; static const unsigned long fixed_clk_rates[NUM_FIXED_CLKS] = { [FIXED_CLK_66M] = 66666000, + [FIXED_CLK_133M] = 133330000, [FIXED_CLK_266M] = 266660000, }; @@ -140,6 +142,7 @@ static int r8a78000_cpg_probe(struct platform_device *pdev) static const struct clk_map r8a78000_cpg_default[] = { { R8A78000_CPG_SGASYNCD4_PERW_BUS, FIXED_CLK(266M) }, + { R8A78000_CPG_SGASYNCD8_PERW_BUS, FIXED_CLK(133M) }, { R8A78000_CPG_SGASYNCD16_PERW_BUS, FIXED_CLK(66M) }, { -1 } }; From f619355a6bc6e2ce8b2b104abfd4f2c86e22aad3 Mon Sep 17 00:00:00 2001 From: Yury Norov Date: Fri, 25 Sep 2026 15:38:58 -0400 Subject: [PATCH 114/168] clk: si521xx: simplify si521xx_diff_idx_to_reg_bit() Switch the function to using fns(), and get rid of the double for-loop. Signed-off-by: Yury Norov Signed-off-by: Brian Masney --- drivers/clk/clk-si521xx.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c index 6e3c8e6ccc8d..23d80f060f99 100644 --- a/drivers/clk/clk-si521xx.c +++ b/drivers/clk/clk-si521xx.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -255,18 +256,24 @@ static void si521xx_diff_idx_to_reg_bit(const u16 chip_info, const int idx, struct si_clk *clk) { unsigned long mask; - int oe, b, ctr = 0; + unsigned int bit; + int oe = 1; - for (oe = 1; oe <= 2; oe++) { - mask = bitrev8(SI521XX_OE_MAP_GET_OE(oe, chip_info)); - for_each_set_bit(b, &mask, 8) { - if (ctr++ != idx) - continue; - clk->reg = SI521XX_REG_OE(oe); - clk->bit = 7 - b; - return; - } - } + mask = bitrev8(SI521XX_OE_MAP_GET_OE(1, chip_info)); + bit = fns(mask, idx); + if (bit < 8) + goto out; + + oe = 2; + bit = idx - hweight8(mask); + mask = bitrev8(SI521XX_OE_MAP_GET_OE(2, chip_info)); + bit = fns(mask, bit); + if (bit >= 8) + return; + +out: + clk->reg = SI521XX_REG_OE(oe); + clk->bit = 7 - bit; } static struct clk_hw * From 906fddec02bc9381ca872544820bd4d610cfa20c Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 24 Jul 2026 14:04:57 +0700 Subject: [PATCH 115/168] clk: si521xx: restore cache_only on regcache_sync() failure in resume If regcache_sync() fails in si521xx_resume(), the function only logs the error, leaving regmap with cache_only disabled even though the register cache has not been synchronized with the hardware. Re-enable cache_only on failure to restore the state established by si521xx_suspend(). Signed-off-by: bui duc phuc Signed-off-by: Brian Masney --- drivers/clk/clk-si521xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c index 23d80f060f99..84dc3621df93 100644 --- a/drivers/clk/clk-si521xx.c +++ b/drivers/clk/clk-si521xx.c @@ -365,8 +365,10 @@ static int si521xx_resume(struct device *dev) regcache_cache_only(si->regmap, false); ret = regcache_sync(si->regmap); - if (ret) + if (ret) { + regcache_cache_only(si->regmap, true); dev_err(dev, "Failed to restore register map: %d\n", ret); + } return ret; } From 1c4f9480473917558908c083d1293b4ebb3d50c5 Mon Sep 17 00:00:00 2001 From: Wentao Liang Date: Thu, 4 Jun 2026 06:43:14 +0000 Subject: [PATCH 116/168] clk: starfive: jh7110-isp: fix refcount leak in jh7110_ispcrg_probe() In jh7110_ispcrg_probe(), the error path for pm_runtime_get_sync() failure directly returns without releasing the runtime PM reference count. The call to __pm_runtime_resume() increments the usage count unconditionally before attempting to resume, and does not decrement it on failure. Thus the leaked reference makes it impossible to suspend the device later. All other error paths correctly jump to err_exit and call pm_runtime_put_sync(). Fix this by replacing pm_runtime_get_sync() with pm_runtime_resume_and_get(), which properly balances the reference count on error. Cc: stable@vger.kernel.org Fixes: 81279f5d0812 ("clk: starfive: Add StarFive JH7110 Image-Signal-Process clock driver") Signed-off-by: Wentao Liang Reviewed-by: Hal Feng Signed-off-by: Brian Masney --- drivers/clk/starfive/clk-starfive-jh7110-isp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/starfive/clk-starfive-jh7110-isp.c b/drivers/clk/starfive/clk-starfive-jh7110-isp.c index f3fa069db193..c02c8b29a123 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-isp.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-isp.c @@ -130,7 +130,7 @@ static int jh7110_ispcrg_probe(struct platform_device *pdev) /* enable power domain and clocks */ pm_runtime_enable(priv->dev); - ret = pm_runtime_get_sync(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); if (ret < 0) return dev_err_probe(priv->dev, ret, "failed to turn on power\n"); From 4c943ddfc24340f1b899762b1ff35c38306b7a35 Mon Sep 17 00:00:00 2001 From: Myeonghun Pak Date: Fri, 26 Jun 2026 18:41:26 +0900 Subject: [PATCH 117/168] clk: ti: adpll: unregister OF clock provider on remove ti_adpll_probe() registers the driver's onecell clock provider with of_clk_add_provider(). The remove path only frees the clock resources, leaving the provider registered after the backing data has been torn down. Unregister the OF clock provider before freeing the ADPLL resources so the provider no longer points at released driver data after device removal. Fixes: 21330497f303 ("clk: ti: Add support for dm814x ADPLL") Co-developed-by: Ijae Kim Signed-off-by: Ijae Kim Signed-off-by: Myeonghun Pak Signed-off-by: Brian Masney --- drivers/clk/ti/adpll.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c index 8885d28face5..0d729c9980a5 100644 --- a/drivers/clk/ti/adpll.c +++ b/drivers/clk/ti/adpll.c @@ -925,6 +925,7 @@ static void ti_adpll_remove(struct platform_device *pdev) { struct ti_adpll_data *d = dev_get_drvdata(&pdev->dev); + of_clk_del_provider(d->np); ti_adpll_free_resources(d); } From e44caef8848790e3515c7c32bd3460e948613092 Mon Sep 17 00:00:00 2001 From: Eduard Bostina Date: Sun, 19 Jul 2026 14:12:36 +0000 Subject: [PATCH 118/168] dt-bindings: clock: Convert TI Palmas Clock to DT schema Convert the Texas Instruments Palmas 32KHz clock bindings to DT schema. During the conversion, the node name in the example was updated from 'palmas_clk32k@0' to 'clock-controller'. The old example contained a unit address without a 'reg' property, which causes dtc compilation warnings. Signed-off-by: Eduard Bostina Reviewed-by: Rob Herring (Arm) Signed-off-by: Brian Masney --- .../clock/clk-palmas-clk32kg-clocks.txt | 35 ------------ .../bindings/clock/ti,palmas-clk32kg.yaml | 56 +++++++++++++++++++ 2 files changed, 56 insertions(+), 35 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/clk-palmas-clk32kg-clocks.txt create mode 100644 Documentation/devicetree/bindings/clock/ti,palmas-clk32kg.yaml diff --git a/Documentation/devicetree/bindings/clock/clk-palmas-clk32kg-clocks.txt b/Documentation/devicetree/bindings/clock/clk-palmas-clk32kg-clocks.txt deleted file mode 100644 index 4208886d834a..000000000000 --- a/Documentation/devicetree/bindings/clock/clk-palmas-clk32kg-clocks.txt +++ /dev/null @@ -1,35 +0,0 @@ -* Palmas 32KHz clocks * - -Palmas device has two clock output pins for 32KHz, KG and KG_AUDIO. - -This binding uses the common clock binding ./clock-bindings.txt. - -Required properties: -- compatible : "ti,palmas-clk32kg" for clk32kg clock - "ti,palmas-clk32kgaudio" for clk32kgaudio clock -- #clock-cells : shall be set to 0. - -Optional property: -- ti,external-sleep-control: The external enable input pins controlled the - enable/disable of clocks. The external enable input pins ENABLE1, - ENABLE2 and NSLEEP. The valid values for the external pins are: - PALMAS_EXT_CONTROL_PIN_ENABLE1 for ENABLE1 pin - PALMAS_EXT_CONTROL_PIN_ENABLE2 for ENABLE2 pin - PALMAS_EXT_CONTROL_PIN_NSLEEP for NSLEEP pin - Option 0 or missing this property means the clock is enabled/disabled - via register access and these pins do not have any control. - The macros of external control pins for DTS is defined at - dt-bindings/mfd/palmas.h - -Example: - #include - ... - palmas: tps65913@58 { - ... - clk32kg: palmas_clk32k@0 { - compatible = "ti,palmas-clk32kg"; - #clock-cells = <0>; - ti,external-sleep-control = ; - }; - ... - }; diff --git a/Documentation/devicetree/bindings/clock/ti,palmas-clk32kg.yaml b/Documentation/devicetree/bindings/clock/ti,palmas-clk32kg.yaml new file mode 100644 index 000000000000..c2a49be9b95a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti,palmas-clk32kg.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti,palmas-clk32kg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments Palmas 32KHz Clocks + +maintainers: + - Eduard Bostina + +description: + The Palmas device family has two clock output pins for 32KHz, + KG and KG_AUDIO. + +allOf: + - $ref: /schemas/clock/clock.yaml# + +properties: + compatible: + enum: + - ti,palmas-clk32kg + - ti,palmas-clk32kgaudio + + "#clock-cells": + const: 0 + + ti,external-sleep-control: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [ 0, 1, 2, 3 ] + description: | + The external enable input pins control the enable/disable of clocks. + The valid values (defined in dt-bindings/mfd/palmas.h) are: + 1: PALMAS_EXT_CONTROL_PIN_ENABLE1 + 2: PALMAS_EXT_CONTROL_PIN_ENABLE2 + 3: PALMAS_EXT_CONTROL_PIN_NSLEEP + Option 0 or missing this property means the clock is enabled/disabled + via register access and these pins do not have any control. + +required: + - compatible + - "#clock-cells" + +unevaluatedProperties: false + +examples: + - | + #include + + pmic { + clock-controller { + compatible = "ti,palmas-clk32kg"; + #clock-cells = <0>; + ti,external-sleep-control = ; + }; + }; From 29e5259e30012bfb0f48345ac7d89999f17e1f26 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 24 Jul 2026 13:56:58 +0700 Subject: [PATCH 119/168] clk: rs9: restore cache_only on regcache_sync() failure in resume If regcache_sync() fails in rs9_resume(), the function only logs the error, leaving regmap with cache_only disabled even though the register cache has not been synchronized with the hardware. Re-enable cache_only on failure to restore the state established by rs9_suspend(). Signed-off-by: bui duc phuc Signed-off-by: Brian Masney --- drivers/clk/clk-renesas-pcie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c index e2b441f99cca..864bf89cecd0 100644 --- a/drivers/clk/clk-renesas-pcie.c +++ b/drivers/clk/clk-renesas-pcie.c @@ -367,8 +367,10 @@ static int rs9_resume(struct device *dev) regcache_cache_only(rs9->regmap, false); ret = regcache_sync(rs9->regmap); - if (ret) + if (ret) { + regcache_cache_only(rs9->regmap, true); dev_err(dev, "Failed to restore register map: %d\n", ret); + } return ret; } From 7b283b8ce37d40d22f41bdc20b407cd76fe86e68 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Fri, 24 Jul 2026 14:46:03 +0700 Subject: [PATCH 120/168] clk: versaclock5: restore cache_only on regcache_sync() failure in resume If regcache_sync() fails in vc5_resume(), the function only logs the error, leaving regmap with cache_only disabled even though the register cache has not been synchronized with the hardware. Re-enable cache_only on failure to restore the state established by vc5_suspend(). Signed-off-by: bui duc phuc Signed-off-by: Brian Masney --- drivers/clk/clk-versaclock5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index fe3827b6c097..d91749be785c 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -1240,8 +1240,10 @@ static int vc5_resume(struct device *dev) regcache_cache_only(vc5->regmap, false); ret = regcache_sync(vc5->regmap); - if (ret) + if (ret) { + regcache_cache_only(vc5->regmap, true); dev_err(dev, "Failed to restore register map: %d\n", ret); + } return ret; } From 109124b8ff43fb911d5b8790bb5e4c5684f72d88 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Fri, 4 Sep 2026 12:06:31 +0200 Subject: [PATCH 121/168] clk: validate spread spectrum configuration The spread spectrum configuration is passed to the provider's set_spread_spectrum() callback without any validation, as clk-conf.c only skips all-zero triplets from "assigned-clock-sscs". An invalid device tree can hand providers a zero modulation frequency or a spread ratio above 100%, and each provider would have to add the same checks to protect e.g. divisions in its rate computations. The KUnit test data for assigned-clock-sscs uses spread values of 30000 and 40000 permyriad (300% and 400%), which the new check rejects, as reported by Sashiko, so fix them to 300 and 400 (3% and 4%). Also use a realistic 6% value for the initial settings of the skip tests, for consistency. Fixes: c86814e70390 ("clk: Introduce clk_hw_set_spread_spectrum") Reported-by: Sashiko Closes: https://lore.kernel.org/r/20260901155657.6A5981F00A3A@smtp.kernel.org Reviewed-by: Peng Fan Signed-off-by: Dario Binacchi Signed-off-by: Brian Masney --- drivers/clk/clk.c | 14 ++++++++++++++ drivers/clk/clk_test.c | 12 ++++++------ drivers/clk/kunit_clk_assigned_rates.h | 4 ++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f1756fe59372..4d2cc86bfbeb 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2853,6 +2853,20 @@ int clk_hw_set_spread_spectrum(struct clk_hw *hw, const struct clk_spread_spectr if (!hw) return 0; + switch (ss_conf->method) { + case CLK_SPREAD_NO: + break; + case CLK_SPREAD_CENTER: + case CLK_SPREAD_UP: + case CLK_SPREAD_DOWN: + if (!ss_conf->modfreq_hz || !ss_conf->spread_bp || + ss_conf->spread_bp > 10000) + return -EINVAL; + break; + default: + return -EINVAL; + } + core = hw->core; clk_prepare_lock(); diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index 91998b7474fc..0505ed357b20 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -3526,7 +3526,7 @@ static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_p */ .desc = "provider missing assigned-clocks", TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without), - .sscs = {50000, 60000, 3}, + .sscs = {50000, 600, 3}, }, { /* @@ -3535,7 +3535,7 @@ static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_p */ .desc = "consumer missing assigned-clocks", TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_without_consumer), - .sscs = {50000, 60000, 3}, + .sscs = {50000, 600, 3}, .consumer_test = true, }, { @@ -3545,7 +3545,7 @@ static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_p */ .desc = "provider assigned-clock-sscs of zero", TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero), - .sscs = {50000, 60000, 3}, + .sscs = {50000, 600, 3}, }, { /* @@ -3554,7 +3554,7 @@ static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_p */ .desc = "consumer assigned-clock-sscs of zero", TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_zero_consumer), - .sscs = {50000, 60000, 3}, + .sscs = {50000, 600, 3}, .consumer_test = true, }, { @@ -3564,7 +3564,7 @@ static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_p */ .desc = "provider assigned-clocks null phandle", TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null), - .sscs = {50000, 60000, 3}, + .sscs = {50000, 600, 3}, }, { /* @@ -3573,7 +3573,7 @@ static const struct clk_assigned_rates_test_param clk_assigned_sscs_skips_test_p */ .desc = "consumer assigned-clocks null phandle", TEST_PARAM_OVERLAY(kunit_clk_assigned_sscs_null_consumer), - .sscs = {50000, 60000, 3}, + .sscs = {50000, 600, 3}, .consumer_test = true, }, }; diff --git a/drivers/clk/kunit_clk_assigned_rates.h b/drivers/clk/kunit_clk_assigned_rates.h index d7ae5ec2d25b..c5d9f004ee81 100644 --- a/drivers/clk/kunit_clk_assigned_rates.h +++ b/drivers/clk/kunit_clk_assigned_rates.h @@ -9,10 +9,10 @@ #define ASSIGNED_RATES_1_RATE 9700000 #define ASSIGNED_SSCS_0_MODFREQ 10000 -#define ASSIGNED_SSCS_0_SPREAD 30000 +#define ASSIGNED_SSCS_0_SPREAD 300 #define ASSIGNED_SSCS_0_METHOD CLK_SSC_CENTER_SPREAD #define ASSIGNED_SSCS_1_MODFREQ 20000 -#define ASSIGNED_SSCS_1_SPREAD 40000 +#define ASSIGNED_SSCS_1_SPREAD 400 #define ASSIGNED_SSCS_1_METHOD CLK_SSC_UP_SPREAD #endif From 93e5dc301c87fe6b7bae0b087a15be69e521e657 Mon Sep 17 00:00:00 2001 From: Bhargav Joshi Date: Sun, 6 Sep 2026 03:10:31 +0530 Subject: [PATCH 122/168] dt-bindings: clock: ti,da850-pll: Convert to DT schema Convert TI da850-pll binding from legacy text to dt schema. No functional change is introduced during conversion. Reviewed-by: Rob Herring (Arm) Reviewed-by: David Lechner Link: https://lore.kernel.org/r/20260717-ti-pll-v1-1-f6f9ba8c9b5e@gmail.com Signed-off-by: Bhargav Joshi Signed-off-by: Brian Masney --- .../bindings/clock/ti/davinci/pll.txt | 96 ---------- .../clock/ti/davinci/ti,da850-pll.yaml | 164 ++++++++++++++++++ 2 files changed, 164 insertions(+), 96 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/ti/davinci/pll.txt create mode 100644 Documentation/devicetree/bindings/clock/ti/davinci/ti,da850-pll.yaml diff --git a/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt b/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt deleted file mode 100644 index c9894538315b..000000000000 --- a/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt +++ /dev/null @@ -1,96 +0,0 @@ -Binding for TI DaVinci PLL Controllers - -The PLL provides clocks to most of the components on the SoC. In addition -to the PLL itself, this controller also contains bypasses, gates, dividers, -an multiplexers for various clock signals. - -Required properties: -- compatible: shall be one of: - - "ti,da850-pll0" for PLL0 on DA850/OMAP-L138/AM18XX - - "ti,da850-pll1" for PLL1 on DA850/OMAP-L138/AM18XX -- reg: physical base address and size of the controller's register area. -- clocks: phandles corresponding to the clock names -- clock-names: names of the clock sources - depends on compatible string - - for "ti,da850-pll0", shall be "clksrc", "extclksrc" - - for "ti,da850-pll1", shall be "clksrc" - -Optional properties: -- ti,clkmode-square-wave: Indicates that the board is supplying a square - wave input on the OSCIN pin instead of using a crystal oscillator. - This property is only valid when compatible = "ti,da850-pll0". - - -Optional child nodes: - -pllout - Describes the main PLL clock output (before POSTDIV). The node name must - be "pllout". - - Required properties: - - #clock-cells: shall be 0 - -sysclk - Describes the PLLDIVn divider clocks that provide the SYSCLKn clock - domains. The node name must be "sysclk". Consumers of this node should - use "n" in "SYSCLKn" as the index parameter for the clock cell. - - Required properties: - - #clock-cells: shall be 1 - -auxclk - Describes the AUXCLK output of the PLL. The node name must be "auxclk". - This child node is only valid when compatible = "ti,da850-pll0". - - Required properties: - - #clock-cells: shall be 0 - -obsclk - Describes the OBSCLK output of the PLL. The node name must be "obsclk". - - Required properties: - - #clock-cells: shall be 0 - - -Examples: - - pll0: clock-controller@11000 { - compatible = "ti,da850-pll0"; - reg = <0x11000 0x1000>; - clocks = <&ref_clk>, <&pll1_sysclk 3>; - clock-names = "clksrc", "extclksrc"; - ti,clkmode-square-wave; - - pll0_pllout: pllout { - #clock-cells = <0>; - }; - - pll0_sysclk: sysclk { - #clock-cells = <1>; - }; - - pll0_auxclk: auxclk { - #clock-cells = <0>; - }; - - pll0_obsclk: obsclk { - #clock-cells = <0>; - }; - }; - - pll1: clock-controller@21a000 { - compatible = "ti,da850-pll1"; - reg = <0x21a000 0x1000>; - clocks = <&ref_clk>; - clock-names = "clksrc"; - - pll0_sysclk: sysclk { - #clock-cells = <1>; - }; - - pll0_obsclk: obsclk { - #clock-cells = <0>; - }; - }; - -Also see: -- Documentation/devicetree/bindings/clock/clock-bindings.txt diff --git a/Documentation/devicetree/bindings/clock/ti/davinci/ti,da850-pll.yaml b/Documentation/devicetree/bindings/clock/ti/davinci/ti,da850-pll.yaml new file mode 100644 index 000000000000..c6563290a702 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/davinci/ti,da850-pll.yaml @@ -0,0 +1,164 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti/davinci/ti,da850-pll.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI DaVinci PLL Controllers + +maintainers: + - David Lechner + +description: + The PLL provides clocks to most of the components on the SoC. In addition to + the PLL itself, this controller also contains bypasses, gates, dividers, an + multiplexers for various clock signals. + +properties: + compatible: + enum: + - ti,da850-pll0 + - ti,da850-pll1 + + reg: + maxItems: 1 + + clocks: + minItems: 1 + items: + - description: Primary reference clock input + - description: External clock source + + clock-names: + minItems: 1 + items: + - const: clksrc + - const: extclksrc + + ti,clkmode-square-wave: + type: boolean + description: + Indicates that the board is supplying a square wave input on the OSCIN + pin instead of using a crystal oscillator. + + pllout: + type: object + description: + Main PLL clock output before POSTDIV. + + properties: + '#clock-cells': + const: 0 + + required: + - '#clock-cells' + + additionalProperties: false + + sysclk: + type: object + description: + PLLDIVn divider clocks that provide the SYSCLKn clock domains. Consumers + of this node should use "n" in "SYSCLKn" as the index parameter for the + clock cell. + + properties: + '#clock-cells': + const: 1 + + required: + - '#clock-cells' + + additionalProperties: false + + auxclk: + type: object + description: + AUXCLK output of the PLL + + properties: + '#clock-cells': + const: 0 + + required: + - '#clock-cells' + + additionalProperties: false + + obsclk: + type: object + description: + the OBSCLK output of the PLL. + + properties: + '#clock-cells': + const: 0 + + required: + - '#clock-cells' + + additionalProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + +additionalProperties: false + +allOf: + - if: + properties: + compatible: + const: ti,da850-pll1 + then: + properties: + clocks: + maxItems: 1 + clock-names: + maxItems: 1 + ti,clkmode-square-wave: false + auxclk: false + +examples: + - | + clock-controller@11000 { + compatible = "ti,da850-pll0"; + reg = <0x11000 0x1000>; + clocks = <&ref_clk>, <&pll1_sysclk 3>; + clock-names = "clksrc", "extclksrc"; + ti,clkmode-square-wave; + + pllout { + #clock-cells = <0>; + }; + + sysclk { + #clock-cells = <1>; + }; + + auxclk { + #clock-cells = <0>; + }; + + obsclk { + #clock-cells = <0>; + }; + }; + + - | + clock-controller@21a000 { + compatible = "ti,da850-pll1"; + reg = <0x21a000 0x1000>; + clocks = <&ref_clk>; + clock-names = "clksrc"; + + sysclk { + #clock-cells = <1>; + }; + + obsclk { + #clock-cells = <0>; + }; + }; From 26881ca4ad352d4003c6d6acc1343ecd1823953f Mon Sep 17 00:00:00 2001 From: Bhargav Joshi Date: Sun, 6 Sep 2026 03:02:39 +0530 Subject: [PATCH 123/168] dt-bindings: clock: ti,dra7-atl-clock: convert to DT schema Convert the clock output portion of the DRA7 ATL (Audio Tracking Logic) binding from text to DT schema. property clock-output-names is added that is used by existing dts/dtsi. Reviewed-by: Rob Herring (Arm) Signed-off-by: Bhargav Joshi Signed-off-by: Brian Masney --- .../devicetree/bindings/clock/ti/dra7-atl.txt | 38 ------------------- .../bindings/clock/ti/ti,dra7-atl-clock.yaml | 38 +++++++++++++++++++ 2 files changed, 38 insertions(+), 38 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/ti/ti,dra7-atl-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt b/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt index 68504079f99f..e3c05844ae86 100644 --- a/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt +++ b/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt @@ -9,20 +9,6 @@ signals - can compensate the drift between the two ws signal. In order to provide the support for ATL and its output clocks (which can be used internally within the SoC or external components) two sets of bindings is needed: -Clock tree binding: -This binding uses the common clock binding[1]. -To be able to integrate the ATL clocks with DT clock tree. -Provides ccf level representation of the ATL clocks to be used by drivers. -Since the clock instances are part of a single IP this binding is used as a node -for the DT clock tree, the IP driver is needed to handle the actual configuration -of the IP. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt - -Required properties: -- compatible : shall be "ti,dra7-atl-clock" -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : link phandles to functional clock of ATL Binding for the IP driver: This binding is used to configure the IP driver which is going to handle the @@ -47,30 +33,6 @@ For valid word select signals, see the dt-bindings/clock/ti-dra7-atl.h include file. Examples: -/* clock bindings for atl provided clocks */ -atl_clkin0_ck: atl_clkin0_ck { - #clock-cells = <0>; - compatible = "ti,dra7-atl-clock"; - clocks = <&atl_gfclk_mux>; -}; - -atl_clkin1_ck: atl_clkin1_ck { - #clock-cells = <0>; - compatible = "ti,dra7-atl-clock"; - clocks = <&atl_gfclk_mux>; -}; - -atl_clkin2_ck: atl_clkin2_ck { - #clock-cells = <0>; - compatible = "ti,dra7-atl-clock"; - clocks = <&atl_gfclk_mux>; -}; - -atl_clkin3_ck: atl_clkin3_ck { - #clock-cells = <0>; - compatible = "ti,dra7-atl-clock"; - clocks = <&atl_gfclk_mux>; -}; /* binding for the IP */ atl: atl@4843c000 { diff --git a/Documentation/devicetree/bindings/clock/ti/ti,dra7-atl-clock.yaml b/Documentation/devicetree/bindings/clock/ti/ti,dra7-atl-clock.yaml new file mode 100644 index 000000000000..c0795f4abcfa --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/ti,dra7-atl-clock.yaml @@ -0,0 +1,38 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti/ti,dra7-atl-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI DRA7 ATL (Audio Tracking Logic) clock output + +maintainers: + - Peter Ujfalusi + +properties: + compatible: + const: ti,dra7-atl-clock + + "#clock-cells": + const: 0 + + clocks: + maxItems: 1 + + clock-output-names: + maxItems: 1 + +required: + - compatible + - "#clock-cells" + - clocks + +additionalProperties: false + +examples: + - | + atl_clkin0_ck { + compatible = "ti,dra7-atl-clock"; + #clock-cells = <0>; + clocks = <&atl_gfclk_mux>; + }; From f31b15c9bbb03b1560fbd137439cd9fba037bace Mon Sep 17 00:00:00 2001 From: Bhargav Joshi Date: Sun, 6 Sep 2026 03:02:40 +0530 Subject: [PATCH 124/168] dt-bindings: clock: ti,dra7-atl: convert to dt-schema Convert the IP driver portion of the DRA7 ATL (Audio Tracking Logic) binding from the freeform text binding to dt-schema. Together with ti,dra7-atl-clock.yaml this fully replaces dra7-atl.txt. ti,hwmods is marked deprecated as modern DTS uses ti,sysc target-module wrappers and the property is absent from current dra7-l4.dtsi. bws/aws maximum set to 15 per the 16 mux sources in dt-bindings/clock/ti-dra7-atl.h. Reviewed-by: Rob Herring (Arm) Signed-off-by: Bhargav Joshi Signed-off-by: Brian Masney --- .../devicetree/bindings/clock/ti/dra7-atl.txt | 56 ---------- .../bindings/clock/ti/ti,dra7-atl.yaml | 100 ++++++++++++++++++ 2 files changed, 100 insertions(+), 56 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/ti/dra7-atl.txt create mode 100644 Documentation/devicetree/bindings/clock/ti/ti,dra7-atl.yaml diff --git a/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt b/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt deleted file mode 100644 index e3c05844ae86..000000000000 --- a/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt +++ /dev/null @@ -1,56 +0,0 @@ -Device Tree Clock bindings for ATL (Audio Tracking Logic) of DRA7 SoC. - -The ATL IP is used to generate clock to be used to synchronize baseband and -audio codec. A single ATL IP provides four ATL clock instances sharing the same -functional clock but can be configured to provide different clocks. -ATL can maintain a clock averages to some desired frequency based on the bws/aws -signals - can compensate the drift between the two ws signal. - -In order to provide the support for ATL and its output clocks (which can be used -internally within the SoC or external components) two sets of bindings is needed: - - -Binding for the IP driver: -This binding is used to configure the IP driver which is going to handle the -configuration of the IP for the ATL clock instances. - -Required properties: -- compatible : shall be "ti,dra7-atl" -- reg : base address for the ATL IP -- ti,provided-clocks : List of phandles to the clocks associated with the ATL -- clocks : link phandles to functional clock of ATL -- clock-names : Shall be set to "fck" -- ti,hwmods : Shall be set to "atl" - -Optional properties: -Configuration of ATL instances: -- atl{0/1/2/3} { - - bws : Baseband word select signal selection - - aws : Audio word select signal selection -}; - -For valid word select signals, see the dt-bindings/clock/ti-dra7-atl.h include -file. - -Examples: - -/* binding for the IP */ -atl: atl@4843c000 { - compatible = "ti,dra7-atl"; - reg = <0x4843c000 0x3ff>; - ti,hwmods = "atl"; - ti,provided-clocks = <&atl_clkin0_ck>, <&atl_clkin1_ck>, - <&atl_clkin2_ck>, <&atl_clkin3_ck>; - clocks = <&atl_gfclk_mux>; - clock-names = "fck"; -}; - -#include - -&atl { - - atl2 { - bws = ; - aws = ; - }; -}; diff --git a/Documentation/devicetree/bindings/clock/ti/ti,dra7-atl.yaml b/Documentation/devicetree/bindings/clock/ti/ti,dra7-atl.yaml new file mode 100644 index 000000000000..f4bb233be83d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/ti,dra7-atl.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti/ti,dra7-atl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI DRA7 ATL (Audio Tracking Logic) Clock Controller + +maintainers: + - Peter Ujfalusi + +description: + The ATL IP is used to generate clock to be used to synchronize baseband and + audio codec. A single ATL IP provides four ATL clock instances sharing the + same functional clock but can be configured to provide different clocks. + ATL can maintain a clock averages to some desired frequency based on the + bws/aws signals - can compensate the drift between the two ws signal. + + See also Documentation/devicetree/bindings/clock/ti/ti,dra7-atl-clock.yaml + +properties: + compatible: + const: ti,dra7-atl + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: fck + + ti,provided-clocks: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + List of phandles to the clocks associated with the ATL. + minItems: 4 + maxItems: 4 + items: + maxItems: 1 + + ti,hwmods: + $ref: /schemas/types.yaml#/definitions/string + description: + Name of the hwmod associated with the ATL. + deprecated: true + const: atl + +patternProperties: + "^atl[0-3]$": + type: object + additionalProperties: false + description: + Configuration of ATL instances. + + properties: + bws: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Baseband word select signal selection. + maximum: 15 + + aws: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Audio word select signal selection. + maximum: 15 + + required: + - bws + - aws + +required: + - compatible + - reg + - clocks + - clock-names + - ti,provided-clocks + +additionalProperties: false + +examples: + - | + #include + + atl@4843c000 { + compatible = "ti,dra7-atl"; + reg = <0x4843c000 0x3ff>; + clocks = <&atl_gfclk_mux>; + clock-names = "fck"; + ti,provided-clocks = <&atl_clkin0_ck>, <&atl_clkin1_ck>, + <&atl_clkin2_ck>, <&atl_clkin3_ck>; + + atl2 { + bws = ; + aws = ; + }; + }; From 307bee2e5a6ede1c50dcbf1ef803c7be44fbbcb6 Mon Sep 17 00:00:00 2001 From: Bhargav Joshi Date: Sun, 6 Sep 2026 02:58:32 +0530 Subject: [PATCH 125/168] dt-bindings: clock: ti,DM814x-ADPLL: Convert to DT schema Convert the Texas Instruments DM814x ADPLL clock binding to DT schema format. Add 'clock-output-names' as required which was missing in legacy binding, as the driver (clk-adpll.c) mandates it and fails probing if it is missing. Reviewed-by: Rob Herring (Arm) Signed-off-by: Bhargav Joshi Signed-off-by: Brian Masney --- .../devicetree/bindings/clock/ti/adpll.txt | 39 -------- .../clock/ti/ti,dm814-adpll-clock.yaml | 88 +++++++++++++++++++ 2 files changed, 88 insertions(+), 39 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/ti/adpll.txt create mode 100644 Documentation/devicetree/bindings/clock/ti/ti,dm814-adpll-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/ti/adpll.txt b/Documentation/devicetree/bindings/clock/ti/adpll.txt deleted file mode 100644 index 3122360adcf3..000000000000 --- a/Documentation/devicetree/bindings/clock/ti/adpll.txt +++ /dev/null @@ -1,39 +0,0 @@ -Binding for Texas Instruments ADPLL clock. - -This binding uses the common clock binding[1]. It assumes a -register-mapped ADPLL with two to three selectable input clocks -and three to four children. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt - -Required properties: -- compatible : shall be one of "ti,dm814-adpll-s-clock" or - "ti,dm814-adpll-lj-clock" depending on the type of the ADPLL -- #clock-cells : from common clock binding; shall be set to 1. -- clocks : link phandles of parent clocks clkinp and clkinpulow, note - that the adpll-s-clock also has an optional clkinphif -- reg : address and length of the register set for controlling the ADPLL. - -Examples: - adpll_mpu_ck: adpll@40 { - #clock-cells = <1>; - compatible = "ti,dm814-adpll-s-clock"; - reg = <0x40 0x40>; - clocks = <&devosc_ck &devosc_ck &devosc_ck>; - clock-names = "clkinp", "clkinpulow", "clkinphif"; - clock-output-names = "481c5040.adpll.dcoclkldo", - "481c5040.adpll.clkout", - "481c5040.adpll.clkoutx2", - "481c5040.adpll.clkouthif"; - }; - - adpll_dsp_ck: adpll@80 { - #clock-cells = <1>; - compatible = "ti,dm814-adpll-lj-clock"; - reg = <0x80 0x30>; - clocks = <&devosc_ck &devosc_ck>; - clock-names = "clkinp", "clkinpulow"; - clock-output-names = "481c5080.adpll.dcoclkldo", - "481c5080.adpll.clkout", - "481c5080.adpll.clkoutldo"; - }; diff --git a/Documentation/devicetree/bindings/clock/ti/ti,dm814-adpll-clock.yaml b/Documentation/devicetree/bindings/clock/ti/ti,dm814-adpll-clock.yaml new file mode 100644 index 000000000000..9676ab2d8705 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/ti,dm814-adpll-clock.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti/ti,dm814-adpll-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments DM814x ADPLL Clock + +maintainers: + - Tony Lindgren + +description: + The ADPLL is a register-mapped clock generator found on TI DM814x SoCs. It + provides multiple output clocks from two or three selectable input clocks and + three to four children. + +properties: + compatible: + enum: + - ti,dm814-adpll-s-clock + - ti,dm814-adpll-lj-clock + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + clocks: + minItems: 2 + maxItems: 3 + + clock-names: + minItems: 2 + items: + - const: clkinp + - const: clkinpulow + - const: clkinphif + + clock-output-names: + minItems: 3 + maxItems: 4 + +required: + - compatible + - reg + - '#clock-cells' + - clocks + - clock-output-names + +if: + properties: + compatible: + contains: + const: ti,dm814-adpll-s-clock +then: + properties: + clocks: + minItems: 3 + clock-names: + minItems: 3 + clock-output-names: + minItems: 4 + +else: + properties: + clocks: + maxItems: 2 + clock-names: + maxItems: 2 + clock-output-names: + maxItems: 3 + +additionalProperties: false + +examples: + - | + adpll@40 { + compatible = "ti,dm814-adpll-s-clock"; + reg = <0x40 0x40>; + #clock-cells = <1>; + clocks = <&devosc_ck &devosc_ck &devosc_ck>; + clock-names = "clkinp", "clkinpulow", "clkinphif"; + clock-output-names = "481c5040.adpll.dcoclkldo", + "481c5040.adpll.clkout", + "481c5040.adpll.clkoutx2", + "481c5040.adpll.clkouthif"; + }; From 64461f89a37a788789a1ce22979e3c0695ae0497 Mon Sep 17 00:00:00 2001 From: Bhargav Joshi Date: Sun, 6 Sep 2026 02:52:04 +0530 Subject: [PATCH 126/168] dt-bindings: clock: ti,dm816-fapll-clock: Convert to DT schema Convert the Texas Instruments DM816 FAPLL clock binding from plain text to YAML DT schema. The text documented #clock-cells to be set as 0, while the example and existing dt and driver require it to be 1. The schema now strictly enforces #clock-cells = <1>. Properties clock-indices and clock-output-names are documented in the binding and added as required as driver strictly requires it and existing dt already use this property. Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20260717-ti-fapll-clock-v1-1-1b684cb2543b@gmail.com Signed-off-by: Bhargav Joshi Signed-off-by: Brian Masney --- .../devicetree/bindings/clock/ti/fapll.txt | 31 -------- .../clock/ti/ti,dm816-fapll-clock.yaml | 71 +++++++++++++++++++ 2 files changed, 71 insertions(+), 31 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/ti/fapll.txt create mode 100644 Documentation/devicetree/bindings/clock/ti/ti,dm816-fapll-clock.yaml diff --git a/Documentation/devicetree/bindings/clock/ti/fapll.txt b/Documentation/devicetree/bindings/clock/ti/fapll.txt deleted file mode 100644 index 88986ef39ddd..000000000000 --- a/Documentation/devicetree/bindings/clock/ti/fapll.txt +++ /dev/null @@ -1,31 +0,0 @@ -Binding for Texas Instruments FAPLL clock. - -This binding uses the common clock binding[1]. It assumes a -register-mapped FAPLL with usually two selectable input clocks -(reference clock and bypass clock), and one or more child -syntesizers. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt - -Required properties: -- compatible : shall be "ti,dm816-fapll-clock" -- #clock-cells : from common clock binding; shall be set to 0. -- clocks : link phandles of parent clocks (clk-ref and clk-bypass) -- reg : address and length of the register set for controlling the FAPLL. - -Examples: - main_fapll: main_fapll { - #clock-cells = <1>; - compatible = "ti,dm816-fapll-clock"; - reg = <0x400 0x40>; - clocks = <&sys_clkin_ck &sys_clkin_ck>; - clock-indices = <1>, <2>, <3>, <4>, <5>, - <6>, <7>; - clock-output-names = "main_pll_clk1", - "main_pll_clk2", - "main_pll_clk3", - "main_pll_clk4", - "main_pll_clk5", - "main_pll_clk6", - "main_pll_clk7"; - }; diff --git a/Documentation/devicetree/bindings/clock/ti/ti,dm816-fapll-clock.yaml b/Documentation/devicetree/bindings/clock/ti/ti,dm816-fapll-clock.yaml new file mode 100644 index 000000000000..423b7405e398 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/ti/ti,dm816-fapll-clock.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/ti/ti,dm816-fapll-clock.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments FAPLL clock + +maintainers: + - Tony Lindgren + - Tero Kristo + +description: + FAPLL is register-mapped with usually two selectable input clocks + (reference clock and bypass clock), and one or more child synthesizers. + +properties: + compatible: + const: ti,dm816-fapll-clock + + "#clock-cells": + const: 1 + + reg: + maxItems: 1 + + clocks: + items: + - description: parent clock clk-ref + - description: parent clock clk-bypass + + clock-indices: + description: + Maps child synthesizers to physical indices 1-7. Index 0 is physically + reserved for the Master PLL. + minItems: 1 + maxItems: 7 + items: + minimum: 1 + maximum: 7 + + clock-output-names: + description: + Names of the child synthesizer outputs. The length of this array must + match clock-indices. + minItems: 1 + maxItems: 7 + +required: + - compatible + - reg + - clocks + - "#clock-cells" + - clock-indices + - clock-output-names + +additionalProperties: false + +examples: + - | + clock-controller@400 { + #clock-cells = <1>; + compatible = "ti,dm816-fapll-clock"; + reg = <0x400 0x40>; + clocks = <&sys_clkin_ck &sys_clkin_ck>; + clock-indices = <1>, <2>, <3>, <4>, <5>, <6>, <7>; + clock-output-names = "main_pll_clk1", "main_pll_clk2", "main_pll_clk3", + "main_pll_clk4", "main_pll_clk5", "main_pll_clk6", + "main_pll_clk7"; + + }; From d0b72c88671b3c46342bbebc9b90280890436c98 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Sun, 19 Jul 2026 14:43:49 -0700 Subject: [PATCH 127/168] clk: mmp: allow COMPILE_TEST builds The MMP clock directory is only entered for ARCH_MMP, even though the PXA1908 and MMP2 audio clock symbols can already be selected for COMPILE_TEST. Add a hidden MMP clock family gate, select it from the compile-testable MMP clock symbols, and use that symbol for the parent Makefile descent. Keep ARCH_MMP as the default provider for existing platform builds. Tested with: make LLVM=1 ARCH=loongarch drivers/clk/mmp/ Assisted-by: Codex:GPT-5.5 Signed-off-by: Rosen Penev Signed-off-by: Brian Masney --- drivers/clk/Kconfig | 2 ++ drivers/clk/Makefile | 2 +- drivers/clk/mmp/Kconfig | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e0cc4ebafb5e..ec39e8375adb 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -451,12 +451,14 @@ config COMMON_CLK_STM32H7 config COMMON_CLK_MMP2 def_bool COMMON_CLK && (MACH_MMP2_DT || MACH_MMP3_DT) + select COMMON_CLK_MMP help Support for Marvell MMP2 and MMP3 SoC clocks config COMMON_CLK_MMP2_AUDIO tristate "Clock driver for MMP2 Audio subsystem" depends on COMMON_CLK_MMP2 || COMPILE_TEST + select COMMON_CLK_MMP help This driver supports clocks for Audio subsystem on MMP2 SoC. diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 2d8f60254373..e742a0886470 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -144,7 +144,7 @@ obj-y += mediatek/ obj-$(CONFIG_ARCH_MESON) += meson/ obj-y += microchip/ ifeq ($(CONFIG_COMMON_CLK), y) -obj-$(CONFIG_ARCH_MMP) += mmp/ +obj-$(CONFIG_COMMON_CLK_MMP) += mmp/ endif obj-y += mstar/ obj-y += mvebu/ diff --git a/drivers/clk/mmp/Kconfig b/drivers/clk/mmp/Kconfig index b0d2fea3cda5..35a069034b28 100644 --- a/drivers/clk/mmp/Kconfig +++ b/drivers/clk/mmp/Kconfig @@ -1,10 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only +config COMMON_CLK_MMP + bool + default ARCH_MMP + config COMMON_CLK_PXA1908 bool "Clock driver for Marvell PXA1908" depends on ARCH_MMP || COMPILE_TEST depends on OF default y if ARCH_MMP && ARM64 + select COMMON_CLK_MMP select AUXILIARY_BUS help This driver supports the Marvell PXA1908 SoC clocks. From b6685c30d15cd7f28c40b2daaeacc00f21b2f12a Mon Sep 17 00:00:00 2001 From: Pengpeng Hou Date: Sun, 20 Sep 2026 11:41:24 +0800 Subject: [PATCH 128/168] clk: si5351: fail prepare when PLL reset times out The clock prepare path requests a PLL reset when the platform data requires a deterministic output phase. The reset helper logs polling errors but returns no status, so prepare still enables the output and reports success when the reset did not complete. Return the poll result to prepare, restore the output power-down bit on failure, and leave the output disabled. XTAL and CLKIN inputs continue to bypass PLL reset successfully. The issue was found by our static-analysis tool. Fixes: 5142cbcea324 ("clk: si5351: Wait for bit clear after PLL reset") Reviewed-by: Brian Masney Assisted-by: gpt 5 Signed-off-by: Pengpeng Hou Signed-off-by: Brian Masney --- drivers/clk/clk-si5351.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index 20b0c3c48b86..70daba62305c 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -907,7 +907,7 @@ static int _si5351_clkout_set_disable_state( return 0; } -static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num) +static int _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num) { u8 val = si5351_reg_read(drvdata, SI5351_CLK0_CTRL + num); u8 mask = val & SI5351_CLK_PLL_SELECT ? SI5351_PLL_RESET_B : @@ -918,7 +918,7 @@ static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num switch (val & SI5351_CLK_INPUT_MASK) { case SI5351_CLK_INPUT_XTAL: case SI5351_CLK_INPUT_CLKIN: - return; /* pll not used, no need to reset */ + return 0; /* pll not used, no need to reset */ } si5351_reg_write(drvdata, SI5351_PLL_RESET, mask); @@ -931,6 +931,8 @@ static void _si5351_clkout_reset_pll(struct si5351_driver_data *drvdata, int num dev_dbg(&drvdata->client->dev, "%s - %s: pll = %d\n", __func__, clk_hw_get_name(&drvdata->clkout[num].hw), (val & SI5351_CLK_PLL_SELECT) ? 1 : 0); + + return err; } static int si5351_clkout_prepare(struct clk_hw *hw) @@ -947,8 +949,18 @@ static int si5351_clkout_prepare(struct clk_hw *hw) * Do a pll soft reset on the parent pll -- needed to get a * deterministic phase relationship between the output clocks. */ - if (pdata->clkout[hwdata->num].pll_reset) - _si5351_clkout_reset_pll(hwdata->drvdata, hwdata->num); + if (pdata->clkout[hwdata->num].pll_reset) { + int ret; + + ret = _si5351_clkout_reset_pll(hwdata->drvdata, hwdata->num); + if (ret) { + si5351_set_bits(hwdata->drvdata, + SI5351_CLK0_CTRL + hwdata->num, + SI5351_CLK_POWERDOWN, + SI5351_CLK_POWERDOWN); + return ret; + } + } si5351_set_bits(hwdata->drvdata, SI5351_OUTPUT_ENABLE_CTRL, (1 << hwdata->num), 0); From f036decc4434323b47b58ad9508fe27d8c9087c2 Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Thu, 14 May 2026 17:27:17 +0800 Subject: [PATCH 129/168] clk: correct clk_div_mask() return value for width == 32 The macro clk_div_mask() currently wraps to zero when width is 32 due to 1 << 32 being undefined behavior. This leads to incorrect mask generation and prevents correct retrieval of register field values for 32-bit-wide dividers. Although it is unlikely to exhaust all U32_MAX div, some clock IPs may rely on a 32-bit val entry in their div_table to match a div, so providing a full 32-bit mask is necessary. Fix this by using the standard GENMASK() macro. This safely resolves the undefined behavior on both 32-bit and 64-bit architectures, while also benefiting from the built-in compile-time type and bounds checking provided by the GENMASK() macro. Cc: Troy Mitchell Cc: Brian Masney Signed-off-by: Junhui Liu Reviewed-by: Troy Mitchell Reviewed-by: Brian Masney Reviewed-by: Jerome Brunet Signed-off-by: Brian Masney --- include/linux/clk-provider.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 58902e8dfd68..a355d1ee5189 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -7,6 +7,7 @@ #define __LINUX_CLK_PROVIDER_H #include +#include #include #include @@ -757,7 +758,7 @@ struct clk_divider { spinlock_t *lock; }; -#define clk_div_mask(width) ((1 << (width)) - 1) +#define clk_div_mask(width) GENMASK((width) - 1, 0) #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) #define CLK_DIVIDER_ONE_BASED BIT(0) From 155d900e4c7d124dfc1fef598fecc6d17a1ea693 Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Thu, 14 May 2026 17:27:18 +0800 Subject: [PATCH 130/168] dt-bindings: clock: add Anlogic DR1V90 CRU Add the Clock and Reset Unit (CRU) support for the Anlogic DR1V90 SoC, which is responsible for clock and reset management. Reviewed-by: Conor Dooley Signed-off-by: Junhui Liu Signed-off-by: Brian Masney --- .../bindings/clock/anlogic,dr1v90-cru.yaml | 60 +++++++++++++++++++ .../dt-bindings/clock/anlogic,dr1v90-cru.h | 46 ++++++++++++++ .../dt-bindings/reset/anlogic,dr1v90-cru.h | 41 +++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/anlogic,dr1v90-cru.yaml create mode 100644 include/dt-bindings/clock/anlogic,dr1v90-cru.h create mode 100644 include/dt-bindings/reset/anlogic,dr1v90-cru.h diff --git a/Documentation/devicetree/bindings/clock/anlogic,dr1v90-cru.yaml b/Documentation/devicetree/bindings/clock/anlogic,dr1v90-cru.yaml new file mode 100644 index 000000000000..11a92588e494 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/anlogic,dr1v90-cru.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/anlogic,dr1v90-cru.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Anlogic DR1V90 Clock and Reset Unit (CRU) + +maintainers: + - Junhui Liu + +properties: + compatible: + const: anlogic,dr1v90-cru + + reg: + maxItems: 1 + + clocks: + items: + - description: Main oscillator + - description: External CAN clock + - description: External WDT clock + + clock-names: + items: + - const: osc + - const: can_ext + - const: wdt_ext + + "#clock-cells": + const: 1 + description: + Refer for valid indices. + + "#reset-cells": + const: 1 + description: + Refer for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - "#clock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + clock-controller@f8801000 { + compatible = "anlogic,dr1v90-cru"; + reg = <0xf8801000 0x400>; + clocks = <&osc>, <&can_ext>, <&wdt_ext>; + clock-names = "osc", "can_ext", "wdt_ext"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/include/dt-bindings/clock/anlogic,dr1v90-cru.h b/include/dt-bindings/clock/anlogic,dr1v90-cru.h new file mode 100644 index 000000000000..664daf3946a7 --- /dev/null +++ b/include/dt-bindings/clock/anlogic,dr1v90-cru.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) 2024-2025 Anlogic, Inc. + * Copyright (C) 2025 Junhui Liu + */ + +#ifndef _DT_BINDINGS_CLOCK_ANLOGIC_DR1V90_CRU_H_ +#define _DT_BINDINGS_CLOCK_ANLOGIC_DR1V90_CRU_H_ + +#define CLK_OSC_DIV2 0 +#define CLK_CPU_PLL 1 +#define CLK_CPU_PLL_4X 2 +#define CLK_CPU_4X 3 +#define CLK_CPU_2X 4 +#define CLK_CPU_1X 5 +#define CLK_IO_PLL 6 +#define CLK_IO_1000M 7 +#define CLK_IO_400M 8 +#define CLK_IO_25M 9 +#define CLK_IO_80M 10 +#define CLK_IO_400M_DIV2 11 +#define CLK_IO_400M_DIV4 12 +#define CLK_IO_400M_DIV8 13 +#define CLK_IO_400M_DIV16 14 +#define CLK_QSPI 15 +#define CLK_SPI 16 +#define CLK_SMC 17 +#define CLK_SDIO 18 +#define CLK_GPIO_DB 19 +#define CLK_EFUSE 20 +#define CLK_TVS 21 +#define CLK_TRNG 22 +#define CLK_OSC_DIV 23 +#define CLK_PWM 24 +#define CLK_FCLK0 25 +#define CLK_FCLK1 26 +#define CLK_FCLK2 27 +#define CLK_FCLK3 28 +#define CLK_WDT_SEL 29 +#define CLK_EFUSE_SEL 30 +#define CLK_CAN_SEL 31 +#define CLK_CPU_SEL 32 +#define CLK_CAN0 33 +#define CLK_CAN1 34 + +#endif /* _DT_BINDINGS_CLOCK_ANLOGIC_DR1V90_CRU_H_ */ diff --git a/include/dt-bindings/reset/anlogic,dr1v90-cru.h b/include/dt-bindings/reset/anlogic,dr1v90-cru.h new file mode 100644 index 000000000000..c5b7aae1ab6a --- /dev/null +++ b/include/dt-bindings/reset/anlogic,dr1v90-cru.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) 2025 Junhui Liu + */ + +#ifndef _DT_BINDINGS_RESET_ANLOGIC_DR1V90_CRU_H_ +#define _DT_BINDINGS_RESET_ANLOGIC_DR1V90_CRU_H_ + +#define RESET_OCM 0 +#define RESET_QSPI 1 +#define RESET_SMC 2 +#define RESET_WDT 3 +#define RESET_DMAC_AXI 4 +#define RESET_DMAC_AHB 5 +#define RESET_NPU 6 +#define RESET_JPU 7 +#define RESET_DDRBUS 8 +#define RESET_NIC_HP0 9 +#define RESET_NIC_HP1 10 +#define RESET_NIC_GP0M 11 +#define RESET_NIC_GP1M 12 +#define RESET_GPIO 13 +#define RESET_IPC 14 +#define RESET_USB0 15 +#define RESET_USB1 16 +#define RESET_GBE0 17 +#define RESET_GBE1 18 +#define RESET_SDIO0 19 +#define RESET_SDIO1 20 +#define RESET_UART0 21 +#define RESET_UART1 22 +#define RESET_SPI0 23 +#define RESET_SPI1 24 +#define RESET_CAN0 25 +#define RESET_CAN1 26 +#define RESET_TTC0 27 +#define RESET_TTC1 28 +#define RESET_I2C0 29 +#define RESET_I2C1 30 + +#endif /* _DT_BINDINGS_RESET_ANLOGIC_DR1V90_CRU_H_ */ From c4e2f5e69ba4298c10ab5a64525379ca48ca921e Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Thu, 14 May 2026 17:27:19 +0800 Subject: [PATCH 131/168] clk: anlogic: add cru support for Anlogic DR1V90 SoC The Clock and Reset Unit (CRU) in the Anlogic DR1V90 SoC provides management for the clock and reset. The clock driver includes support for: - Generic clocks: fixed-factor, divider, mux and gate. - PLL: "nm" type (parent * n / m) and "c" type (parent / c). These PLLs are set up by the FSBL and mared as "don't touch" in the datasheet, so only the recal_rate() op is provided. - Divider with gate: support both division and gating (by setting value to 0); some of them require a minimum divider value to avoid timing issues. This also prepares the structure for the reset controller support, registering an auxiliary device for resets. Signed-off-by: Junhui Liu Signed-off-by: Brian Masney --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/anlogic/Kconfig | 21 +++ drivers/clk/anlogic/Makefile | 7 + drivers/clk/anlogic/cru-dr1v90.c | 192 ++++++++++++++++++++++++++ drivers/clk/anlogic/cru_dr1.c | 226 +++++++++++++++++++++++++++++++ drivers/clk/anlogic/cru_dr1.h | 117 ++++++++++++++++ 7 files changed, 565 insertions(+) create mode 100644 drivers/clk/anlogic/Kconfig create mode 100644 drivers/clk/anlogic/Makefile create mode 100644 drivers/clk/anlogic/cru-dr1v90.c create mode 100644 drivers/clk/anlogic/cru_dr1.c create mode 100644 drivers/clk/anlogic/cru_dr1.h diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index ec39e8375adb..983bf74b86fb 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -510,6 +510,7 @@ config COMMON_CLK_RPMI source "drivers/clk/actions/Kconfig" source "drivers/clk/analogbits/Kconfig" +source "drivers/clk/anlogic/Kconfig" source "drivers/clk/aspeed/Kconfig" source "drivers/clk/bcm/Kconfig" source "drivers/clk/cix/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e742a0886470..d94de2988167 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -126,6 +126,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o # please keep this section sorted lexicographically by directory path name obj-y += actions/ obj-y += analogbits/ +obj-y += anlogic/ obj-y += aspeed/ obj-$(CONFIG_COMMON_CLK_AT91) += at91/ obj-$(CONFIG_ARCH_ARTPEC) += axis/ diff --git a/drivers/clk/anlogic/Kconfig b/drivers/clk/anlogic/Kconfig new file mode 100644 index 000000000000..b3b17540176d --- /dev/null +++ b/drivers/clk/anlogic/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config ANLOGIC_DR1_CRU + tristate "Clock support for Anlogic DR1 series SoCs" + depends on ARCH_ANLOGIC || COMPILE_TEST + select AUXILIARY_BUS + default ARCH_ANLOGIC + help + Say Y to enable clock controller unit support for Anlogic DR1 series + SoCs. + +if ANLOGIC_DR1_CRU + +config ANLOGIC_DR1V90_CRU + tristate "Anlogic DR1V90 clock support" + depends on ARCH_ANLOGIC || COMPILE_TEST + default ARCH_ANLOGIC + help + Support for the Clock and Reset Unit in Anlogic DR1V90 SoCs. + +endif diff --git a/drivers/clk/anlogic/Makefile b/drivers/clk/anlogic/Makefile new file mode 100644 index 000000000000..fab7f29bb097 --- /dev/null +++ b/drivers/clk/anlogic/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_ANLOGIC_DR1_CRU) += anlogic-dr1-cru.o +anlogic-dr1-cru-y += cru_dr1.o + +obj-$(CONFIG_ANLOGIC_DR1V90_CRU) += anlogic-dr1v90-cru.o +anlogic-dr1v90-cru-y += cru-dr1v90.o diff --git a/drivers/clk/anlogic/cru-dr1v90.c b/drivers/clk/anlogic/cru-dr1v90.c new file mode 100644 index 000000000000..b513dfba3dbd --- /dev/null +++ b/drivers/clk/anlogic/cru-dr1v90.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024-2025 Anlogic, Inc. + * Copyright (C) 2026 Junhui Liu + */ + +#include +#include +#include +#include +#include + +#include "cru_dr1.h" + +#include + +static const struct clk_div_table cru_div_table_24[] = { + { 0xFFFFFF, 1 }, { 0x555555, 2 }, { 0x249249, 3 }, { 0x111111, 4 }, + { 0x084210, 5 }, { 0x041041, 6 }, { 0x020408, 7 }, { 0x010101, 8 }, + { 0x008040, 9 }, { 0x004010, 10 }, { 0x002004, 11 }, { 0x001001, 12 }, + { 0x000800, 13 }, { 0x000400, 14 }, { 0x000200, 15 }, { 0x000100, 16 }, + { 0x000080, 17 }, { 0x000040, 18 }, { 0x000020, 19 }, { 0x000010, 20 }, + { 0x000008, 21 }, { 0x000004, 22 }, { 0x000002, 23 }, { 0x000001, 24 }, + { /* sentinel */ } +}; + +static const struct clk_div_table cru_div_table_32[] = { + { 0xFFFFFFFF, 1 }, { 0x55555555, 2 }, { 0x24924924, 3 }, + { 0x11111111, 4 }, { 0x08421084, 5 }, { 0x04104104, 6 }, + { 0x02040810, 7 }, { 0x01010101, 8 }, { 0x00804020, 9 }, + { 0x00401004, 10 }, { 0x00200400, 11 }, { 0x00100100, 12 }, + { 0x00080040, 13 }, { 0x00040010, 14 }, { 0x00020004, 15 }, + { 0x00010001, 16 }, { 0x00008000, 17 }, { 0x00004000, 18 }, + { 0x00002000, 19 }, { 0x00001000, 20 }, { 0x00000800, 21 }, + { 0x00000400, 22 }, { 0x00000200, 23 }, { 0x00000100, 24 }, + { 0x00000080, 25 }, { 0x00000040, 26 }, { 0x00000020, 27 }, + { 0x00000010, 28 }, { 0x00000008, 29 }, { 0x00000004, 30 }, + { 0x00000002, 31 }, { 0x00000001, 32 }, { /* sentinel */ } +}; + +CLK_FIXED_FACTOR_FW_NAME(osc_div2, "osc_div2", "osc", 2, 1, 0); + +CRU_PLL_NM_DEFINE(cpu_pll, CRU_PARENT_NAME(osc), 0x120); +CRU_PLL_C_DEFINE(cpu_pll_4x, CRU_PARENT_HW(cpu_pll), 0x14c); + +CRU_DIV_DEFINE(cpu_4x_div1, CRU_PARENT_HW(cpu_pll_4x), 0x010, 0, 24, + cru_div_table_24, CLK_DIVIDER_READ_ONLY); +CRU_DIV_DEFINE(cpu_4x_div2, CRU_PARENT_HW(cpu_pll_4x), 0x014, 0, 24, + cru_div_table_24, CLK_DIVIDER_READ_ONLY); +CRU_DIV_DEFINE(cpu_4x_div4, CRU_PARENT_HW(cpu_pll_4x), 0x018, 0, 24, + cru_div_table_24, CLK_DIVIDER_READ_ONLY); + +CRU_PLL_NM_DEFINE(io_pll, CRU_PARENT_NAME(osc), 0x220); +CRU_PLL_C_DEFINE(io_1000m, CRU_PARENT_HW(io_pll), 0x248); +CRU_PLL_C_DEFINE(io_400m, CRU_PARENT_HW(io_pll), 0x24c); +CRU_PLL_C_DEFINE(io_25m, CRU_PARENT_HW(io_pll), 0x250); +CRU_PLL_C_DEFINE(io_80m, CRU_PARENT_HW(io_pll), 0x254); + +CRU_DIV_DEFINE(io_400m_div2, CRU_PARENT_HW(io_400m), 0x020, 0, 32, + cru_div_table_32, CLK_DIVIDER_READ_ONLY); +CRU_DIV_DEFINE(io_400m_div4, CRU_PARENT_HW(io_400m), 0x024, 0, 32, + cru_div_table_32, CLK_DIVIDER_READ_ONLY); +CRU_DIV_DEFINE(io_400m_div8, CRU_PARENT_HW(io_400m), 0x028, 0, 32, + cru_div_table_32, CLK_DIVIDER_READ_ONLY); +CRU_DIV_DEFINE(io_400m_div16, CRU_PARENT_HW(io_400m), 0x02c, 0, 32, + cru_div_table_32, CLK_DIVIDER_READ_ONLY); + +CRU_DIV_GATE_DEFINE(qspi, CRU_PARENT_HW(io_1000m), 0x030, 0, 6, NULL, 0, 2); +CRU_DIV_GATE_DEFINE(spi, CRU_PARENT_HW(io_1000m), 0x030, 8, 6, NULL, 0, 4); +CRU_DIV_GATE_DEFINE(smc, CRU_PARENT_HW(io_1000m), 0x030, 16, 6, NULL, 0, 4); +CRU_DIV_DEFINE(sdio, CRU_PARENT_HW(io_400m), 0x030, 24, 6, NULL, 0); + +CRU_DIV_GATE_DEFINE(gpio_db, CRU_PARENT_HW(io_25m), 0x034, 0, 6, NULL, 0, 1); +CRU_DIV_GATE_DEFINE(efuse, CRU_PARENT_HW(io_25m), 0x034, 8, 6, NULL, 0, 1); +CRU_DIV_GATE_DEFINE(tvs, CRU_PARENT_HW(io_25m), 0x034, 16, 6, NULL, 0, 1); +CRU_DIV_GATE_DEFINE(trng, CRU_PARENT_HW(io_25m), 0x034, 24, 7, NULL, 0, 1); + +CRU_DIV_GATE_DEFINE(osc_div, CRU_PARENT_NAME(osc), 0x038, 0, 6, NULL, 0, 1); +CRU_DIV_GATE_DEFINE(pwm, CRU_PARENT_NAME(osc), 0x038, 8, 12, NULL, 0, 1); + +CRU_DIV_GATE_DEFINE(fclk0, CRU_PARENT_HW(io_400m), 0x03c, 0, 6, NULL, 0, 1); +CRU_DIV_GATE_DEFINE(fclk1, CRU_PARENT_HW(io_400m), 0x03c, 8, 6, NULL, 0, 1); +CRU_DIV_GATE_DEFINE(fclk2, CRU_PARENT_HW(io_400m), 0x03c, 16, 6, NULL, 0, 1); +CRU_DIV_GATE_DEFINE(fclk3, CRU_PARENT_HW(io_400m), 0x03c, 24, 6, NULL, 0, 1); + +static const struct clk_parent_data wdt_parents[] = { + CRU_PARENT_HW(osc_div2), + CRU_PARENT_NAME(wdt_ext) +}; +CRU_MUX_DEFINE(wdt_sel, wdt_parents, 0x040, 1, 1); + +static const struct clk_parent_data efuse_parents[] = { + CRU_PARENT_NAME(osc), + CRU_PARENT_DIV_HW(efuse) +}; +CRU_MUX_DEFINE(efuse_sel, efuse_parents, 0x040, 2, 1); + +static const struct clk_parent_data can_parents[] = { + CRU_PARENT_HW(io_80m), + CRU_PARENT_NAME(can_ext) +}; +CRU_MUX_DEFINE(can_sel, can_parents, 0x040, 3, 1); + +static const struct clk_parent_data cpu_parents[] = { + CRU_PARENT_HW(cpu_4x_div1), + CRU_PARENT_HW(cpu_4x_div2) +}; +CRU_MUX_DEFINE(cpu_sel, cpu_parents, 0x040, 5, 1); + +CRU_GATE_DEFINE(can0, CRU_PARENT_HW(can_sel), 0x08c, 20, CLK_GATE_SET_TO_DISABLE); +CRU_GATE_DEFINE(can1, CRU_PARENT_HW(can_sel), 0x08c, 21, CLK_GATE_SET_TO_DISABLE); + +static const struct cru_clk dr1v90_cru_clks[] = { + [CLK_OSC_DIV2] = { &osc_div2.hw, NULL }, + [CLK_CPU_PLL] = { &cpu_pll.hw, &cpu_pll.reg }, + [CLK_CPU_PLL_4X] = { &cpu_pll_4x.hw, &cpu_pll_4x.reg }, + [CLK_CPU_4X] = { &cpu_4x_div1.hw, &cpu_4x_div1.reg }, + [CLK_CPU_2X] = { &cpu_4x_div2.hw, &cpu_4x_div2.reg }, + [CLK_CPU_1X] = { &cpu_4x_div4.hw, &cpu_4x_div4.reg }, + [CLK_IO_PLL] = { &io_pll.hw, &io_pll.reg }, + [CLK_IO_1000M] = { &io_1000m.hw, &io_1000m.reg }, + [CLK_IO_400M] = { &io_400m.hw, &io_400m.reg }, + [CLK_IO_25M] = { &io_25m.hw, &io_25m.reg }, + [CLK_IO_80M] = { &io_80m.hw, &io_80m.reg }, + [CLK_IO_400M_DIV2] = { &io_400m_div2.hw, &io_400m_div2.reg }, + [CLK_IO_400M_DIV4] = { &io_400m_div4.hw, &io_400m_div4.reg }, + [CLK_IO_400M_DIV8] = { &io_400m_div8.hw, &io_400m_div8.reg }, + [CLK_IO_400M_DIV16] = { &io_400m_div16.hw, &io_400m_div16.reg }, + [CLK_QSPI] = { &qspi.divider.hw, &qspi.divider.reg }, + [CLK_SPI] = { &spi.divider.hw, &spi.divider.reg }, + [CLK_SMC] = { &smc.divider.hw, &smc.divider.reg }, + [CLK_SDIO] = { &sdio.hw, &sdio.reg }, + [CLK_GPIO_DB] = { &gpio_db.divider.hw, &gpio_db.divider.reg }, + [CLK_EFUSE] = { &efuse.divider.hw, &efuse.divider.reg }, + [CLK_TVS] = { &tvs.divider.hw, &tvs.divider.reg }, + [CLK_TRNG] = { &trng.divider.hw, &trng.divider.reg }, + [CLK_OSC_DIV] = { &osc_div.divider.hw, &osc_div.divider.reg }, + [CLK_PWM] = { &pwm.divider.hw, &pwm.divider.reg }, + [CLK_FCLK0] = { &fclk0.divider.hw, &fclk0.divider.reg }, + [CLK_FCLK1] = { &fclk1.divider.hw, &fclk1.divider.reg }, + [CLK_FCLK2] = { &fclk2.divider.hw, &fclk2.divider.reg }, + [CLK_FCLK3] = { &fclk3.divider.hw, &fclk3.divider.reg }, + [CLK_WDT_SEL] = { &wdt_sel.hw, &wdt_sel.reg }, + [CLK_EFUSE_SEL] = { &efuse_sel.hw, &efuse_sel.reg }, + [CLK_CAN_SEL] = { &can_sel.hw, &can_sel.reg }, + [CLK_CPU_SEL] = { &cpu_sel.hw, &cpu_sel.reg }, + [CLK_CAN0] = { &can0.hw, &can0.reg }, + [CLK_CAN1] = { &can1.hw, &can1.reg } +}; + +static int dr1v90_cru_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + void __iomem *base; + int ret; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + ret = dr1_cru_clk_register(dev, base, dr1v90_cru_clks, + ARRAY_SIZE(dr1v90_cru_clks)); + if (ret) + return dev_err_probe(dev, ret, "failed to register clocks\n"); + + ret = dr1_cru_reset_register(dev, base); + if (ret) + return dev_err_probe(dev, ret, "failed to register resets\n"); + + return 0; +} + +static const struct of_device_id dr1v90_cru_ids[] = { + { .compatible = "anlogic,dr1v90-cru" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dr1v90_cru_ids); + +static struct platform_driver dr1v90_cru_driver = { + .driver = { + .name = "dr1v90-cru", + .of_match_table = dr1v90_cru_ids, + }, + .probe = dr1v90_cru_probe, +}; +module_platform_driver(dr1v90_cru_driver); + +MODULE_AUTHOR("Fushan Zeng "); +MODULE_AUTHOR("Junhui Liu "); +MODULE_DESCRIPTION("Anlogic DR1V90 CRU driver"); +MODULE_IMPORT_NS("CLK_ANLOGIC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/anlogic/cru_dr1.c b/drivers/clk/anlogic/cru_dr1.c new file mode 100644 index 000000000000..10f8751a8838 --- /dev/null +++ b/drivers/clk/anlogic/cru_dr1.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024-2025 Anlogic, Inc. + * Copyright (C) 2026 Junhui Liu + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cru_dr1.h" + +static unsigned long cru_pll_nm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct cru_pll *pll = hw_to_cru_pll(hw); + u32 mult, div; + + div = FIELD_GET(GENMASK(6, 0), readl(pll->reg)) + 1; + mult = FIELD_GET(GENMASK(6, 0), readl(pll->reg + 4)) + 1; + + return parent_rate * mult / div; +} + +const struct clk_ops dr1_cru_pll_nm_ops = { + .recalc_rate = cru_pll_nm_recalc_rate, +}; +EXPORT_SYMBOL_NS_GPL(dr1_cru_pll_nm_ops, "CLK_ANLOGIC"); + +static unsigned long cru_pll_c_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct cru_pll *pll = hw_to_cru_pll(hw); + u32 div; + + div = FIELD_GET(GENMASK(30, 24), readl(pll->reg)) + 1; + + return parent_rate / div; +} + +const struct clk_ops dr1_cru_pll_c_ops = { + .recalc_rate = cru_pll_c_recalc_rate, +}; +EXPORT_SYMBOL_NS_GPL(dr1_cru_pll_c_ops, "CLK_ANLOGIC"); + +static void cru_div_gate_endisable(struct clk_hw *hw, int enable) +{ + struct cru_div_gate *div_gate = hw_to_cru_div_gate(hw); + struct clk_divider *divider = &div_gate->divider; + u32 reg; + + reg = readl(divider->reg); + reg &= ~(clk_div_mask(divider->width) << divider->shift); + + if (enable) + reg |= div_gate->val << divider->shift; + + writel(reg, divider->reg); +} + +static int cru_div_gate_enable(struct clk_hw *hw) +{ + cru_div_gate_endisable(hw, 1); + + return 0; +} + +static void cru_div_gate_disable(struct clk_hw *hw) +{ + cru_div_gate_endisable(hw, 0); +} + +static int cru_div_gate_is_enabled(struct clk_hw *hw) +{ + struct cru_div_gate *div_gate = hw_to_cru_div_gate(hw); + struct clk_divider *divider = &div_gate->divider; + u32 val; + + val = readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + + return !!val; +} + +static unsigned long cru_div_gate_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct cru_div_gate *div_gate = hw_to_cru_div_gate(hw); + struct clk_divider *divider = &div_gate->divider; + unsigned int val; + + val = readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + + if (val < div_gate->min) + return 0; + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + +static int cru_div_gate_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct cru_div_gate *div_gate = hw_to_cru_div_gate(hw); + struct clk_divider *divider = &div_gate->divider; + unsigned long maxdiv, mindiv; + int div = 0; + + maxdiv = clk_div_mask(divider->width) + 1; + mindiv = div_gate->min + 1; + + div = DIV_ROUND_UP_ULL(req->best_parent_rate, req->rate); + div = div > maxdiv ? maxdiv : div; + div = div < mindiv ? mindiv : div; + + req->rate = DIV_ROUND_UP_ULL(req->best_parent_rate, div); + + return 0; +} + +static int cru_div_gate_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct cru_div_gate *div_gate = hw_to_cru_div_gate(hw); + struct clk_divider *divider = &div_gate->divider; + int value; + u32 reg; + + if (!__clk_is_enabled(hw->clk)) + return 0; + + value = divider_get_val(rate, parent_rate, divider->table, + divider->width, divider->flags); + if (value < 0) + return value; + + if (value < div_gate->min) + value = div_gate->min; + + reg = readl(divider->reg); + reg &= ~(clk_div_mask(divider->width) << divider->shift); + reg |= (u32)value << divider->shift; + writel(reg, divider->reg); + + div_gate->val = value; + + return 0; +} + +static int cru_div_gate_init(struct clk_hw *hw) +{ + struct cru_div_gate *div_gate = hw_to_cru_div_gate(hw); + struct clk_divider *divider = &div_gate->divider; + u32 val; + + val = readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + div_gate->val = val; + + return 0; +} + +const struct clk_ops dr1_cru_div_gate_ops = { + .enable = cru_div_gate_enable, + .disable = cru_div_gate_disable, + .is_enabled = cru_div_gate_is_enabled, + .recalc_rate = cru_div_gate_recalc_rate, + .determine_rate = cru_div_gate_determine_rate, + .set_rate = cru_div_gate_set_rate, + .init = cru_div_gate_init, +}; +EXPORT_SYMBOL_NS_GPL(dr1_cru_div_gate_ops, "CLK_ANLOGIC"); + +int dr1_cru_clk_register(struct device *dev, void __iomem *base, + const struct cru_clk *clks, int nr_clks) +{ + struct clk_hw_onecell_data *priv; + int i, ret; + + priv = devm_kzalloc(dev, struct_size(priv, hws, nr_clks), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + for (i = 0; i < nr_clks; i++) { + const struct cru_clk *clk = &clks[i]; + + if (clk->reg) + *(clk->reg) += (uintptr_t)base; + + ret = devm_clk_hw_register(dev, clk->hw); + if (ret) + return ret; + + priv->hws[i] = clk->hw; + } + + priv->num = nr_clks; + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, priv); + if (ret) + dev_err(dev, "failed to add clock hardware provider\n"); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(dr1_cru_clk_register, "CLK_ANLOGIC"); + +int dr1_cru_reset_register(struct device *dev, void __iomem *base) +{ + struct auxiliary_device *adev; + + adev = devm_auxiliary_device_create(dev, "reset", base); + if (!adev) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(dr1_cru_reset_register, "CLK_ANLOGIC"); + +MODULE_DESCRIPTION("Anlogic DR1 CRU driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/anlogic/cru_dr1.h b/drivers/clk/anlogic/cru_dr1.h new file mode 100644 index 000000000000..5386aed9e9f3 --- /dev/null +++ b/drivers/clk/anlogic/cru_dr1.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024-2025 Anlogic, Inc. + * Copyright (C) 2026 Junhui Liu + */ + +#ifndef _CRU_DR1_H_ +#define _CRU_DR1_H_ + +#include + +struct cru_pll { + struct clk_hw hw; + void __iomem *reg; +}; + +struct cru_div_gate { + struct clk_divider divider; + u32 val; /* Cached divider value for restoring on enable */ + u8 min; /* Minimum divider value to avoid timing issues */ +}; + +struct cru_clk { + struct clk_hw *hw; + void **reg; +}; + +#define CRU_PARENT_NAME(_name) { .fw_name = #_name } +#define CRU_PARENT_HW(_parent) { .hw = &_parent.hw } +#define CRU_PARENT_DIV_HW(_parent) { .hw = &_parent.divider.hw } + +#define CRU_INITHW(_name, _parent, _ops) \ + .hw.init = &(struct clk_init_data) { \ + .name = #_name, \ + .parent_data = (const struct clk_parent_data[]) \ + { _parent }, \ + .num_parents = 1, \ + .ops = &_ops, \ + } + +#define CRU_INITHW_PARENTS(_name, _parents, _ops) \ + .hw.init = CLK_HW_INIT_PARENTS_DATA(#_name, _parents, &_ops, 0) + +#define CRU_PLL_NM_DEFINE(_name, _parent, _reg) \ +static struct cru_pll _name = { \ + .reg = (void __iomem *)(_reg), \ + CRU_INITHW(_name, _parent, dr1_cru_pll_nm_ops), \ +} + +#define CRU_PLL_C_DEFINE(_name, _parent, _reg) \ +static struct cru_pll _name = { \ + .reg = (void __iomem *)(_reg), \ + CRU_INITHW(_name, _parent, dr1_cru_pll_c_ops), \ +} + +#define CRU_DIV_DEFINE(_name, _parent, _reg, _shift, _width, _table, \ + _flags) \ +static struct clk_divider _name = { \ + .shift = _shift, \ + .width = _width, \ + .flags = _flags, \ + .table = _table, \ + .reg = (void __iomem *)(_reg), \ + CRU_INITHW(_name, _parent, clk_divider_ops), \ +} + +#define CRU_DIV_GATE_DEFINE(_name, _parent, _reg, _shift, _width, \ + _table, _flags, _min) \ +static struct cru_div_gate _name = { \ + .min = _min, \ + .divider = { \ + .shift = _shift, \ + .width = _width, \ + .flags = _flags, \ + .table = _table, \ + .reg = (void __iomem *)(_reg), \ + CRU_INITHW(_name, _parent, dr1_cru_div_gate_ops), \ + } \ +} + +#define CRU_MUX_DEFINE(_name, _parents, _reg, _shift, _width) \ +static struct clk_mux _name = { \ + .shift = _shift, \ + .mask = GENMASK(_width - 1, 0), \ + .reg = (void __iomem *)(_reg), \ + CRU_INITHW_PARENTS(_name, _parents, clk_mux_ops) \ +} + +#define CRU_GATE_DEFINE(_name, _parent, _reg, _bit_idx, _flags) \ +static struct clk_gate _name = { \ + .bit_idx = _bit_idx, \ + .flags = _flags, \ + .reg = (void __iomem *)(_reg), \ + CRU_INITHW(_name, _parent, clk_gate_ops) \ +} + +static inline struct cru_pll *hw_to_cru_pll(struct clk_hw *hw) +{ + return container_of(hw, struct cru_pll, hw); +} + +static inline struct cru_div_gate *hw_to_cru_div_gate(struct clk_hw *hw) +{ + struct clk_divider *divider = to_clk_divider(hw); + + return container_of(divider, struct cru_div_gate, divider); +} + +extern const struct clk_ops dr1_cru_pll_nm_ops; +extern const struct clk_ops dr1_cru_pll_c_ops; +extern const struct clk_ops dr1_cru_div_gate_ops; + +int dr1_cru_clk_register(struct device *dev, void __iomem *base, + const struct cru_clk *clks, int nr_clks); +int dr1_cru_reset_register(struct device *dev, void __iomem *base); + +#endif /* _CRU_DR1_H_ */ From 9fd565971072d2d7158e15178f84b0273e294e70 Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Thu, 14 May 2026 17:27:20 +0800 Subject: [PATCH 132/168] reset: anlogic: add support for Anlogic DR1V90 resets Add reset controller support for the Anlogic DR1V90 SoC, which is an auxiliary device associated with the Clock and Reset Unit (CRU). All resets are active-low. Signed-off-by: Junhui Liu Reviewed-by: Philipp Zabel Acked-by: Philipp Zabel Signed-off-by: Brian Masney --- drivers/reset/Kconfig | 10 +++ drivers/reset/Makefile | 1 + drivers/reset/reset-dr1v90.c | 140 +++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 drivers/reset/reset-dr1v90.c diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 3168ab1eea88..eda9c698a95f 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -73,6 +73,16 @@ config RESET_BRCMSTB_RESCAL This enables the RESCAL reset controller for SATA, PCIe0, or PCIe1 on BCM7216 or the BCM2712. +config RESET_DR1V90 + tristate "Anlogic DR1V90 reset controller" + depends on ARCH_ANLOGIC || COMPILE_TEST + depends on ANLOGIC_DR1V90_CRU + select AUXILIARY_BUS + default ARCH_ANLOGIC + help + This enables the reset controller driver for Anlogic DR1V90 SoCs + provided by the CRU unit. + config RESET_EIC7700 bool "Reset controller driver for ESWIN SoCs" depends on ARCH_ESWIN || COMPILE_TEST diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 45ad17062462..489fafd6bbe3 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o +obj-$(CONFIG_RESET_DR1V90) += reset-dr1v90.o obj-$(CONFIG_RESET_EIC7700) += reset-eic7700.o obj-$(CONFIG_RESET_EIC7700_HSP) += reset-eic7700-hsp.o obj-$(CONFIG_RESET_EYEQ) += reset-eyeq.o diff --git a/drivers/reset/reset-dr1v90.c b/drivers/reset/reset-dr1v90.c new file mode 100644 index 000000000000..daa99c797b1a --- /dev/null +++ b/drivers/reset/reset-dr1v90.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Junhui Liu + */ + +#include +#include +#include +#include +#include + +#include + +struct dr1v90_reset_map { + u32 offset; + u32 bit; +}; + +struct dr1v90_reset_controller { + struct reset_controller_dev rcdev; + void __iomem *base; + spinlock_t lock; /* protect register read-modify-write */ +}; + +static inline struct dr1v90_reset_controller * +to_dr1v90_reset_controller(struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct dr1v90_reset_controller, rcdev); +} + +static const struct dr1v90_reset_map dr1v90_resets[] = { + [RESET_OCM] = { 0x74, BIT(4)}, + [RESET_QSPI] = { 0x74, BIT(5)}, + [RESET_SMC] = { 0x74, BIT(6)}, + [RESET_WDT] = { 0x74, BIT(7)}, + [RESET_DMAC_AXI] = { 0x74, BIT(8)}, + [RESET_DMAC_AHB] = { 0x74, BIT(9)}, + [RESET_NPU] = { 0x74, BIT(12)}, + [RESET_JPU] = { 0x74, BIT(13)}, + [RESET_DDRBUS] = { 0x74, BIT(14)}, + [RESET_NIC_HP0] = { 0x78, BIT(0)}, + [RESET_NIC_HP1] = { 0x78, BIT(1)}, + [RESET_NIC_GP0M] = { 0x78, BIT(4)}, + [RESET_NIC_GP1M] = { 0x78, BIT(5)}, + [RESET_GPIO] = { 0x78, BIT(8)}, + [RESET_IPC] = { 0x78, BIT(12)}, + [RESET_USB0] = { 0x7C, BIT(0)}, + [RESET_USB1] = { 0x7C, BIT(1)}, + [RESET_GBE0] = { 0x7C, BIT(4)}, + [RESET_GBE1] = { 0x7C, BIT(5)}, + [RESET_SDIO0] = { 0x7C, BIT(8)}, + [RESET_SDIO1] = { 0x7C, BIT(9)}, + [RESET_UART0] = { 0x7C, BIT(12)}, + [RESET_UART1] = { 0x7C, BIT(13)}, + [RESET_SPI0] = { 0x7C, BIT(16)}, + [RESET_SPI1] = { 0x7C, BIT(17)}, + [RESET_CAN0] = { 0x7C, BIT(20)}, + [RESET_CAN1] = { 0x7C, BIT(21)}, + [RESET_TTC0] = { 0x7C, BIT(24)}, + [RESET_TTC1] = { 0x7C, BIT(25)}, + [RESET_I2C0] = { 0x7C, BIT(28)}, + [RESET_I2C1] = { 0x7C, BIT(29)} +}; + +static int dr1v90_reset_control_update(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct dr1v90_reset_controller *rstc = to_dr1v90_reset_controller(rcdev); + u32 offset = dr1v90_resets[id].offset; + u32 bit = dr1v90_resets[id].bit; + u32 reg; + + guard(spinlock_irqsave)(&rstc->lock); + + reg = readl(rstc->base + offset); + if (assert) + reg &= ~bit; + else + reg |= bit; + writel(reg, rstc->base + offset); + + return 0; +} + +static int dr1v90_reset_control_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return dr1v90_reset_control_update(rcdev, id, true); +} + +static int dr1v90_reset_control_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return dr1v90_reset_control_update(rcdev, id, false); +} + +static const struct reset_control_ops dr1v90_reset_control_ops = { + .assert = dr1v90_reset_control_assert, + .deassert = dr1v90_reset_control_deassert, +}; + +static int dr1v90_reset_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct dr1v90_reset_controller *rstc; + struct device *dev = &adev->dev; + + rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL); + if (!rstc) + return -ENOMEM; + + spin_lock_init(&rstc->lock); + + rstc->base = dev->platform_data; + rstc->rcdev.dev = dev; + rstc->rcdev.nr_resets = ARRAY_SIZE(dr1v90_resets); + rstc->rcdev.of_node = dev->parent->of_node; + rstc->rcdev.ops = &dr1v90_reset_control_ops; + rstc->rcdev.owner = THIS_MODULE; + + return devm_reset_controller_register(dev, &rstc->rcdev); +} + +static const struct auxiliary_device_id dr1v90_reset_ids[] = { + { + .name = "anlogic_dr1_cru.reset" + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(auxiliary, dr1v90_reset_ids); + +static struct auxiliary_driver dr1v90_reset_driver = { + .probe = dr1v90_reset_probe, + .id_table = dr1v90_reset_ids, +}; +module_auxiliary_driver(dr1v90_reset_driver); + +MODULE_AUTHOR("Junhui Liu "); +MODULE_DESCRIPTION("Anlogic DR1V90 reset controller driver"); +MODULE_LICENSE("GPL"); From da9f1312b06e4c03d43d21494fb5beea7f9e096d Mon Sep 17 00:00:00 2001 From: Aamir Ahmed Date: Sat, 5 Sep 2026 21:48:35 +0100 Subject: [PATCH 133/168] clk: tenstorrent: Assign .num before accessing .hws Commit f316cdff8d67 ("clk: Annotate struct clk_hw_onecell_data with __counted_by") annotated the hws member of 'struct clk_hw_onecell_data' with __counted_by, which informs the bounds sanitizer (UBSAN_BOUNDS) about the number of elements in .hws[], so that it can warn when .hws[] is accessed out of bounds. As noted in that change, the __counted_by member must be initialized with the number of elements before the first array access happens, otherwise there will be a warning from each access prior to the initialization because the number of elements is zero. This occurs in atlantis_prcm_clocks_register() due to .num being assigned only after every clock has been stored in .hws[]. With CONFIG_UBSAN_BOUNDS and a compiler that implements __counted_by (GCC 15.1+ or Clang 20.1+), this triggers an array-index-out-of-bounds report during probe, and with CONFIG_UBSAN_TRAP the first store traps so the clock provider never registers. Move the .num initialization to right after the allocation. Fixes: 23c8ebc95284 ("clk: tenstorrent: Add Atlantis clock controller driver") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Aamir Ahmed Reviewed-by: Gustavo A. R. Silva Reviewed-by: Anirudh Srinivasan Reviewed-by: Drew Fustini (Tenstorrent) Link: https://patch.msgid.link/AS8P251MB00013BD9A093C06D2D60E10EC8B42@AS8P251MB0001.EURP251.PROD.OUTLOOK.COM [fustini: drop num_clks, use data->num per Gustavo] Signed-off-by: Drew Fustini (Tenstorrent) --- drivers/clk/tenstorrent/atlantis-prcm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/clk/tenstorrent/atlantis-prcm.c b/drivers/clk/tenstorrent/atlantis-prcm.c index 6d4386eeb7da..6772035ec872 100644 --- a/drivers/clk/tenstorrent/atlantis-prcm.c +++ b/drivers/clk/tenstorrent/atlantis-prcm.c @@ -789,13 +789,14 @@ static int atlantis_prcm_clocks_register(struct device *dev, { struct clk_hw_onecell_data *clk_data; int i, ret; - size_t num_clks = data->num; clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, data->num), GFP_KERNEL); if (!clk_data) return -ENOMEM; + clk_data->num = data->num; + for (i = 0; i < data->num; i++) { struct clk_hw *hw = data->hws[i]; struct atlantis_clk_common *common = @@ -809,8 +810,6 @@ static int atlantis_prcm_clocks_register(struct device *dev, clk_data->hws[common->clkid] = hw; } - clk_data->num = num_clks; - return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); } From 3f0655b51eb01dad30d61ced0a81718211f2776e Mon Sep 17 00:00:00 2001 From: Anirudh Srinivasan Date: Thu, 24 Sep 2026 10:31:51 -0500 Subject: [PATCH 134/168] clk: tenstorrent: Fix refcount leak on shared gate clk enable failure atlantis_clk_gate_shared_enable() increments the refcount for the number of clks requesting the shared gate clk to be enabled always. It should only do this when the enable for the gate took effect in hardware. It's possible to end up in a situation where the gate enable failed, but the refcount is incremented anyway, so subsequent requests by other clks that share the same refcount get ignored and the gate enable is never retried. Update this function so that the refcount is not incremented when the gate clk enable fails in hardware. Fixes: 23c8ebc95284 ("clk: tenstorrent: Add Atlantis clock controller driver") Cc: stable@vger.kernel.org Reported-by: Sashiko Link: https://sashiko.dev/#/patchset/AS8P251MB00013BD9A093C06D2D60E10EC8B42%40AS8P251MB0001.EURP251.PROD.OUTLOOK.COM Signed-off-by: Anirudh Srinivasan Reviewed-by: Drew Fustini (Tenstorrent) Link: https://patch.msgid.link/20260924-atlantis_gate_shared_enable_fix-v1-1-303f925b8a3d@oss.tenstorrent.com Signed-off-by: Drew Fustini (Tenstorrent) --- drivers/clk/tenstorrent/atlantis-prcm.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/clk/tenstorrent/atlantis-prcm.c b/drivers/clk/tenstorrent/atlantis-prcm.c index 6772035ec872..bf244b1fbfc1 100644 --- a/drivers/clk/tenstorrent/atlantis-prcm.c +++ b/drivers/clk/tenstorrent/atlantis-prcm.c @@ -397,22 +397,21 @@ static int atlantis_clk_gate_shared_enable(struct clk_hw *hw) scoped_guard(spinlock_irqsave, gate->config.refcount_lock) { - need_enable = (*gate->config.share_count)++ == 0; + need_enable = (*gate->config.share_count) == 0; if (need_enable) { regmap_set_bits(gate->common.regmap, gate->config.reg_offset, gate->config.enable); - } - } - if (need_enable) { - if (!regmap_test_bits(gate->common.regmap, - gate->config.reg_offset, - gate->config.enable)) { - pr_warn("%s: gate enable %d failed to enable\n", - clk_hw_get_name(hw), gate->config.enable); - return -EIO; + if (!regmap_test_bits(gate->common.regmap, + gate->config.reg_offset, + gate->config.enable)) { + pr_warn("%s: gate enable %d failed to enable\n", + clk_hw_get_name(hw), gate->config.enable); + return -EIO; + } } + (*gate->config.share_count)++; } return 0; From d5e56ca6c53bf0ed790bb73707817c92302311ae Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 24 Sep 2026 16:34:38 +0800 Subject: [PATCH 135/168] clk: tenstorrent: use regmap_assign_bits() for conditional set/clear Replace if/else blocks using regmap_set_bits()/regmap_clear_bits() with the simpler regmap_assign_bits() call. Signed-off-by: Peng Fan Reviewed-by: Anirudh Srinivasan Reviewed-by: Drew Fustini (Tenstorrent) Link: https://patch.msgid.link/20260924083439.461769-1-peng.fan@oss.nxp.com Signed-off-by: Drew Fustini (Tenstorrent) --- drivers/clk/tenstorrent/atlantis-prcm.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/clk/tenstorrent/atlantis-prcm.c b/drivers/clk/tenstorrent/atlantis-prcm.c index bf244b1fbfc1..6d28aa2ba881 100644 --- a/drivers/clk/tenstorrent/atlantis-prcm.c +++ b/drivers/clk/tenstorrent/atlantis-prcm.c @@ -205,14 +205,9 @@ static int atlantis_clk_gate_endisable(struct clk_hw *hw, int enable) { struct atlantis_clk_gate *gate = hw_to_atlantis_clk_gate(hw); - if (enable) - return regmap_set_bits(gate->common.regmap, - gate->config.reg_offset, - gate->config.enable); - else - return regmap_clear_bits(gate->common.regmap, - gate->config.reg_offset, - gate->config.enable); + return regmap_assign_bits(gate->common.regmap, + gate->config.reg_offset, + gate->config.enable, enable); } static int atlantis_clk_gate_enable(struct clk_hw *hw) From c64b54ddb692c30b8fb139a2ead32eb4db7faef5 Mon Sep 17 00:00:00 2001 From: "Drew Fustini (Tenstorrent)" Date: Thu, 24 Sep 2026 11:09:52 -0700 Subject: [PATCH 136/168] MAINTAINERS: Update RISC-V Tenstorrent SoC entry Add Anirudh Srinivasan as a maintainer. He wrote the Atlantis PRCM clock and reset controller drivers and their DT binding. Switch my address to kernel.org, which I use for all my upstream work, and point T: at the kernel.org tree that the clk and dt pull requests are sent from. Signed-off-by: Drew Fustini (Tenstorrent) --- MAINTAINERS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3a19da74d00c..086b14b688a8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23600,11 +23600,12 @@ N: spacemit K: spacemit RISC-V TENSTORRENT SoC SUPPORT -M: Drew Fustini +M: Drew Fustini M: Joel Stanley +M: Anirudh Srinivasan L: linux-riscv@lists.infradead.org S: Maintained -T: git https://github.com/tenstorrent/linux.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git F: Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml F: Documentation/devicetree/bindings/riscv/tenstorrent.yaml F: arch/riscv/boot/dts/tenstorrent/ From d19f9c0dacdeac3b27a74ad6ee97f457ff62e72f Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Thu, 14 May 2026 17:27:22 +0800 Subject: [PATCH 137/168] MAINTAINERS: Add Anlogic DR1V90 CRU driver entry Add a MAINTAINERS entry for the Anlogic DR1V90 Clock and Reset Unit (CRU) drivers. Signed-off-by: Junhui Liu Signed-off-by: Brian Masney --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3a729f7326f0..6977bc6245b0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2010,6 +2010,15 @@ M: Jiaxun Yang S: Supported F: drivers/rtc/rtc-goldfish.c +ANLOGIC DR1V90 CRU DRIVER +M: Junhui Liu +S: Maintained +F: Documentation/devicetree/bindings/clock/anlogic,dr1v90-cru.yaml +F: drivers/clk/anlogic/cru?dr1* +F: drivers/reset/reset-dr1v90.c +F: include/dt-bindings/clock/anlogic,dr1v90-cru.h +F: include/dt-bindings/reset/anlogic,dr1v90-cru.h + AOA (Apple Onboard Audio) ALSA DRIVER M: Johannes Berg L: linuxppc-dev@lists.ozlabs.org From 8d1bd7882127465b56f1157bbe48ef3375d8f2d9 Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Wed, 30 Sep 2026 05:42:59 -0700 Subject: [PATCH 138/168] dt-bindings: clock: Add StarFive JHB100 System-0 clock and reset generator Add bindings for the System-0 clocks and reset generator (SYS0CRG) on JHB100 SoC. Signed-off-by: Changhuang Liang Reviewed-by: Rob Herring (Arm) Signed-off-by: Conor Dooley --- .../clock/starfive,jhb100-sys0crg.yaml | 63 +++++++++++++++++++ .../dt-bindings/clock/starfive,jhb100-crg.h | 56 +++++++++++++++++ .../dt-bindings/reset/starfive,jhb100-crg.h | 28 +++++++++ 3 files changed, 147 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/starfive,jhb100-sys0crg.yaml create mode 100644 include/dt-bindings/clock/starfive,jhb100-crg.h create mode 100644 include/dt-bindings/reset/starfive,jhb100-crg.h diff --git a/Documentation/devicetree/bindings/clock/starfive,jhb100-sys0crg.yaml b/Documentation/devicetree/bindings/clock/starfive,jhb100-sys0crg.yaml new file mode 100644 index 000000000000..cf1b0175b158 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/starfive,jhb100-sys0crg.yaml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/starfive,jhb100-sys0crg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JHB100 System-0 Clock and Reset Generator + +maintainers: + - Changhuang Liang + +properties: + compatible: + const: starfive,jhb100-sys0crg + + reg: + maxItems: 1 + + clocks: + items: + - description: Main Oscillator (25 MHz) + - description: PLL0 + - description: PLL1 + - description: PLL2 + + clock-names: + items: + - const: osc + - const: pll0 + - const: pll1 + - const: pll2 + + '#clock-cells': + const: 1 + description: + See for valid indices. + + '#reset-cells': + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@13000000 { + compatible = "starfive,jhb100-sys0crg"; + reg = <0x13000000 0x4000>; + clocks = <&osc>, <&pll0>, <&pll1>, + <&syspll 0>; + clock-names = "osc", "pll0", "pll1", "pll2"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/include/dt-bindings/clock/starfive,jhb100-crg.h b/include/dt-bindings/clock/starfive,jhb100-crg.h new file mode 100644 index 000000000000..24ef2663f05a --- /dev/null +++ b/include/dt-bindings/clock/starfive,jhb100-crg.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* + * Copyright (C) 2024 StarFive Technology Co., Ltd. + * Author: Changhuang Liang + * + */ + +#ifndef __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ +#define __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ + +/* SYS0CRG clocks */ +#define JHB100_SYS0CLK_BMCPCIERP_NCNOC_MAIN 17 +#define JHB100_SYS0CLK_BMCPCIERP_NCNOC_CFG 18 + +#define JHB100_SYS0CLK_PCIE_REF_CML 20 +#define JHB100_SYS0CLK_BMCPCIERP_NCNOC_DATA_INIT 21 +#define JHB100_SYS0CLK_BMCPCIERP_NCNOC_CFG_INIT 22 +#define JHB100_SYS0CLK_BMCPCIERP_NCNOC_TARG 23 + +#define JHB100_SYS0CLK_BMCPCIERP_PCU 26 +#define JHB100_SYS0CLK_HOSTSS0_NCNOC_CFG 27 +#define JHB100_SYS0CLK_HOSTSS0_NCNOC_DATA 28 +#define JHB100_SYS0CLK_HOSTSS0_PHY_SCAN_400 29 +#define JHB100_SYS0CLK_GPIO_ESPI0_EXT 30 + +#define JHB100_SYS0CLK_BMCUSB_NCNOC_INIT 34 +#define JHB100_SYS0CLK_BMCUSB_NCNOC_TARG 35 +#define JHB100_SYS0CLK_BMCUSB_SCANCLK 36 +#define JHB100_SYS0CLK_BMCUSB_480M_SCANCLK 37 + +#define JHB100_SYS0CLK_VCE_NCNOC_INIT 50 +#define JHB100_SYS0CLK_VCE_NCNOC_TARG 51 +#define JHB100_SYS0CLK_BMCPER2_NCNOC_INIT 52 +#define JHB100_SYS0CLK_BMCPER2_NCNOC_TARG 53 +#define JHB100_SYS0CLK_BMCPER2_CFG_400 54 +#define JHB100_SYS0CLK_BMCPER2_CFG_125 55 + +#define JHB100_SYS0CLK_HOSTSS1_NCNOC_DATA 58 +#define JHB100_SYS0CLK_HOSTSS1_PHY_SCAN_400 59 +#define JHB100_SYS0CLK_HOSTSS1_PHY_SCAN_400_ICG_BUF 60 +#define JHB100_SYS0CLK_NPU_NCNOC_INIT 61 +#define JHB100_SYS0CLK_VOUT_NCNOC_INIT 62 +#define JHB100_SYS0CLK_VOUT_AUX 63 + +#define JHB100_SYS0CLK_BMCPER3_NCNOC_INIT 65 +#define JHB100_SYS0CLK_HOSTUSB_NCNOC_INIT 66 +#define JHB100_SYS0CLK_HOSTUSBCMN_CFG_480 67 +#define JHB100_SYS0CLK_BMCPER1_NCNOC_INIT 68 +#define JHB100_SYS0CLK_BMCPER1_CFG_800 69 +#define JHB100_SYS0CLK_BMCPER0_NCNOC_INIT 70 +#define JHB100_SYS0CLK_BMCPER0_CFG_400 71 +#define JHB100_SYS0CLK_BMCPER0_CFG_800 72 +#define JHB100_SYS0CLK_GPU0_NCNOC_INIT 73 +#define JHB100_SYS0CLK_GPU1_NCNOC_INIT 74 + +#endif /* __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ */ diff --git a/include/dt-bindings/reset/starfive,jhb100-crg.h b/include/dt-bindings/reset/starfive,jhb100-crg.h new file mode 100644 index 000000000000..5c7b00afda73 --- /dev/null +++ b/include/dt-bindings/reset/starfive,jhb100-crg.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* + * Copyright (C) 2024 StarFive Technology Co., Ltd. + * Author: Changhuang Liang + * + */ + +#ifndef __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ +#define __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ + +/* SYS0CRG resets */ +#define JHB100_SYS0RST_RESOURCE_ARB 0 +#define JHB100_SYS0RST_SYS0_IOMUX_PRESETN 1 +#define JHB100_SYS0RST_SYS0H_IOMUX_PRESETN 2 +#define JHB100_SYS0RST_RST_ADAPTOR_TIMEOUT_RSTN 3 +#define JHB100_SYS0RST_BMCPCIERP_RSTN_BUS 4 +#define JHB100_SYS0RST_BMCPCIERP_RSTN_CRG 5 +#define JHB100_SYS0RST_HOSTSS0_RSTN_BUS_ESPI 6 +#define JHB100_SYS0RST_HOSTSS0_RSTN_BUS_PCIE 7 +#define JHB100_SYS0RST_HOSTSS0_RSTN_CRG 8 +#define JHB100_SYS0RST_BMCPERIPH2_RSTN_CRG 9 +#define JHB100_SYS0RST_BMCPERIPH2_RSTN_BUS 10 +#define JHB100_SYS0RST_VCE_RSTN_CRG 11 +#define JHB100_SYS0RST_VCE_RSTN_BUS 12 +#define JHB100_SYS0RST_BMCUSB_RSTN_BUS 13 +#define JHB100_SYS0RST_BMCUSB_RSTN_CRG 14 + +#endif /* __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ */ From 2bb7b7f56c5b679c3c31aca4f7de6d62fa3dd263 Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Wed, 30 Sep 2026 05:43:01 -0700 Subject: [PATCH 139/168] dt-bindings: clock: Add StarFive JHB100 System-1 clock and reset generator Add bindings for the System-1 clocks and reset generator (SYS1CRG) on JHB100 SoC. Signed-off-by: Changhuang Liang Reviewed-by: Rob Herring (Arm) Signed-off-by: Conor Dooley --- .../clock/starfive,jhb100-sys1crg.yaml | 71 +++++++++++++++++++ .../dt-bindings/clock/starfive,jhb100-crg.h | 20 ++++++ .../dt-bindings/reset/starfive,jhb100-crg.h | 11 +++ 3 files changed, 102 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/starfive,jhb100-sys1crg.yaml diff --git a/Documentation/devicetree/bindings/clock/starfive,jhb100-sys1crg.yaml b/Documentation/devicetree/bindings/clock/starfive,jhb100-sys1crg.yaml new file mode 100644 index 000000000000..70cbfa38c100 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/starfive,jhb100-sys1crg.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/starfive,jhb100-sys1crg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JHB100 System-1 Clock and Reset Generator + +maintainers: + - Changhuang Liang + +properties: + compatible: + const: starfive,jhb100-sys1crg + + reg: + maxItems: 1 + + clocks: + items: + - description: Main Oscillator (25 MHz) + - description: PLL0 + - description: PLL1 + - description: PLL2 + - description: PLL4 + - description: PLL5 + - description: NPU Non Coherent NOC Initiator + + clock-names: + items: + - const: osc + - const: pll0 + - const: pll1 + - const: pll2 + - const: pll4 + - const: pll5 + - const: npu_ncnoc_init + + '#clock-cells': + const: 1 + description: + See for valid indices. + + '#reset-cells': + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@13004000 { + compatible = "starfive,jhb100-sys1crg"; + reg = <0x13004000 0x4000>; + clocks = <&osc>, <&pll0>, <&pll1>, + <&syspll 0>, <&syspll 2>, + <&syspll 3>, <&sys0crg 61>; + clock-names = "osc", "pll0", "pll1", "pll2", + "pll4", "pll5", "npu_ncnoc_init"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/include/dt-bindings/clock/starfive,jhb100-crg.h b/include/dt-bindings/clock/starfive,jhb100-crg.h index 24ef2663f05a..d7904b32bd51 100644 --- a/include/dt-bindings/clock/starfive,jhb100-crg.h +++ b/include/dt-bindings/clock/starfive,jhb100-crg.h @@ -53,4 +53,24 @@ #define JHB100_SYS0CLK_GPU0_NCNOC_INIT 73 #define JHB100_SYS0CLK_GPU1_NCNOC_INIT 74 +/* SYS1CRG clocks */ +#define JHB100_SYS1CLK_APB_MAIN_SYS1 0 +#define JHB100_SYS1CLK_APB_SENSOR_ICG_BUF 1 + +#define JHB100_SYS1CLK_GPIO_ESPI1_EXT 5 + +#define JHB100_SYS1CLK_HOSTSS1_NCNOC_CFG 7 +#define JHB100_SYS1CLK_HOSTSS1_PHY_SCAN_1000_ICG_BUF 8 +#define JHB100_SYS1CLK_NPU_NCNOC_CFG 9 +#define JHB100_SYS1CLK_NPU_CORE_DIV 10 +#define JHB100_SYS1CLK_DOM_NPU_CORE_CLK 11 +#define JHB100_SYS1CLK_DOM_NPU_BUS_CLK 12 +#define JHB100_SYS1CLK_DOM_NPU_INIT_CLK 13 +#define JHB100_SYS1CLK_DOM_NPU_OSC_CLK 14 +#define JHB100_SYS1CLK_VOUT_NCNOC_TARG 15 +#define JHB100_SYS1CLK_VOUT_PIX0 16 +#define JHB100_SYS1CLK_VOUT_PIX1 17 +#define JHB100_SYS1CLK_BMCPER3_NCNOC_TARG 18 +#define JHB100_SYS1CLK_BMCPER3_CFG_125 19 + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ */ diff --git a/include/dt-bindings/reset/starfive,jhb100-crg.h b/include/dt-bindings/reset/starfive,jhb100-crg.h index 5c7b00afda73..da1b51621172 100644 --- a/include/dt-bindings/reset/starfive,jhb100-crg.h +++ b/include/dt-bindings/reset/starfive,jhb100-crg.h @@ -25,4 +25,15 @@ #define JHB100_SYS0RST_BMCUSB_RSTN_BUS 13 #define JHB100_SYS0RST_BMCUSB_RSTN_CRG 14 +/* SYS1CRG resets */ +#define JHB100_SYS1RST_SYS1_IOMUX_PRESETN 0 +#define JHB100_SYS1RST_MAIN_RSTN_CHIPTOP_SENSOR 1 +#define JHB100_SYS1RST_VOUT_RSTN_HOST0 2 +#define JHB100_SYS1RST_VOUT_RSTN_HOST1 3 +#define JHB100_SYS1RST_HOSTSS1_RSTN_BUS_ESPI 4 +#define JHB100_SYS1RST_HOSTSS1_RSTN_BUS_PCIE 5 +#define JHB100_SYS1RST_HOSTSS1_RSTN_CRG 6 +#define JHB100_SYS1RST_BMCPERIPH3_RSTN_CRG 7 +#define JHB100_SYS1RST_BMCPERIPH3_RSTN_BUS 8 + #endif /* __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ */ From 59e04d1e99361ceeb2dd474a6a66f8cd9937d3d2 Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Wed, 30 Sep 2026 05:43:03 -0700 Subject: [PATCH 140/168] dt-bindings: clock: Add StarFive JHB100 System-2 clock and reset generator Add bindings for the System-2 clocks and reset generator (SYS2CRG) on JHB100 SoC. Signed-off-by: Changhuang Liang Reviewed-by: Rob Herring (Arm) Signed-off-by: Conor Dooley --- .../clock/starfive,jhb100-sys2crg.yaml | 64 +++++++++++++++++++ .../dt-bindings/clock/starfive,jhb100-crg.h | 33 ++++++++++ .../dt-bindings/reset/starfive,jhb100-crg.h | 25 ++++++++ 3 files changed, 122 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/starfive,jhb100-sys2crg.yaml diff --git a/Documentation/devicetree/bindings/clock/starfive,jhb100-sys2crg.yaml b/Documentation/devicetree/bindings/clock/starfive,jhb100-sys2crg.yaml new file mode 100644 index 000000000000..a63809c72e2a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/starfive,jhb100-sys2crg.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/starfive,jhb100-sys2crg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JHB100 System-2 Clock and Reset Generator + +maintainers: + - Changhuang Liang + +properties: + compatible: + const: starfive,jhb100-sys2crg + + reg: + maxItems: 1 + + clocks: + items: + - description: Main Oscillator (25 MHz) + - description: PLL1 + - description: GPU0 Non Coherent NOC Initiator + - description: GPU1 Non Coherent NOC Initiator + + clock-names: + items: + - const: osc + - const: pll1 + - const: gpu0_ncnoc_init + - const: gpu1_ncnoc_init + + '#clock-cells': + const: 1 + description: + See for valid indices. + + '#reset-cells': + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@13008000 { + compatible = "starfive,jhb100-sys2crg"; + reg = <0x13008000 0x4000>; + clocks = <&osc>, <&pll1>, <&sys0crg 73>, + <&sys0crg 74>; + clock-names = "osc", "pll1", "gpu0_ncnoc_init", + "gpu1_ncnoc_init"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/include/dt-bindings/clock/starfive,jhb100-crg.h b/include/dt-bindings/clock/starfive,jhb100-crg.h index d7904b32bd51..d19618e2a846 100644 --- a/include/dt-bindings/clock/starfive,jhb100-crg.h +++ b/include/dt-bindings/clock/starfive,jhb100-crg.h @@ -73,4 +73,37 @@ #define JHB100_SYS1CLK_BMCPER3_NCNOC_TARG 18 #define JHB100_SYS1CLK_BMCPER3_CFG_125 19 +/* SYS2CRG clocks */ +#define JHB100_SYS2CLK_JTAGM0_HCLK 3 +#define JHB100_SYS2CLK_JTAGM1_HCLK 4 +#define JHB100_SYS2CLK_JTAGM0_ATPG 5 +#define JHB100_SYS2CLK_JTAGM1_ATPG 6 +#define JHB100_SYS2CLK_JTAGM0_ATPG_TCLOCK 7 +#define JHB100_SYS2CLK_JTAGM1_ATPG_TCLOCK 8 +#define JHB100_SYS2CLK_JTAG0_MST_WRAP_HCLK 9 +#define JHB100_SYS2CLK_JTAG0_MST_WRAP_CLK_JTAG 10 +#define JHB100_SYS2CLK_JTAG0_MST_WRAP_APB_PCLK 11 +#define JHB100_SYS2CLK_JTAG0_MST_WRAP_ATPG_TCLOCK 12 +#define JHB100_SYS2CLK_JTAG1_MST_WRAP_HCLK 13 +#define JHB100_SYS2CLK_JTAG1_MST_WRAP_CLK_JTAG 14 +#define JHB100_SYS2CLK_JTAG1_MST_WRAP_APB_PCLK 15 +#define JHB100_SYS2CLK_JTAG1_MST_WRAP_ATPG_TCLOCK 16 +#define JHB100_SYS2CLK_HOSTUSB_NCNOC_TARG 17 +#define JHB100_SYS2CLK_HOSTUSBCMN_CFG_500 18 +#define JHB100_SYS2CLK_BMCPER1_NCNOC_TARG 19 +#define JHB100_SYS2CLK_BMCPER1_CFG_250 20 +#define JHB100_SYS2CLK_BMCPER1_CFG_143_DFT 21 +#define JHB100_SYS2CLK_BMCPER1_CFG_143 22 +#define JHB100_SYS2CLK_BMCPER0_NCNOC_TARG 23 +#define JHB100_SYS2CLK_GPU0_NCNOC_TARG 24 +#define JHB100_SYS2CLK_GPU0_BUS_CLK 25 +#define JHB100_SYS2CLK_GPU0_APB_CLK 26 +#define JHB100_SYS2CLK_GPU0_OSC_CLK 27 +#define JHB100_SYS2CLK_GPU1_NCNOC_TARG 28 +#define JHB100_SYS2CLK_GPU1_BUS_CLK 29 +#define JHB100_SYS2CLK_GPU1_APB_CLK 30 +#define JHB100_SYS2CLK_GPU1_OSC_CLK 31 +#define JHB100_SYS2CLK_MAIN_ICG_EN_JTAG0 32 +#define JHB100_SYS2CLK_MAIN_ICG_EN_JTAG1 33 + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ */ diff --git a/include/dt-bindings/reset/starfive,jhb100-crg.h b/include/dt-bindings/reset/starfive,jhb100-crg.h index da1b51621172..fbc55f95e76c 100644 --- a/include/dt-bindings/reset/starfive,jhb100-crg.h +++ b/include/dt-bindings/reset/starfive,jhb100-crg.h @@ -36,4 +36,29 @@ #define JHB100_SYS1RST_BMCPERIPH3_RSTN_CRG 7 #define JHB100_SYS1RST_BMCPERIPH3_RSTN_BUS 8 +/* SYS2CRG resets */ +#define JHB100_SYS2RST_JTAG0_MST_WRAP_HRESETN 0 +#define JHB100_SYS2RST_JTAG0_MST_WRAP_APB_PRESETN 1 +#define JHB100_SYS2RST_JTAG1_MST_WRAP_HRESETN 2 +#define JHB100_SYS2RST_JTAG1_MST_WRAP_APB_PRESETN 3 +#define JHB100_SYS2RST_HUSBCMN_HOSTCMN_RSTN_BUS_NCNOC_INIT 4 +#define JHB100_SYS2RST_HUSBCMN_RSTN_HOSTCMN_CRG 5 +#define JHB100_SYS2RST_HUSBCMN_HOSTUSB0_RSTN_BUS_NCNOC_BMC_TARG 6 +#define JHB100_SYS2RST_HUSBCMN_HOSTUSB0_RSTN_BUS_NCNOC_HOST_TARG 7 +#define JHB100_SYS2RST_HUSBCMN_RSTN_BMC_CRG 8 +#define JHB100_SYS2RST_HUSBCMN_RSTN_HOSTUSB0_CRG 9 +#define JHB100_SYS2RST_HUSBCMN_HOSTUSB1_RSTN_BUS_NCNOC_BMC_TARG 10 +#define JHB100_SYS2RST_HUSBCMN_HOSTUSB1_RSTN_BUS_NCNOC_HOST_TARG 11 +#define JHB100_SYS2RST_HUSBCMN_RSTN_HOSTUSB1_CRG 12 +#define JHB100_SYS2RST_BMCPERIPH1_RSTN_CRG 13 +#define JHB100_SYS2RST_BMCPERIPH1_RSTN_BUS 14 +#define JHB100_SYS2RST_BMCPERIPH0_RSTN_CRG 15 +#define JHB100_SYS2RST_BMCPERIPH0_RSTN_BUS 16 +#define JHB100_SYS2RST_GPU0_RSTN_CRG 17 +#define JHB100_SYS2RST_GPU0_RSTN_BUS 18 +#define JHB100_SYS2RST_GPU0_HOST_PCIE_RST_N 19 +#define JHB100_SYS2RST_GPU1_RSTN_CRG 20 +#define JHB100_SYS2RST_GPU1_RSTN_BUS 21 +#define JHB100_SYS2RST_GPU1_HOST_PCIE_RST_N 22 + #endif /* __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ */ From 412d6e358eec72bd5227e4fd4a5af9461e695fbf Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Wed, 30 Sep 2026 05:43:05 -0700 Subject: [PATCH 141/168] dt-bindings: clock: Add StarFive JHB100 Peripheral-0 clock and reset generator Add bindings for the Peripheral-0 clock and reset generator (PER0CRG) on the JHB100 RISC-V SoC by StarFive Ltd. Signed-off-by: Changhuang Liang Reviewed-by: Rob Herring (Arm) Signed-off-by: Conor Dooley --- .../clock/starfive,jhb100-per0crg.yaml | 70 +++++ .../dt-bindings/clock/starfive,jhb100-crg.h | 281 ++++++++++++++++++ .../dt-bindings/reset/starfive,jhb100-crg.h | 77 +++++ 3 files changed, 428 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/starfive,jhb100-per0crg.yaml diff --git a/Documentation/devicetree/bindings/clock/starfive,jhb100-per0crg.yaml b/Documentation/devicetree/bindings/clock/starfive,jhb100-per0crg.yaml new file mode 100644 index 000000000000..db43e03fd60c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/starfive,jhb100-per0crg.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/starfive,jhb100-per0crg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JHB100 Peripheral-0 Clock and Reset Generator + +maintainers: + - Changhuang Liang + +properties: + compatible: + const: starfive,jhb100-per0crg + + reg: + maxItems: 1 + + clocks: + items: + - description: Main Oscillator (25 MHz) + - description: PLL6 + - description: Configure 400MHz + - description: Configure 800MHZ + - description: Non Coherent NOC Initiator + - description: Non Coherent NOC Target + + clock-names: + items: + - const: osc + - const: pll6 + - const: cfg_400 + - const: cfg_800 + - const: ncnoc_init + - const: ncnoc_targ + + '#clock-cells': + const: 1 + description: + See for valid indices. + + '#reset-cells': + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@11a08000 { + compatible = "starfive,jhb100-per0crg"; + reg = <0x11a08000 0x1000>; + clocks = <&osc>, <&pll6>, <&sys0crg 71>, + <&sys0crg 72>, <&sys0crg 70>, + <&sys2crg 23>; + clock-names = "osc", "pll6", "cfg_400", + "cfg_800", "ncnoc_init", + "ncnoc_targ"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/include/dt-bindings/clock/starfive,jhb100-crg.h b/include/dt-bindings/clock/starfive,jhb100-crg.h index d19618e2a846..add2cd093dbd 100644 --- a/include/dt-bindings/clock/starfive,jhb100-crg.h +++ b/include/dt-bindings/clock/starfive,jhb100-crg.h @@ -106,4 +106,285 @@ #define JHB100_SYS2CLK_MAIN_ICG_EN_JTAG0 32 #define JHB100_SYS2CLK_MAIN_ICG_EN_JTAG1 33 +/* PER0CRG clocks */ +#define JHB100_PER0CLK_CDR_I3C0 0 +#define JHB100_PER0CLK_CDR_I3C1 1 +#define JHB100_PER0CLK_CDR_I3C2 2 +#define JHB100_PER0CLK_CDR_I3C3 3 +#define JHB100_PER0CLK_CDR_I3C4 4 +#define JHB100_PER0CLK_CDR_I3C5 5 +#define JHB100_PER0CLK_CDR_I3C6 6 +#define JHB100_PER0CLK_CDR_I3C7 7 +#define JHB100_PER0CLK_CDR_I3C8 8 +#define JHB100_PER0CLK_CDR_I3C9 9 +#define JHB100_PER0CLK_CDR_I3C10 10 +#define JHB100_PER0CLK_CDR_I3C11 11 +#define JHB100_PER0CLK_CDR_I3C12 12 +#define JHB100_PER0CLK_CDR_I3C13 13 +#define JHB100_PER0CLK_CDR_I3C14 14 +#define JHB100_PER0CLK_CDR_I3C15 15 +#define JHB100_PER0CLK_200 16 +#define JHB100_PER0CLK_600_DIV6 17 +#define JHB100_PER0CLK_600_DIV6_DIV5 18 +#define JHB100_PER0CLK_TIMER0_DUALTIMER0 19 +#define JHB100_PER0CLK_TIMER1_DUALTIMER0 20 +#define JHB100_PER0CLK_TIMER0_DUALTIMER1 21 +#define JHB100_PER0CLK_TIMER1_DUALTIMER1 22 +#define JHB100_PER0CLK_TIMER0_DUALTIMER2 23 +#define JHB100_PER0CLK_TIMER1_DUALTIMER2 24 +#define JHB100_PER0CLK_1200_PH0_LVDS0 25 +#define JHB100_PER0CLK_1200_PH0_LVDS1 26 +#define JHB100_PER0CLK_1200_CORE0 27 +#define JHB100_PER0CLK_1200_CORE1 28 +#define JHB100_PER0CLK_1200_SHIFT90_LVDS0 29 +#define JHB100_PER0CLK_1200_SHIFT90_LVDS1 30 +#define JHB100_PER0CLK_1200_DIV5_CORE0 31 +#define JHB100_PER0CLK_1200_DIV5_CORE1 32 +#define JHB100_PER0CLK_PH0_LTPI0 33 + +#define JHB100_PER0CLK_PH0_LTPI1 35 + +#define JHB100_PER0CLK_PH90_LTPI0 37 + +#define JHB100_PER0CLK_PH90_LTPI1 39 + +#define JHB100_PER0CLK_240_CORE_LTPI0 41 + +#define JHB100_PER0CLK_240_CORE_LTPI1 43 + +#define JHB100_PER0CLK_AXI_DMA_I2C_INIT 45 +#define JHB100_PER0CLK_AXI_DMA_I3C_INIT 46 +#define JHB100_PER0CLK_AXI_DMA_UART_INIT 47 +#define JHB100_PER0CLK_CORE_DMAC0 48 +#define JHB100_PER0CLK_CORE_DMAC1 49 +#define JHB100_PER0CLK_CORE_DMAC2 50 + +#define JHB100_PER0CLK_HDR_TX_I3C0 78 +#define JHB100_PER0CLK_HDR_TX_I3C1 79 +#define JHB100_PER0CLK_HDR_TX_I3C2 80 +#define JHB100_PER0CLK_HDR_TX_I3C3 81 +#define JHB100_PER0CLK_HDR_TX_I3C4 82 +#define JHB100_PER0CLK_HDR_TX_I3C5 83 +#define JHB100_PER0CLK_HDR_TX_I3C6 84 +#define JHB100_PER0CLK_HDR_TX_I3C7 85 +#define JHB100_PER0CLK_HDR_TX_I3C8 86 +#define JHB100_PER0CLK_HDR_TX_I3C9 87 +#define JHB100_PER0CLK_HDR_TX_I3C10 88 +#define JHB100_PER0CLK_HDR_TX_I3C11 89 +#define JHB100_PER0CLK_HDR_TX_I3C12 90 +#define JHB100_PER0CLK_HDR_TX_I3C13 91 +#define JHB100_PER0CLK_HDR_TX_I3C14 92 +#define JHB100_PER0CLK_HDR_TX_I3C15 93 +#define JHB100_PER0CLK_CORE_I2C0 94 +#define JHB100_PER0CLK_CORE_I2C1 95 +#define JHB100_PER0CLK_CORE_I2C2 96 +#define JHB100_PER0CLK_CORE_I2C3 97 +#define JHB100_PER0CLK_CORE_I2C4 98 +#define JHB100_PER0CLK_CORE_I2C5 99 +#define JHB100_PER0CLK_CORE_I2C6 100 +#define JHB100_PER0CLK_CORE_I2C7 101 +#define JHB100_PER0CLK_CORE_I2C8 102 +#define JHB100_PER0CLK_CORE_I2C9 103 +#define JHB100_PER0CLK_CORE_I2C10 104 +#define JHB100_PER0CLK_CORE_I2C11 105 +#define JHB100_PER0CLK_CORE_I2C12 106 +#define JHB100_PER0CLK_CORE_I2C13 107 +#define JHB100_PER0CLK_CORE_I2C14 108 +#define JHB100_PER0CLK_CORE_I2C15 109 + +#define JHB100_PER0CLK_WDOGCLK_WDT0 126 +#define JHB100_PER0CLK_WDOGCLK_WDT1 127 +#define JHB100_PER0CLK_WDOGCLK_WDT2 128 +#define JHB100_PER0CLK_WDOGCLK_WDT3 129 +#define JHB100_PER0CLK_WDOGCLK_WDT_EXTERNAL 130 +#define JHB100_PER0CLK_SCLK_UART4 131 +#define JHB100_PER0CLK_SCLK_UART5 132 +#define JHB100_PER0CLK_SCLK_UART6 133 +#define JHB100_PER0CLK_SCLK_UART7 134 +#define JHB100_PER0CLK_SCLK_UART8 135 +#define JHB100_PER0CLK_SCLK_UART9 136 +#define JHB100_PER0CLK_SCLK_UART10 137 +#define JHB100_PER0CLK_SCLK_UART11 138 +#define JHB100_PER0CLK_SCLK_UART12 139 +#define JHB100_PER0CLK_SCLK_UART13 140 +#define JHB100_PER0CLK_SCLK_UART14 141 + +#define JHB100_PER0CLK_PCLK_DMA_UART_CFG 148 +#define JHB100_PER0CLK_PCLK_DMA_I2C_CFG 149 +#define JHB100_PER0CLK_PCLK_DMA_I3C_CFG 150 +#define JHB100_PER0CLK_PCLK_DUALTIMER0 151 +#define JHB100_PER0CLK_PCLK_DUALTIMER1 152 +#define JHB100_PER0CLK_PCLK_DUALTIMER2 153 + +#define JHB100_PER0CLK_HCLK_TRNG 156 +#define JHB100_PER0CLK_APB_I2C0 157 +#define JHB100_PER0CLK_APB_I2C1 158 +#define JHB100_PER0CLK_APB_I2C2 159 +#define JHB100_PER0CLK_APB_I2C3 160 +#define JHB100_PER0CLK_APB_I2C4 161 +#define JHB100_PER0CLK_APB_I2C5 162 +#define JHB100_PER0CLK_APB_I2C6 163 +#define JHB100_PER0CLK_APB_I2C7 164 +#define JHB100_PER0CLK_APB_I2C8 165 +#define JHB100_PER0CLK_APB_I2C9 166 +#define JHB100_PER0CLK_APB_I2C10 167 +#define JHB100_PER0CLK_APB_I2C11 168 +#define JHB100_PER0CLK_APB_I2C12 169 +#define JHB100_PER0CLK_APB_I2C13 170 +#define JHB100_PER0CLK_APB_I2C14 171 +#define JHB100_PER0CLK_APB_I2C15 172 +#define JHB100_PER0CLK_APB_I2CF0 173 +#define JHB100_PER0CLK_APB_I2CF1 174 +#define JHB100_PER0CLK_APB_I2CF2 175 +#define JHB100_PER0CLK_APB_I2CF3 176 +#define JHB100_PER0CLK_APB_I2CF4 177 +#define JHB100_PER0CLK_APB_I2CF5 178 +#define JHB100_PER0CLK_APB_I2CF6 179 +#define JHB100_PER0CLK_APB_I2CF7 180 +#define JHB100_PER0CLK_APB_I2CF8 181 +#define JHB100_PER0CLK_APB_I2CF9 182 +#define JHB100_PER0CLK_APB_I2CF10 183 +#define JHB100_PER0CLK_APB_I2CF11 184 +#define JHB100_PER0CLK_APB_I2CF12 185 +#define JHB100_PER0CLK_APB_I2CF13 186 +#define JHB100_PER0CLK_APB_I2CF14 187 +#define JHB100_PER0CLK_APB_I2CF15 188 +#define JHB100_PER0CLK_APB_I3C0 189 +#define JHB100_PER0CLK_APB_I3C1 190 +#define JHB100_PER0CLK_APB_I3C2 191 +#define JHB100_PER0CLK_APB_I3C3 192 +#define JHB100_PER0CLK_APB_I3C4 193 +#define JHB100_PER0CLK_APB_I3C5 194 +#define JHB100_PER0CLK_APB_I3C6 195 +#define JHB100_PER0CLK_APB_I3C7 196 +#define JHB100_PER0CLK_APB_I3C8 197 +#define JHB100_PER0CLK_APB_I3C9 198 +#define JHB100_PER0CLK_APB_I3C10 199 +#define JHB100_PER0CLK_APB_I3C11 200 +#define JHB100_PER0CLK_APB_I3C12 201 +#define JHB100_PER0CLK_APB_I3C13 202 +#define JHB100_PER0CLK_APB_I3C14 203 +#define JHB100_PER0CLK_APB_I3C15 204 +#define JHB100_PER0CLK_APB_UART0 205 +#define JHB100_PER0CLK_APB_UART1 206 +#define JHB100_PER0CLK_APB_UART2 207 +#define JHB100_PER0CLK_APB_UART3 208 +#define JHB100_PER0CLK_APB_UART4 209 +#define JHB100_PER0CLK_APB_UART5 210 +#define JHB100_PER0CLK_APB_UART6 211 +#define JHB100_PER0CLK_APB_UART7 212 +#define JHB100_PER0CLK_APB_UART8 213 +#define JHB100_PER0CLK_APB_UART9 214 +#define JHB100_PER0CLK_APB_UART10 215 +#define JHB100_PER0CLK_APB_UART11 216 +#define JHB100_PER0CLK_APB_UART12 217 +#define JHB100_PER0CLK_APB_UART13 218 +#define JHB100_PER0CLK_APB_UART14 219 +#define JHB100_PER0CLK_DMA_I3C0 220 +#define JHB100_PER0CLK_DMA_I3C1 221 +#define JHB100_PER0CLK_DMA_I3C2 222 +#define JHB100_PER0CLK_DMA_I3C3 223 +#define JHB100_PER0CLK_DMA_I3C4 224 +#define JHB100_PER0CLK_DMA_I3C5 225 +#define JHB100_PER0CLK_DMA_I3C6 226 +#define JHB100_PER0CLK_DMA_I3C7 227 +#define JHB100_PER0CLK_DMA_I3C8 228 +#define JHB100_PER0CLK_DMA_I3C9 229 +#define JHB100_PER0CLK_DMA_I3C10 230 +#define JHB100_PER0CLK_DMA_I3C11 231 +#define JHB100_PER0CLK_DMA_I3C12 232 +#define JHB100_PER0CLK_DMA_I3C13 233 +#define JHB100_PER0CLK_DMA_I3C14 234 +#define JHB100_PER0CLK_DMA_I3C15 235 +#define JHB100_PER0CLK_CORE_I3C0 236 +#define JHB100_PER0CLK_CORE_I3C1 237 +#define JHB100_PER0CLK_CORE_I3C2 238 +#define JHB100_PER0CLK_CORE_I3C3 239 +#define JHB100_PER0CLK_CORE_I3C4 240 +#define JHB100_PER0CLK_CORE_I3C5 241 +#define JHB100_PER0CLK_CORE_I3C6 242 +#define JHB100_PER0CLK_CORE_I3C7 243 +#define JHB100_PER0CLK_CORE_I3C8 244 +#define JHB100_PER0CLK_CORE_I3C9 245 +#define JHB100_PER0CLK_CORE_I3C10 246 +#define JHB100_PER0CLK_CORE_I3C11 247 +#define JHB100_PER0CLK_CORE_I3C12 248 +#define JHB100_PER0CLK_CORE_I3C13 249 +#define JHB100_PER0CLK_CORE_I3C14 250 +#define JHB100_PER0CLK_CORE_I3C15 251 +#define JHB100_PER0CLK_DMAC_AXI_PERIPH0_HS_CLK_I2C 252 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C0 253 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C1 254 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C2 255 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C3 256 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C4 257 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C5 258 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C6 259 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C7 260 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C8 261 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C9 262 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C10 263 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C11 264 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C12 265 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C13 266 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C14 267 +#define JHB100_PER0CLK_MAIN_ICG_EN_I3C15 268 +#define JHB100_PER0CLK_MAIN_ICG_EN_DUALTIMER0 269 +#define JHB100_PER0CLK_MAIN_ICG_EN_DUALTIMER1 270 +#define JHB100_PER0CLK_MAIN_ICG_EN_DUALTIMER2 271 +#define JHB100_PER0CLK_MAIN_ICG_EN_LTPI0 272 +#define JHB100_PER0CLK_MAIN_ICG_EN_LTPI1 273 +#define JHB100_PER0CLK_MAIN_ICG_EN_DMAC_I2C 274 +#define JHB100_PER0CLK_MAIN_ICG_EN_DMAC_I3C 275 +#define JHB100_PER0CLK_MAIN_ICG_EN_DMAC_UART 276 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL4 277 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL5 278 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL6 279 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL7 280 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL8 281 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL9 282 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL10 283 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL11 284 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL12 285 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL13 286 +#define JHB100_PER0CLK_MAIN_ICG_EN_SOL14 287 + +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C0 304 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C1 305 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C2 306 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C3 307 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C4 308 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C5 309 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C6 310 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C7 311 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C8 312 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C9 313 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C10 314 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C11 315 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C12 316 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C13 317 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C14 318 +#define JHB100_PER0CLK_MAIN_ICG_EN_I2C15 319 +#define JHB100_PER0CLK_MAIN_ICG_EN_WDT0 320 +#define JHB100_PER0CLK_MAIN_ICG_EN_WDT1 321 +#define JHB100_PER0CLK_MAIN_ICG_EN_WDT2 322 +#define JHB100_PER0CLK_MAIN_ICG_EN_WDT3 323 +#define JHB100_PER0CLK_MAIN_ICG_EN_WDT_EXTERNAL 324 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART4 325 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART5 326 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART6 327 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART7 328 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART8 329 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART9 330 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART10 331 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART11 332 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART12 333 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART13 334 +#define JHB100_PER0CLK_MAIN_ICG_EN_UART14 335 +#define JHB100_PER0CLK_MAIN_ICG_EN_LDO0 336 +#define JHB100_PER0CLK_MAIN_ICG_EN_LDO1 337 +#define JHB100_PER0CLK_MAIN_ICG_EN_SENSORS_PERIPH0 338 +#define JHB100_PER0CLK_MAIN_ICG_EN_SENSORS_DMAC 339 +#define JHB100_PER0CLK_MAIN_ICG_EN_TRNG 340 + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ */ diff --git a/include/dt-bindings/reset/starfive,jhb100-crg.h b/include/dt-bindings/reset/starfive,jhb100-crg.h index fbc55f95e76c..ccfb7616e1a7 100644 --- a/include/dt-bindings/reset/starfive,jhb100-crg.h +++ b/include/dt-bindings/reset/starfive,jhb100-crg.h @@ -61,4 +61,81 @@ #define JHB100_SYS2RST_GPU1_RSTN_BUS 21 #define JHB100_SYS2RST_GPU1_HOST_PCIE_RST_N 22 +/* PER0CRG resets */ +#define JHB100_PER0RST_MAIN_RSTN_UART4 0 +#define JHB100_PER0RST_MAIN_RSTN_UART5 1 +#define JHB100_PER0RST_MAIN_RSTN_UART6 2 +#define JHB100_PER0RST_MAIN_RSTN_UART7 3 +#define JHB100_PER0RST_MAIN_RSTN_UART8 4 +#define JHB100_PER0RST_MAIN_RSTN_UART9 5 +#define JHB100_PER0RST_MAIN_RSTN_UART10 6 +#define JHB100_PER0RST_MAIN_RSTN_UART11 7 +#define JHB100_PER0RST_MAIN_RSTN_UART12 8 +#define JHB100_PER0RST_MAIN_RSTN_UART13 9 +#define JHB100_PER0RST_MAIN_RSTN_UART14 10 +#define JHB100_PER0RST_MAIN_RSTN_I2C0 11 +#define JHB100_PER0RST_MAIN_RSTN_I2C1 12 +#define JHB100_PER0RST_MAIN_RSTN_I2C2 13 +#define JHB100_PER0RST_MAIN_RSTN_I2C3 14 +#define JHB100_PER0RST_MAIN_RSTN_I2C4 15 +#define JHB100_PER0RST_MAIN_RSTN_I2C5 16 +#define JHB100_PER0RST_MAIN_RSTN_I2C6 17 +#define JHB100_PER0RST_MAIN_RSTN_I2C7 18 +#define JHB100_PER0RST_MAIN_RSTN_I2C8 19 +#define JHB100_PER0RST_MAIN_RSTN_I2C9 20 +#define JHB100_PER0RST_MAIN_RSTN_I2C10 21 +#define JHB100_PER0RST_MAIN_RSTN_I2C11 22 +#define JHB100_PER0RST_MAIN_RSTN_I2C12 23 +#define JHB100_PER0RST_MAIN_RSTN_I2C13 24 +#define JHB100_PER0RST_MAIN_RSTN_I2C14 25 +#define JHB100_PER0RST_MAIN_RSTN_I2C15 26 +#define JHB100_PER0RST_MAIN_RSTN_I3C0 27 +#define JHB100_PER0RST_MAIN_RSTN_I3C1 28 +#define JHB100_PER0RST_MAIN_RSTN_I3C2 29 +#define JHB100_PER0RST_MAIN_RSTN_I3C3 30 +#define JHB100_PER0RST_MAIN_RSTN_I3C4 31 +#define JHB100_PER0RST_MAIN_RSTN_I3C5 32 +#define JHB100_PER0RST_MAIN_RSTN_I3C6 33 +#define JHB100_PER0RST_MAIN_RSTN_I3C7 34 +#define JHB100_PER0RST_MAIN_RSTN_I3C8 35 +#define JHB100_PER0RST_MAIN_RSTN_I3C9 36 +#define JHB100_PER0RST_MAIN_RSTN_I3C10 37 +#define JHB100_PER0RST_MAIN_RSTN_I3C11 38 +#define JHB100_PER0RST_MAIN_RSTN_I3C12 39 +#define JHB100_PER0RST_MAIN_RSTN_I3C13 40 +#define JHB100_PER0RST_MAIN_RSTN_I3C14 41 +#define JHB100_PER0RST_MAIN_RSTN_I3C15 42 +#define JHB100_PER0RST_MAIN_RSTN_WDT0 43 +#define JHB100_PER0RST_MAIN_RSTN_WDT1 44 +#define JHB100_PER0RST_MAIN_RSTN_WDT2 45 +#define JHB100_PER0RST_MAIN_RSTN_WDT3 46 +#define JHB100_PER0RST_MAIN_RSTN_WDT4 47 +#define JHB100_PER0RST_MAIN_RSTN_DUALTIMER0 48 +#define JHB100_PER0RST_MAIN_RSTN_DUALTIMER1 49 +#define JHB100_PER0RST_MAIN_RSTN_DUALTIMER2 50 +#define JHB100_PER0RST_MAIN_RSTN_TRNG 51 +#define JHB100_PER0RST_MAIN_RSTN_DMAC0 52 +#define JHB100_PER0RST_MAIN_RSTN_DMAC1 53 +#define JHB100_PER0RST_MAIN_RSTN_DMAC2 54 +#define JHB100_PER0RST_MAIN_RSTN_LTPI0 55 +#define JHB100_PER0RST_MAIN_RSTN_LTPI1 56 +#define JHB100_PER0RST_MAIN_RSTN_SOL4 57 +#define JHB100_PER0RST_MAIN_RSTN_SOL5 58 +#define JHB100_PER0RST_MAIN_RSTN_SOL6 59 +#define JHB100_PER0RST_MAIN_RSTN_SOL7 60 +#define JHB100_PER0RST_MAIN_RSTN_SOL8 61 +#define JHB100_PER0RST_MAIN_RSTN_SOL9 62 +#define JHB100_PER0RST_MAIN_RSTN_SOL10 63 +#define JHB100_PER0RST_MAIN_RSTN_SOL11 64 +#define JHB100_PER0RST_MAIN_RSTN_SOL12 65 +#define JHB100_PER0RST_MAIN_RSTN_SOL13 66 +#define JHB100_PER0RST_MAIN_RSTN_SOL14 67 +#define JHB100_PER0RST_MAIN_RSTN_LDO0 68 +#define JHB100_PER0RST_MAIN_RSTN_LDO1 69 +#define JHB100_PER0RST_MAIN_RSTN_PERIPH0_SENSORS 70 +#define JHB100_PER0RST_MAIN_RSTN_DMAC0_SENSORS 71 +#define JHB100_PER0RST_SYSCON_PRESETN 72 +#define JHB100_PER0RST_GPIO_IOMUX_PRESETN 73 +#define JHB100_PER0RST_UART_MUX_REG_WRAP 74 + #endif /* __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ */ From d20c33354c2234f52f426d283eaf85b1e4f375dd Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Wed, 30 Sep 2026 05:43:09 -0700 Subject: [PATCH 142/168] dt-bindings: clock: Add StarFive JHB100 Peripheral-1 clock and reset generator Add bindings for the Peripheral-1 clock and reset generator (PER1CRG) on the JHB100 RISC-V SoC by StarFive Ltd. Signed-off-by: Changhuang Liang Reviewed-by: Rob Herring (Arm) Signed-off-by: Conor Dooley --- .../clock/starfive,jhb100-per1crg.yaml | 70 +++++++++++++++++++ .../dt-bindings/clock/starfive,jhb100-crg.h | 60 ++++++++++++++++ .../dt-bindings/reset/starfive,jhb100-crg.h | 19 +++++ 3 files changed, 149 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/starfive,jhb100-per1crg.yaml diff --git a/Documentation/devicetree/bindings/clock/starfive,jhb100-per1crg.yaml b/Documentation/devicetree/bindings/clock/starfive,jhb100-per1crg.yaml new file mode 100644 index 000000000000..c72a355ceb34 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/starfive,jhb100-per1crg.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/starfive,jhb100-per1crg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JHB100 Peripheral-1 Clock and Reset Generator + +maintainers: + - Changhuang Liang + +properties: + compatible: + const: starfive,jhb100-per1crg + + reg: + maxItems: 1 + + clocks: + items: + - description: PLL7 + - description: Non Coherent NOC Initiator + - description: Configure 800MHz + - description: Non Coherent NOC Target + - description: Configure 143MHz + + clock-names: + items: + - const: pll7 + - const: ncnoc_init + - const: cfg_800 + - const: ncnoc_targ + - const: cfg_143 + + '#clock-cells': + const: 1 + description: + See for valid indices. + + '#reset-cells': + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@11b40000 { + compatible = "starfive,jhb100-per1crg"; + reg = <0x11b40000 0x1000>; + clocks = <&pll7>, + <&sys0crg 68>, + <&sys0crg 69>, + <&sys2crg 19>, + <&sys2crg 22>; + clock-names = "pll7", "ncnoc_init", + "cfg_800", "ncnoc_targ", + "cfg_143"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/include/dt-bindings/clock/starfive,jhb100-crg.h b/include/dt-bindings/clock/starfive,jhb100-crg.h index add2cd093dbd..7f508574177c 100644 --- a/include/dt-bindings/clock/starfive,jhb100-crg.h +++ b/include/dt-bindings/clock/starfive,jhb100-crg.h @@ -387,4 +387,64 @@ #define JHB100_PER0CLK_MAIN_ICG_EN_SENSORS_DMAC 339 #define JHB100_PER0CLK_MAIN_ICG_EN_TRNG 340 +/* PER1CRG clocks */ +#define JHB100_PER1CLK_100 0 +#define JHB100_PER1CLK_1 1 +#define JHB100_PER1CLK_200_DIVN0 2 +#define JHB100_PER1CLK_200_DIVN1 3 +#define JHB100_PER1CLK_200_DIVN2 4 +#define JHB100_PER1CLK_200_DIVN3 5 +#define JHB100_PER1CLK_200_CCLK_DIV 6 + +#define JHB100_PER1CLK_SGPIO0_PCLK 15 +#define JHB100_PER1CLK_SGPIO0_DCLK 16 +#define JHB100_PER1CLK_SGPIO1_PCLK 17 +#define JHB100_PER1CLK_SGPIO1_DCLK 18 + +#define JHB100_PER1CLK_EMMC0_BCLK 22 + +#define JHB100_PER1CLK_EMMC0_CCLK 25 + +#define JHB100_PER1CLK_DMAC1_1CH_CORE 29 + +#define JHB100_PER1CLK_DMAC1_1CH_ACLK 31 + +#define JHB100_PER1CLK_DMAC2_1CH_CORE 33 + +#define JHB100_PER1CLK_DMAC2_1CH_ACLK 35 + +#define JHB100_PER1CLK_DMAC3_1CH_CORE 37 + +#define JHB100_PER1CLK_DMAC3_1CH_ACLK 39 + +#define JHB100_PER1CLK_DMAC0_2CH_CORE 41 + +#define JHB100_PER1CLK_DMAC0_2CH_ACLK 43 + +#define JHB100_PER1CLK_UFS_REF 45 +#define JHB100_PER1CLK_UFS_300 46 +#define JHB100_PER1CLK_UFS_150 47 +#define JHB100_PER1CLK_UFS_400 48 +#define JHB100_PER1CLK_UFS_75 49 +#define JHB100_PER1CLK_UFS_37_5 50 +#define JHB100_PER1CLK_UFS_7_5 51 +#define JHB100_PER1CLK_UFS_1_875 52 +#define JHB100_PER1CLK_UFS_7_143 53 +#define JHB100_PER1CLK_UFS_3_5715 54 + +#define JHB100_PER1CLK_MAIN_ICG_EN_SFC0 63 +#define JHB100_PER1CLK_MAIN_ICG_EN_SFC1 64 +#define JHB100_PER1CLK_MAIN_ICG_EN_SFC2 65 +#define JHB100_PER1CLK_MAIN_ICG_EN_SPI0 66 +#define JHB100_PER1CLK_MAIN_ICG_EN_SGPIO0 67 +#define JHB100_PER1CLK_MAIN_ICG_EN_SGPIO1 68 +#define JHB100_PER1CLK_MAIN_ICG_EN_SENSORS_PERIPH1 69 +#define JHB100_PER1CLK_MAIN_ICG_EN_EMMC0 70 +#define JHB100_PER1CLK_MAIN_ICG_EN_DMAC_SFC0 71 +#define JHB100_PER1CLK_MAIN_ICG_EN_DMAC_SFC1 72 +#define JHB100_PER1CLK_MAIN_ICG_EN_DMAC_SFC2 73 +#define JHB100_PER1CLK_MAIN_ICG_EN_DMAC_SPI0 74 +#define JHB100_PER1CLK_MAIN_ICG_EN_RAS 75 +#define JHB100_PER1CLK_MAIN_ICG_EN_UFS 76 + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ */ diff --git a/include/dt-bindings/reset/starfive,jhb100-crg.h b/include/dt-bindings/reset/starfive,jhb100-crg.h index ccfb7616e1a7..cf933a1befbb 100644 --- a/include/dt-bindings/reset/starfive,jhb100-crg.h +++ b/include/dt-bindings/reset/starfive,jhb100-crg.h @@ -138,4 +138,23 @@ #define JHB100_PER0RST_GPIO_IOMUX_PRESETN 73 #define JHB100_PER0RST_UART_MUX_REG_WRAP 74 +/* PER1CRG resets */ +#define JHB100_PER1RST_IOMUX_PRESETN 0 +#define JHB100_PER1RST_SYSCON_PRESETN 1 +#define JHB100_PER1RST_MAIN_RSTN_SFC0 2 +#define JHB100_PER1RST_MAIN_RSTN_SFC1 3 +#define JHB100_PER1RST_MAIN_RSTN_SFC2 4 +#define JHB100_PER1RST_MAIN_RSTN_SPI0 5 +#define JHB100_PER1RST_MAIN_RSTN_PERIPH1_SENSORS 6 +#define JHB100_PER1RST_MAIN_RSTN_SGPIO0 7 +#define JHB100_PER1RST_MAIN_RSTN_SGPIO1 8 +#define JHB100_PER1RST_MAIN_RSTN_EMMC0 9 +#define JHB100_PER1RST_MAIN_RSTN_UFS 10 +#define JHB100_PER1RST_MAIN_RSTN_UFS_PHY 11 +#define JHB100_PER1RST_MAIN_RSTN_DMAC_SFC0 12 +#define JHB100_PER1RST_MAIN_RSTN_DMAC_SFC1 13 +#define JHB100_PER1RST_MAIN_RSTN_DMAC_SFC2 14 +#define JHB100_PER1RST_MAIN_RSTN_DMAC_SPI0 15 +#define JHB100_PER1RST_MAIN_RSTN_PERIPH1_RAS 16 + #endif /* __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ */ From 5b86a2f9415fdf4ef1188fdfe0dafb1727328cfd Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Wed, 30 Sep 2026 05:43:11 -0700 Subject: [PATCH 143/168] dt-bindings: clock: Add StarFive JHB100 Peripheral-2 clock and reset generator Add bindings for the Peripheral-2 clock and reset generator (PER2CRG) on the JHB100 RISC-V SoC by StarFive Ltd. Signed-off-by: Changhuang Liang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Conor Dooley --- .../clock/starfive,jhb100-per2crg.yaml | 76 +++++++++++++++++++ .../dt-bindings/clock/starfive,jhb100-crg.h | 57 ++++++++++++++ .../dt-bindings/reset/starfive,jhb100-crg.h | 17 +++++ 3 files changed, 150 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/starfive,jhb100-per2crg.yaml diff --git a/Documentation/devicetree/bindings/clock/starfive,jhb100-per2crg.yaml b/Documentation/devicetree/bindings/clock/starfive,jhb100-per2crg.yaml new file mode 100644 index 000000000000..175654645221 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/starfive,jhb100-per2crg.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/starfive,jhb100-per2crg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JHB100 Peripheral-2 Clock and Reset Generator + +maintainers: + - Changhuang Liang + +properties: + compatible: + const: starfive,jhb100-per2crg + + reg: + maxItems: 1 + + clocks: + items: + - description: Non Coherent NOC Initiator + - description: Configure 400MHz + - description: Configure 125MHz + - description: GMAC2 RGMII RX + - description: GMAC2 RMII Reference + - description: GMAC3 SGMII TX + - description: GMAC3 SGMII RX + - description: Main Oscillator (25 MHz) + + clock-names: + items: + - const: ncnoc_init + - const: cfg_400 + - const: cfg_125 + - const: gmac2_rgmii_rx + - const: gmac2_rmii_ref + - const: gmac3_sgmii_tx + - const: gmac3_sgmii_rx + - const: osc + + '#clock-cells': + const: 1 + description: + See for valid indices. + + '#reset-cells': + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@11bc0000 { + compatible = "starfive,jhb100-per2crg"; + reg = <0x11bc0000 0x1000>; + clocks = <&sys0crg 52>, <&sys0crg 54>, <&sys0crg 55>, + <&per2_gmac2_rgmii_rx>, <&per2_gmac2_rmii_ref>, + <&per2_gmac3_sgmii_tx>, <&per2_gmac3_sgmii_rx>, + <&osc>; + clock-names = "ncnoc_init", "cfg_400", "cfg_125", + "gmac2_rgmii_rx", "gmac2_rmii_ref", + "gmac3_sgmii_tx", "gmac3_sgmii_rx", + "osc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/include/dt-bindings/clock/starfive,jhb100-crg.h b/include/dt-bindings/clock/starfive,jhb100-crg.h index 7f508574177c..2b2e148ce5ce 100644 --- a/include/dt-bindings/clock/starfive,jhb100-crg.h +++ b/include/dt-bindings/clock/starfive,jhb100-crg.h @@ -447,4 +447,61 @@ #define JHB100_PER1CLK_MAIN_ICG_EN_RAS 75 #define JHB100_PER1CLK_MAIN_ICG_EN_UFS 76 +/* PER2CRG clocks */ +#define JHB100_PER2CLK_300 0 +#define JHB100_PER2CLK_100 1 +#define JHB100_PER2CLK_50 2 +#define JHB100_PER2CLK_GMAC2_RMII_50 3 +#define JHB100_PER2CLK_CAN0_CORE_DIV 4 +#define JHB100_PER2CLK_CAN1_CORE_DIV 5 +#define JHB100_PER2CLK_CAN0_TIMER 6 +#define JHB100_PER2CLK_CAN1_TIMER 7 + +#define JHB100_PER2CLK_RTC_CORE_DIV 11 +#define JHB100_PER2CLK_GMAC2_RMII_MUX_DLY 12 +#define JHB100_PER2CLK_GMAC2_RMII_DIV 13 + +#define JHB100_PER2CLK_GMAC2_RGMII_125_MUX 15 +#define JHB100_PER2CLK_GMAC2_RGMII_DIV 16 +#define JHB100_PER2CLK_GMAC2_TX_MUX 17 +#define JHB100_PER2CLK_GMAC2_TX_180_BUF 18 +#define JHB100_PER2CLK_GMAC2_RX_MUX_DLY 19 +#define JHB100_PER2CLK_GMAC2_RX_180_BUF 20 +#define JHB100_PER2CLK_GMAC2_TXCK_MUX_DLY 21 +#define JHB100_PER2CLK_GMAC3_TX_125_MUX 22 +#define JHB100_PER2CLK_GMAC3_RX_125_MUX 23 +#define JHB100_PER2CLK_GMAC3_TX_DIV 24 +#define JHB100_PER2CLK_GMAC3_RX_DIV 25 +#define JHB100_PER2CLK_SENSORS_PERIPH2 26 + +#define JHB100_PER2CLK_FAN_TACH_PCLK 33 + +#define JHB100_PER2CLK_ETHER0_RMIIANDRGMII_TX_I 44 +#define JHB100_PER2CLK_ETHER0_RMIIANDRGMII_RX_I 45 +#define JHB100_PER2CLK_ETHER0_RMIIANDRGMII_TX_180_I 46 +#define JHB100_PER2CLK_ETHER0_RMIIANDRGMII_RX_180_I 47 +#define JHB100_PER2CLK_ETHER0_RMIIANDRGMII_PTP_REF_I 48 +#define JHB100_PER2CLK_ETHER0_RMIIANDRGMII_RMII_I 49 +#define JHB100_PER2CLK_ETHER0_RMIIANDRGMII_CSR_I 50 +#define JHB100_PER2CLK_ETHER0_RMIIANDRGMII_ACLK_I 51 +#define JHB100_PER2CLK_RMIIANDRGMII_IOMUX_GMAC2_TXCK 52 +#define JHB100_PER2CLK_ETHER1_SGMII_TX_I 53 +#define JHB100_PER2CLK_ETHER1_SGMII_RX_I 54 +#define JHB100_PER2CLK_ETHER1_SGMII_TX_125_I 55 +#define JHB100_PER2CLK_ETHER1_SGMII_RX_125_I 56 +#define JHB100_PER2CLK_ETHER1_SGMII_PTP_REF_I 57 +#define JHB100_PER2CLK_ETHER1_SGMII_CSR_I 58 +#define JHB100_PER2CLK_ETHER1_SGMII_ACLK_I 59 +#define JHB100_PER2CLK_ETHER1_SGMII_PHY_PCLK_I 60 +#define JHB100_PER2CLK_ETHER1_SGMII_REF_25_I 61 +#define JHB100_PER2CLK_MAIN_ICG_EN_CAN0 62 +#define JHB100_PER2CLK_MAIN_ICG_EN_CAN1 63 + +#define JHB100_PER2CLK_MAIN_ICG_EN_DMAC_8CH 65 +#define JHB100_PER2CLK_MAIN_ICG_EN_RTC_SCAN 66 +#define JHB100_PER2CLK_MAIN_ICG_EN_ADC0 67 +#define JHB100_PER2CLK_MAIN_ICG_EN_ADC1 68 +#define JHB100_PER2CLK_MAIN_ICG_EN_GMAC2 69 +#define JHB100_PER2CLK_MAIN_ICG_EN_GMAC3 70 + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ */ diff --git a/include/dt-bindings/reset/starfive,jhb100-crg.h b/include/dt-bindings/reset/starfive,jhb100-crg.h index cf933a1befbb..0965f3798397 100644 --- a/include/dt-bindings/reset/starfive,jhb100-crg.h +++ b/include/dt-bindings/reset/starfive,jhb100-crg.h @@ -157,4 +157,21 @@ #define JHB100_PER1RST_MAIN_RSTN_DMAC_SPI0 15 #define JHB100_PER1RST_MAIN_RSTN_PERIPH1_RAS 16 +/* PER2CRG resets */ +#define JHB100_PER2RST_IOMUX_PRESETN 0 +#define JHB100_PER2RST_POK_IOMUX_PRESETN 1 +#define JHB100_PER2RST_SYSREG_RSTN 2 +#define JHB100_PER2RST_MAIN_RSTN_CAN0 3 +#define JHB100_PER2RST_MAIN_RSTN_CAN1 4 +#define JHB100_PER2RST_FAN_TACH_PRESETN 5 +#define JHB100_PER2RST_MAIN_RSTN_GMAC2 6 +#define JHB100_PER2RST_MAIN_RSTN_GMAC3 7 +#define JHB100_PER2RST_MAIN_RSTN_DMAC_8CH 8 +#define JHB100_PER2RST_MAIN_RSTN_RTC 9 +#define JHB100_PER2RST_ADC0_PRESETN 10 +#define JHB100_PER2RST_ADC0_IOMUX_PRESETN 11 +#define JHB100_PER2RST_ADC1_PRESETN 12 +#define JHB100_PER2RST_ADC1_IOMUX_PRESETN 13 +#define JHB100_PER2RST_MAIN_RSTN_PERIPH2_SENSORS 14 + #endif /* __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ */ From 17986e31f3b6142c302c8f9af16540422787daf9 Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Wed, 30 Sep 2026 05:43:13 -0700 Subject: [PATCH 144/168] dt-bindings: clock: Add StarFive JHB100 Peripheral-3 clock and reset generator Add bindings for the Peripheral-3 clock and reset generator (PER3CRG) on the JHB100 RISC-V SoC by StarFive Ltd. Signed-off-by: Changhuang Liang Reviewed-by: Rob Herring (Arm) Signed-off-by: Conor Dooley --- .../clock/starfive,jhb100-per3crg.yaml | 76 +++++++++++++++++++ .../dt-bindings/clock/starfive,jhb100-crg.h | 35 +++++++++ .../dt-bindings/reset/starfive,jhb100-crg.h | 9 +++ 3 files changed, 120 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/starfive,jhb100-per3crg.yaml diff --git a/Documentation/devicetree/bindings/clock/starfive,jhb100-per3crg.yaml b/Documentation/devicetree/bindings/clock/starfive,jhb100-per3crg.yaml new file mode 100644 index 000000000000..2c3b9f4146b5 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/starfive,jhb100-per3crg.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/starfive,jhb100-per3crg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JHB100 Peripheral-3 Clock and Reset Generator + +maintainers: + - Changhuang Liang + +properties: + compatible: + const: starfive,jhb100-per3crg + + reg: + maxItems: 1 + + clocks: + items: + - description: Non Coherent NOC Initiator + - description: Non Coherent NOC Target + - description: Configure 125MHz + - description: GMAC0 RMII Reference clock + - description: GMAC1 SGMII TX + - description: GMAC1 SGMII RX + - description: Main Oscillator (25 MHz) + + clock-names: + items: + - const: ncnoc_init + - const: ncnoc_targ + - const: cfg_125 + - const: gmac0_rmii_rclki + - const: gmac1_sgmii_tx + - const: gmac1_sgmii_rx + - const: osc + + '#clock-cells': + const: 1 + description: + See for valid indices. + + '#reset-cells': + const: 1 + description: + See for valid indices. + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@11c40000 { + compatible = "starfive,jhb100-per3crg"; + reg = <0x11c40000 0x1000>; + clocks = <&sys0crg 65>, + <&sys1crg 18>, + <&sys1crg 19>, + <&per3_gmac0_rmii_rclki>, + <&per3_gmac1_sgmii_tx>, + <&per3_gmac1_sgmii_rx>, + <&osc>; + clock-names = "ncnoc_init", "ncnoc_targ", "cfg_125", + "gmac0_rmii_rclki", "gmac1_sgmii_tx", + "gmac1_sgmii_rx", "osc"; + #clock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/include/dt-bindings/clock/starfive,jhb100-crg.h b/include/dt-bindings/clock/starfive,jhb100-crg.h index 2b2e148ce5ce..bdf7d628b381 100644 --- a/include/dt-bindings/clock/starfive,jhb100-crg.h +++ b/include/dt-bindings/clock/starfive,jhb100-crg.h @@ -504,4 +504,39 @@ #define JHB100_PER2CLK_MAIN_ICG_EN_GMAC2 69 #define JHB100_PER2CLK_MAIN_ICG_EN_GMAC3 70 +/* PER3CRG clocks */ +#define JHB100_PER3CLK_300 0 +#define JHB100_PER3CLK_200 1 +#define JHB100_PER3CLK_GMAC1_PTP_REF 2 +#define JHB100_PER3CLK_GMAC1_TX_125_MUX 3 +#define JHB100_PER3CLK_GMAC1_TX 4 +#define JHB100_PER3CLK_GMAC1_RX_125_MUX 5 +#define JHB100_PER3CLK_GMAC1_RX 6 +#define JHB100_PER3CLK_GMAC0_PTP_REF 7 +#define JHB100_PER3CLK_GMAC0_RMII_PLL 8 +#define JHB100_PER3CLK_GMAC0_RMII_MUX 9 +#define JHB100_PER3CLK_GMAC0_RMII_MUX_DIV2 10 + +#define JHB100_PER3CLK_ETHER0_RMII_CLK_TX_I 17 +#define JHB100_PER3CLK_ETHER0_RMII_CLK_RX_I 18 +#define JHB100_PER3CLK_ETHER0_RMII_CLK_PTP_REF_I 19 +#define JHB100_PER3CLK_ETHER0_RMII_CLK_RMII_I 20 +#define JHB100_PER3CLK_ETHER0_RMII_CLK_CSR_I 21 +#define JHB100_PER3CLK_ETHER0_RMII_ACLK_I 22 +#define JHB100_PER3CLK_GMAC0_RMII_RCLKO 23 +#define JHB100_PER3CLK_ETHER0_SGMII_CLK_TX_I 24 +#define JHB100_PER3CLK_ETHER0_SGMII_CLK_RX_I 25 +#define JHB100_PER3CLK_ETHER0_SGMII_CLK_TX_125_I 26 +#define JHB100_PER3CLK_ETHER0_SGMII_CLK_RX_125_I 27 +#define JHB100_PER3CLK_ETHER0_SGMII_CLK_PTP_REF_I 28 +#define JHB100_PER3CLK_ETHER0_SGMII_CLK_REF_25_I 29 +#define JHB100_PER3CLK_ETHER0_SGMII_CLK_CSR_I 30 +#define JHB100_PER3CLK_ETHER0_SGMII_ACLK_I 31 +#define JHB100_PER3CLK_ETHER0_SGMII_PHY_PCLK_I 32 +#define JHB100_PER3CLK_MAIN_ICG_EN_SENSORS_PERIPH3 33 +#define JHB100_PER3CLK_MAIN_ICG_EN_PECI0 34 +#define JHB100_PER3CLK_MAIN_ICG_EN_PECI1 35 +#define JHB100_PER3CLK_MAIN_ICG_EN_GMAC0 36 +#define JHB100_PER3CLK_MAIN_ICG_EN_GMAC1 37 + #endif /* __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ */ diff --git a/include/dt-bindings/reset/starfive,jhb100-crg.h b/include/dt-bindings/reset/starfive,jhb100-crg.h index 0965f3798397..872a4dd25beb 100644 --- a/include/dt-bindings/reset/starfive,jhb100-crg.h +++ b/include/dt-bindings/reset/starfive,jhb100-crg.h @@ -174,4 +174,13 @@ #define JHB100_PER2RST_ADC1_IOMUX_PRESETN 13 #define JHB100_PER2RST_MAIN_RSTN_PERIPH2_SENSORS 14 +/* PER3CRG resets */ +#define JHB100_PER3RST_SYSREG_RSTN 0 +#define JHB100_PER3RST_MAIN_RSTN_GMAC0 1 +#define JHB100_PER3RST_MAIN_RSTN_GMAC1 2 +#define JHB100_PER3RST_MAIN_RSTN_PECI0 3 +#define JHB100_PER3RST_MAIN_RSTN_PECI1 4 +#define JHB100_PER3RST_MAIN_RSTN_PERIPH3_SENSORS 5 +#define JHB100_PER3RST_IOMUX_PRESETN 6 + #endif /* __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ */ From c4a545d3e428e9600d670fa8a08098b7bc82d5ec Mon Sep 17 00:00:00 2001 From: Changhuang Liang Date: Fri, 28 Aug 2026 02:56:01 -0700 Subject: [PATCH 145/168] dt-bindings: soc: starfive: Add StarFive JHB100 syscon modules Add documentation to describe StarFive JHB100 SoC System Controller Registers. Add the PLL clocks for the sys0, per0, and per1 domains under syscon, as well as the PCIe RP reset. Signed-off-by: Changhuang Liang Reviewed-by: Krzysztof Kozlowski Signed-off-by: Conor Dooley --- .../soc/starfive/starfive,jhb100-syscon.yaml | 115 ++++++++++++++++++ .../dt-bindings/clock/starfive,jhb100-crg.h | 12 ++ .../dt-bindings/reset/starfive,jhb100-crg.h | 3 + 3 files changed, 130 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/starfive/starfive,jhb100-syscon.yaml diff --git a/Documentation/devicetree/bindings/soc/starfive/starfive,jhb100-syscon.yaml b/Documentation/devicetree/bindings/soc/starfive/starfive,jhb100-syscon.yaml new file mode 100644 index 000000000000..000f53acab34 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/starfive/starfive,jhb100-syscon.yaml @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/starfive/starfive,jhb100-syscon.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: StarFive JHB100 SoC system controller + +maintainers: + - Kevin Xie + - Changhuang Liang + +description: + The StarFive JHB100 SoC system controller contains MMIO registers used by + other hardware modules (e.g., PLL, eMMC, PCIe). These modules access + specific register offsets, bit masks, and shifts within the system + controller region for configuration and status. + +properties: + compatible: + items: + - enum: + - starfive,jhb100-b2h-syscon + - starfive,jhb100-gpu-syscon + - starfive,jhb100-h2b-syscon + - starfive,jhb100-host-syscon + - starfive,jhb100-husb-syscon + - starfive,jhb100-husbcmn-syscon + - starfive,jhb100-husbd-syscon + - starfive,jhb100-npu-syscon + - starfive,jhb100-pcieep-ecsr-syscon + - starfive,jhb100-pcierp-ecsr-syscon + - starfive,jhb100-pcierp-syscon + - starfive,jhb100-per0-syscon + - starfive,jhb100-per1-syscon + - starfive,jhb100-per2-syscon + - starfive,jhb100-per3-syscon + - starfive,jhb100-sfc-filter-syscon + - starfive,jhb100-strap-syscon + - starfive,jhb100-sys0-syscon + - starfive,jhb100-sys1-syscon + - starfive,jhb100-sys2-syscon + - starfive,jhb100-usb-syscon + - starfive,jhb100-vout-syscon + - const: syscon + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + '#clock-cells': + const: 1 + + '#reset-cells': + const: 1 + +required: + - compatible + - reg + +allOf: + - if: + properties: + compatible: + contains: + enum: + - starfive,jhb100-per0-syscon + - starfive,jhb100-per1-syscon + - starfive,jhb100-sys0-syscon + then: + required: + - clocks + - '#clock-cells' + else: + properties: + clocks: false + '#clock-cells': false + + - if: + properties: + compatible: + contains: + const: starfive,jhb100-pcierp-syscon + then: + required: + - '#reset-cells' + else: + properties: + '#reset-cells': false + +additionalProperties: false + +examples: + - | + syscon@13010000 { + compatible = "starfive,jhb100-sys0-syscon", "syscon"; + reg = <0x13010000 0x2000>; + clocks = <&osc>; + #clock-cells = <1>; + }; + + syscon@13014000 { + compatible = "starfive,jhb100-sys1-syscon", "syscon"; + reg = <0x13014000 0x4000>; + }; + + syscon@11719000 { + compatible = "starfive,jhb100-pcierp-syscon", "syscon"; + reg = <0x11719000 0x1000>; + #reset-cells = <1>; + }; + +... diff --git a/include/dt-bindings/clock/starfive,jhb100-crg.h b/include/dt-bindings/clock/starfive,jhb100-crg.h index bdf7d628b381..4270bfa532e8 100644 --- a/include/dt-bindings/clock/starfive,jhb100-crg.h +++ b/include/dt-bindings/clock/starfive,jhb100-crg.h @@ -8,6 +8,18 @@ #ifndef __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ #define __DT_BINDINGS_CLOCK_STARFIVE_JHB100_H__ +/* SYS0PLL clocks */ +#define JHB100_SYS0PLL_PLL2_OUT 0 +#define JHB100_SYS0PLL_PLL3_OUT 1 +#define JHB100_SYS0PLL_PLL4_OUT 2 +#define JHB100_SYS0PLL_PLL5_OUT 3 + +/* PER0PLL clocks */ +#define JHB100_PER0PLL_PLL6_OUT 0 + +/* PER1PLL clocks */ +#define JHB100_PER1PLL_PLL7_OUT 0 + /* SYS0CRG clocks */ #define JHB100_SYS0CLK_BMCPCIERP_NCNOC_MAIN 17 #define JHB100_SYS0CLK_BMCPCIERP_NCNOC_CFG 18 diff --git a/include/dt-bindings/reset/starfive,jhb100-crg.h b/include/dt-bindings/reset/starfive,jhb100-crg.h index 872a4dd25beb..1489bb01c2bd 100644 --- a/include/dt-bindings/reset/starfive,jhb100-crg.h +++ b/include/dt-bindings/reset/starfive,jhb100-crg.h @@ -183,4 +183,7 @@ #define JHB100_PER3RST_MAIN_RSTN_PERIPH3_SENSORS 5 #define JHB100_PER3RST_IOMUX_PRESETN 6 +/* PCIERP SYSCON resets */ +#define JHB100_PCIERP_SYSCONRST_PE2RST_OUT 0 + #endif /* __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__ */ From 602aba4a3924486fbae7d388b853fedb37e69a42 Mon Sep 17 00:00:00 2001 From: Francesco Dolcini Date: Wed, 30 Sep 2026 13:49:06 +0200 Subject: [PATCH 146/168] clk: clk-gpio: do not blame the DT property on probe deferral The message is also stored as the probe deferral reason, where it wrongly claims the 'enable'/'select' property is missing while it is the GPIO provider that has not probed (yet?). Signed-off-by: Francesco Dolcini Reviewed-by: Heiko Stuebner Link: https://patch.msgid.link/20260930114907.153690-1-francesco@dolcini.it Signed-off-by: Jerome Brunet Signed-off-by: Brian Masney --- drivers/clk/clk-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 9099c57e2715..918b2c6444ee 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -214,7 +214,7 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW); if (IS_ERR(gpiod)) return dev_err_probe(dev, PTR_ERR(gpiod), - "Can't get '%s' named GPIO property\n", gpio_name); + "Can't get '%s' GPIO\n", gpio_name); if (is_mux) hw = clk_hw_register_gpio_mux(dev, gpiod); From 26ec588063d9b6c70773b8729372e2bf6d3ea95a Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 30 Sep 2026 19:24:47 +0200 Subject: [PATCH 147/168] clk: nuvoton: ma35d1: Keep the clock count in the driver The number of clocks is not a binding since this is a value that can change. As such, in order to support the missing watchdog clocks and allow the deprecation and removal of CLK_MAX_IDX from the bindings, we need to switch to a local definition first. Signed-off-by: Miquel Raynal Link: https://patch.msgid.link/20260930-perso-ma35d1-upstream-clk-v6-1-48937ee6c9bb@bootlin.com Signed-off-by: Jerome Brunet Signed-off-by: Brian Masney --- drivers/clk/nuvoton/clk-ma35d1.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c index 9f65d0623517..6aa42a3e1be3 100644 --- a/drivers/clk/nuvoton/clk-ma35d1.c +++ b/drivers/clk/nuvoton/clk-ma35d1.c @@ -17,6 +17,7 @@ static DEFINE_SPINLOCK(ma35d1_lock); #define PLL_MAX_NUM 5 +#define MA35D1_CLK_COUNT 236 /* Clock Control Registers Offset */ #define REG_CLK_PWRCTL 0x00 @@ -467,12 +468,12 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) int ret; ma35d1_hw_data = devm_kzalloc(dev, - struct_size(ma35d1_hw_data, hws, CLK_MAX_IDX), + struct_size(ma35d1_hw_data, hws, MA35D1_CLK_COUNT), GFP_KERNEL); if (!ma35d1_hw_data) return -ENOMEM; - ma35d1_hw_data->num = CLK_MAX_IDX; + ma35d1_hw_data->num = MA35D1_CLK_COUNT; hws = ma35d1_hw_data->hws; clk_base = devm_platform_ioremap_resource(pdev, 0); From ea1f41802312e77b58113146a060fb0546b2234d Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 30 Sep 2026 19:24:48 +0200 Subject: [PATCH 148/168] dt-bindings: clock: ma35d1: Document the missing crystal inputs The MA35D1 clock controller takes two crystal oscillator inputs from the board: - HXT, a high-speed 24 MHz crystal for most of the system - LXT, a low-speed 32.768 kHz crytal for the RTC and low power modes So far the binding was expecting a single crystal. The example named it HXT, but no real definition for it was given. LXT was not even described. In order to remain backward compatible, we will continue to allow either one (HXT) or two (HXT then LXT) input clocks. I propose to give those phandles a name to clarify what these entries expect, but I'm not listing the clock-names property in the required block, for backward compatibility. The rates are fixed by the TRM, so even if the second oscillator is not described, the OS can make an educated guess. Fixes: 2f8b5eb589cb ("dt-bindings: clock: nuvoton: add binding for ma35d1 clock controller") Cc: stable@vger.kernel.org Reviewed-by: Krzysztof Kozlowski Signed-off-by: Miquel Raynal Link: https://patch.msgid.link/20260930-perso-ma35d1-upstream-clk-v6-2-48937ee6c9bb@bootlin.com Signed-off-by: Jerome Brunet Signed-off-by: Brian Masney --- .../bindings/clock/nuvoton,ma35d1-clk.yaml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/nuvoton,ma35d1-clk.yaml b/Documentation/devicetree/bindings/clock/nuvoton,ma35d1-clk.yaml index 8f0c43683729..9649feda8d7a 100644 --- a/Documentation/devicetree/bindings/clock/nuvoton,ma35d1-clk.yaml +++ b/Documentation/devicetree/bindings/clock/nuvoton,ma35d1-clk.yaml @@ -29,7 +29,18 @@ properties: const: 1 clocks: - maxItems: 1 + minItems: 1 + maxItems: 2 + description: + The controller takes 2 crystal oscillator inputs from the board. + HXT is a 24 MHz crystal feeding the internal PLLs. LXT is a 32.768 + kHz crystal, for RTC and low power operations. + + clock-names: + minItems: 1 + items: + - const: hxt + - const: lxt nuvoton,pll-mode: description: @@ -58,6 +69,7 @@ examples: compatible = "nuvoton,ma35d1-clk"; reg = <0x40460200 0x100>; #clock-cells = <1>; - clocks = <&clk_hxt>; + clocks = <&clk_hxt>, <&clk_lxt>; + clock-names = "hxt", "lxt"; }; ... From 653738db38c7c7f0fb959a7870f9461cf4987825 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 30 Sep 2026 19:24:49 +0200 Subject: [PATCH 149/168] dt-bindings: clock: ma35d1: Drop CLK_MAX_IDX define Drop CLK_MAX_IDX define of MA35D1 include. This is not a binding and should not be placed here. Value is defined in the user driver. Acked-by: Conor Dooley Signed-off-by: Miquel Raynal Link: https://patch.msgid.link/20260930-perso-ma35d1-upstream-clk-v6-3-48937ee6c9bb@bootlin.com Signed-off-by: Jerome Brunet Signed-off-by: Brian Masney --- include/dt-bindings/clock/nuvoton,ma35d1-clk.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/dt-bindings/clock/nuvoton,ma35d1-clk.h b/include/dt-bindings/clock/nuvoton,ma35d1-clk.h index ba2d70f776a6..2d6a44a7e55c 100644 --- a/include/dt-bindings/clock/nuvoton,ma35d1-clk.h +++ b/include/dt-bindings/clock/nuvoton,ma35d1-clk.h @@ -248,6 +248,5 @@ #define ADC_GATE 233 #define EADC_DIV 234 #define EADC_GATE 235 -#define CLK_MAX_IDX 236 #endif /* __DT_BINDINGS_CLOCK_NUVOTON_MA35D1_CLK_H */ From 8c7453cb0b01bee47ec2f902a9ac1872d3b77f3d Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 30 Sep 2026 19:24:50 +0200 Subject: [PATCH 150/168] dt-bindings: clock: ma35d1: Add missing WDT/WWDT parent clocks The WDT and WWDT muxes have PCLK3/4096 and PCLK4/4096 among their possible parents, but these fixed factor clocks are currently not defined, even though they are needed to properly describe the clock tree. Add them to the bindings. Acked-by: Conor Dooley Signed-off-by: Miquel Raynal Link: https://patch.msgid.link/20260930-perso-ma35d1-upstream-clk-v6-4-48937ee6c9bb@bootlin.com Signed-off-by: Jerome Brunet Signed-off-by: Brian Masney --- include/dt-bindings/clock/nuvoton,ma35d1-clk.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/dt-bindings/clock/nuvoton,ma35d1-clk.h b/include/dt-bindings/clock/nuvoton,ma35d1-clk.h index 2d6a44a7e55c..764d837d6162 100644 --- a/include/dt-bindings/clock/nuvoton,ma35d1-clk.h +++ b/include/dt-bindings/clock/nuvoton,ma35d1-clk.h @@ -248,5 +248,7 @@ #define ADC_GATE 233 #define EADC_DIV 234 #define EADC_GATE 235 +#define PCLK3_DIV4096 236 +#define PCLK4_DIV4096 237 #endif /* __DT_BINDINGS_CLOCK_NUVOTON_MA35D1_CLK_H */ From 1dc3871ce7ec819030c22297f8960c61cc42a990 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 30 Sep 2026 19:24:51 +0200 Subject: [PATCH 151/168] clk: nuvoton: ma35d1: Add missing WDT/WWDT parent clocks The WDT and WWDT muxes list PCLK3/4096 and PCLK4/4096 among their possible parents, but the driver never registers the corresponding clocks, so these parents could never be used. Add pclk3_div4096 and pclk4_div4096 as fixed factor children of pclk3 and pclk4 and expose them through the clock provider. Reported-by: Jacky Huang Closes: https://lore.kernel.org/linux-clk/b8a8a65b-e302-4747-bc90-4920fc48795a@gmail.com/ Suggested-by: Jacky Huang Fixes: 691521a367cf ("clk: nuvoton: Add clock driver for ma35d1 clock controller") Cc: stable@vger.kernel.org Reviewed-by: Jerome Brunet Signed-off-by: Miquel Raynal Link: https://patch.msgid.link/20260930-perso-ma35d1-upstream-clk-v6-5-48937ee6c9bb@bootlin.com [jbrunet@baylibre.com: removed stale link trailer] Signed-off-by: Jerome Brunet Signed-off-by: Brian Masney --- drivers/clk/nuvoton/clk-ma35d1.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/nuvoton/clk-ma35d1.c b/drivers/clk/nuvoton/clk-ma35d1.c index 6aa42a3e1be3..c914079cee2d 100644 --- a/drivers/clk/nuvoton/clk-ma35d1.c +++ b/drivers/clk/nuvoton/clk-ma35d1.c @@ -17,7 +17,7 @@ static DEFINE_SPINLOCK(ma35d1_lock); #define PLL_MAX_NUM 5 -#define MA35D1_CLK_COUNT 236 +#define MA35D1_CLK_COUNT 238 /* Clock Control Registers Offset */ #define REG_CLK_PWRCTL 0x00 @@ -544,6 +544,8 @@ static int ma35d1_clocks_probe(struct platform_device *pdev) hws[HCLK3] = ma35d1_clk_fixed_factor(dev, "hclk3", "sysclk1_mux", 1, 2); hws[PCLK3] = ma35d1_clk_fixed_factor(dev, "pclk3", "sysclk1_mux", 1, 2); hws[PCLK4] = ma35d1_clk_fixed_factor(dev, "pclk4", "sysclk1_mux", 1, 2); + hws[PCLK3_DIV4096] = ma35d1_clk_fixed_factor(dev, "pclk3_div4096", "pclk3", 1, 4096); + hws[PCLK4_DIV4096] = ma35d1_clk_fixed_factor(dev, "pclk4_div4096", "pclk4", 1, 4096); hws[USBPHY0] = ma35d1_clk_fixed("usbphy0", 480000000); hws[USBPHY1] = ma35d1_clk_fixed("usbphy1", 480000000); From 7bdc3c32d5037f9d55c5f109e29f0c2c066ba522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:29 +0300 Subject: [PATCH 152/168] dt-bindings: clk: zte: Add zx297520v3 top clock and reset controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These SoCs have 3 clock and reset controllers: Top, Matrix and LSP. Clocks go from oscillator -> top -> matrix -> LSP, with a register in top controlling most clocks that get passed to matrix and a register in matrix controlling all the clocks that get passed to LSP. Generally every device has two clocks (one work clock, and one that connects it to the bus, I call it PCLK), two reset bits (I don't know what the difference is - sometimes asserting one is enough to reset the device, sometimes both need to be asserted). PCLK and WCLK are controlled by individual gates. Some devices have a mux and/or a divider for their work clock. Some devices, like the GPIO controller, only have reset bits and no clocks. The top clock controller is fed by a 26 MHz external oscillator and has 4 PLLs to generate other clock rates. ZTE's kernel mostly relies on the boot ROM to set up PLLs, but one LTE-related PLL is not configured on some boards. Therefore my driver contains code to program PLLs. It produces identical settings as the boot ROM for the pre-programmed frequencies. Not all clocks will have an explicit user in the end. I am defining a lot of them simply to shut them off. The boot loader sets up a few of the proprietary timers, which will send regular IRQs (although the kernel of course doesn't need to listen to them). I don't plan to add a driver for the proprietary timer as I see no use for them - the ARM arch timer works just fine. I will add a driver for the very similar proprietary watchdog though. The clock list in this patch is pretty complete but not exhaustive. There are other bits that are enabled, but I couldn't deduce what they are controlling by trial and error. Some of them seem to do nothing. Others cause an instant hang of the board when disabled. It is quite likely that a handful more clocks will be added in the future, but not a large number. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stefan Dösinger Signed-off-by: Brian Masney --- .../bindings/clock/zte,zx297520v3-topcrm.yaml | 122 ++++++++++++++++++ MAINTAINERS | 4 + .../dt-bindings/clock/zte,zx297520v3-clk.h | 72 +++++++++++ .../dt-bindings/phy/zte,zx297520v3-topcrm.h | 12 ++ .../dt-bindings/reset/zte,zx297520v3-reset.h | 30 +++++ 5 files changed, 240 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml create mode 100644 include/dt-bindings/clock/zte,zx297520v3-clk.h create mode 100644 include/dt-bindings/phy/zte,zx297520v3-topcrm.h create mode 100644 include/dt-bindings/reset/zte,zx297520v3-reset.h diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml new file mode 100644 index 000000000000..8510ffde2924 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml @@ -0,0 +1,122 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zte,zx297520v3-topcrm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ZTE zx297520v3 SoC top clock and reset controller + +maintainers: + - Stefan Dösinger + +description: | + The zx297520v3 top clock and reset controller generates clocks for core + devices on the board like the main bus, USB and timers. In addition to clocks + it has reset controls for peripherals, a global board reset, watchdog reset + controls and a USB status register. + + The controller has two clock inputs: a 26 MHz and a 32 kHz external + oscillator. They need to be provided as input clocks. The controller provides + PLL output frequencies to downstream clock controllers. + + The USB PHY is exposed as two PHYs, one for USB and another for HSIC. Note + that while the controls for both PHYs are always present, the PHYs themselves + may be absent. If this is the case the controller never signals that the + missing PHY is ready. + + All available clocks are defined as preprocessor macros in the + "include/dt-bindings/clock/zte,zx297520v3-clk.h" header. The resets are + defined in the "include/dt-bindings/reset/zte,zx297520v3-reset.h" header. PHY + defines are found in "include/dt-bindings/phy/zte,zx297520v3-topcrm.h". + +properties: + compatible: + items: + - const: zte,zx297520v3-topcrm + - const: syscon + + reg: + maxItems: 1 + + clocks: + items: + - description: 26 MHz external oscillator + - description: 32 kHz external oscillator + + clock-names: + items: + - const: osc26m + - const: osc32k + + interrupts: + items: + - description: IRQ reporting USB connection + - description: IRQ reporting USB disconnection + - description: IRQ reporting HSIC connection + - description: IRQ reporting HSIC disconnection + + interrupt-names: + items: + - const: usb-up + - const: usb-down + - const: hsic-up + - const: hsic-down + + "#clock-cells": + const: 1 + + "#phy-cells": + const: 1 + + "#reset-cells": + const: 1 + + reboot: + type: object + $ref: /schemas/power/reset/syscon-reboot.yaml# + unevaluatedProperties: false + description: + Reboot method for the SoC. + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - interrupt-names + - reboot + - "#clock-cells" + - "#phy-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + clock-controller@13b000 { + compatible = "zte,zx297520v3-topcrm", "syscon"; + reg = <0x0013b000 0x400>; + #clock-cells = <1>; + clocks = <&osc26m>, <&osc32k>; + clock-names = "osc26m", "osc32k"; + interrupts = , + , + , + ; + interrupt-names = "usb-up", "usb-down", "hsic-up", "hsic-down"; + #phy-cells = <1>; + #reset-cells = <1>; + + reboot { + compatible = "syscon-reboot"; + mask = <0x1>; + offset = <0x0>; + value = <0x1>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 6977bc6245b0..573341cca24a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3909,8 +3909,12 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Odd fixes F: Documentation/arch/arm/zte/ F: Documentation/devicetree/bindings/arm/zte.yaml +F: Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: include/dt-bindings/clock/zte,zx297520v3-clk.h +F: include/dt-bindings/phy/zte,zx297520v3-topcrm.h +F: include/dt-bindings/reset/zte,zx297520v3-reset.h ARM/ZYNQ ARCHITECTURE M: Michal Simek diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bindings/clock/zte,zx297520v3-clk.h new file mode 100644 index 000000000000..1bc9267e4d62 --- /dev/null +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) Stefan Dösinger. + */ + +#ifndef __DT_BINDINGS_CLOCK_ZX297520V3_H +#define __DT_BINDINGS_CLOCK_ZX297520V3_H + +#define ZX297520V3_M0_WCLK 0 +#define ZX297520V3_SRAM1_PCLK 1 +#define ZX297520V3_SRAM2_PCLK 2 +#define ZX297520V3_UART0_WCLK 3 +#define ZX297520V3_UART0_PCLK 4 +#define ZX297520V3_I2C0_WCLK 5 +#define ZX297520V3_I2C0_PCLK 6 +#define ZX297520V3_RTC_WCLK 7 +#define ZX297520V3_RTC_PCLK 8 +#define ZX297520V3_LPM_GSM_WCLK 9 +#define ZX297520V3_LPM_GSM_PCLK 10 +#define ZX297520V3_LPM_LTE_WCLK 11 +#define ZX297520V3_LPM_LTE_PCLK 12 +#define ZX297520V3_LPM_TD_WCLK 13 +#define ZX297520V3_LPM_TD_PCLK 14 +#define ZX297520V3_LPM_W_WCLK 15 +#define ZX297520V3_LPM_W_PCLK 16 +#define ZX297520V3_TIMER_T08_WCLK 17 +#define ZX297520V3_TIMER_T08_PCLK 18 +#define ZX297520V3_TIMER_T09_WCLK 19 +#define ZX297520V3_TIMER_T09_PCLK 20 +#define ZX297520V3_MPLL 21 +#define ZX297520V3_MPLL_D5 22 +#define ZX297520V3_DPLL 23 +#define ZX297520V3_GPLL 24 +#define ZX297520V3_GPLL_D2 25 +#define ZX297520V3_GATED_OSC26M 26 +#define ZX297520V3_PMM_WCLK 27 +#define ZX297520V3_PMM_PCLK 28 +#define ZX297520V3_OUT0_WCLK 29 +#define ZX297520V3_OUT1_WCLK 30 +#define ZX297520V3_OUT2_WCLK 31 +#define ZX297520V3_OUT32K_WCLK 32 +#define ZX297520V3_RMIIPHY_WCLK 33 +#define ZX297520V3_TIMER_T12_WCLK 34 +#define ZX297520V3_TIMER_T12_PCLK 35 +#define ZX297520V3_TIMER_T13_WCLK 36 +#define ZX297520V3_TIMER_T13_PCLK 37 +#define ZX297520V3_TIMER_T14_WCLK 38 +#define ZX297520V3_TIMER_T14_PCLK 39 +#define ZX297520V3_TIMER_T15_WCLK 40 +#define ZX297520V3_TIMER_T15_PCLK 41 +#define ZX297520V3_TIMER_T16_WCLK 42 +#define ZX297520V3_TIMER_T16_PCLK 43 +#define ZX297520V3_TIMER_T17_WCLK 44 +#define ZX297520V3_TIMER_T17_PCLK 45 +#define ZX297520V3_WDT_T18_WCLK 46 +#define ZX297520V3_WDT_T18_PCLK 47 +#define ZX297520V3_USIM1_WCLK 48 +#define ZX297520V3_USIM1_PCLK 49 +#define ZX297520V3_AHB_WCLK 50 +#define ZX297520V3_AHB_PCLK 51 +#define ZX297520V3_USB_WCLK 52 +#define ZX297520V3_USB_PCLK 53 +#define ZX297520V3_HSIC_WCLK 54 +#define ZX297520V3_HSIC_PCLK 55 +#define ZX297520V3_GSM_32K 56 +#define ZX297520V3_GSM_26M 57 +#define ZX297520V3_GSM_48M 58 +#define ZX297520V3_GSM_104M 59 +#define ZX297520V3_GSM_156M 60 +#define ZX297520V3_ABB_WCLK 61 + +#endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */ diff --git a/include/dt-bindings/phy/zte,zx297520v3-topcrm.h b/include/dt-bindings/phy/zte,zx297520v3-topcrm.h new file mode 100644 index 000000000000..b36ccf2f54ef --- /dev/null +++ b/include/dt-bindings/phy/zte,zx297520v3-topcrm.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) Stefan Dösinger. + */ + +#ifndef __DT_BINDINGS_PHY_ZTE_ZX297520V3_TOPCRM_H +#define __DT_BINDINGS_PHY_ZTE_ZX297520V3_TOPCRM_H + +#define ZX297520V3_USB_PHY 0 +#define ZX297520V3_HSIC_PHY 1 + +#endif /* __DT_BINDINGS_PHY_ZTE_ZX297520V3_TOPCRM_H */ diff --git a/include/dt-bindings/reset/zte,zx297520v3-reset.h b/include/dt-bindings/reset/zte,zx297520v3-reset.h new file mode 100644 index 000000000000..4a0eaec0e981 --- /dev/null +++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) Stefan Dösinger. + */ + +#ifndef __DT_BINDINGS_RESET_ZX297520V3_H +#define __DT_BINDINGS_RESET_ZX297520V3_H + +#define ZX297520V3_ZSP_CORE_RESET 0 +#define ZX297520V3_UART0_RESET 1 +#define ZX297520V3_I2C0_RESET 2 +#define ZX297520V3_RTC_RESET 3 +#define ZX297520V3_TIMER_T08_RESET 4 +#define ZX297520V3_TIMER_T09_RESET 5 +#define ZX297520V3_PMM_RESET 6 +#define ZX297520V3_GPIO_RESET 7 +#define ZX297520V3_GPIO8_RESET 8 +#define ZX297520V3_TIMER_T12_RESET 9 +#define ZX297520V3_TIMER_T13_RESET 10 +#define ZX297520V3_TIMER_T14_RESET 11 +#define ZX297520V3_TIMER_T15_RESET 12 +#define ZX297520V3_TIMER_T16_RESET 13 +#define ZX297520V3_TIMER_T17_RESET 14 +#define ZX297520V3_WDT_T18_RESET 15 +#define ZX297520V3_USIM1_RESET 16 +#define ZX297520V3_AHB_RESET 17 +#define ZX297520V3_USB_RESET 18 +#define ZX297520V3_HSIC_RESET 19 + +#endif /* __DT_BINDINGS_RESET_ZX297520V3_H */ From 574e62ac2dd913774486b09ff2672be872f23aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:50:55 +0300 Subject: [PATCH 153/168] dt-bindings: clk: zte: Add zx297520v3 matrix clock and reset controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This controller contains clocks and resets for high speed devices on the zx297520v3 board and hardware spinlocks that I expect will be necessary to communicate correctly with the LTE DSP firmware blob. I don't know much about the hwlocks yet other than that they exist, so there is no header yet adding meaning to their indices. Presumably that meaning doesn't exist in hardware and is de facto defined by ZTE's firmware blobs running on the rprocs. The zte-zx297520v3-crm driver will instantiate separate MFD children for clocks and resets, which are handled by separate clock and reset drivers. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stefan Dösinger Signed-off-by: Brian Masney --- .../clock/zte,zx297520v3-matrixcrm.yaml | 98 +++++++++++++++++++ MAINTAINERS | 1 + .../dt-bindings/clock/zte,zx297520v3-clk.h | 45 +++++++++ .../dt-bindings/reset/zte,zx297520v3-reset.h | 13 +++ 4 files changed, 157 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml new file mode 100644 index 000000000000..5e9506db7365 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml @@ -0,0 +1,98 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zte,zx297520v3-matrixcrm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ZTE zx297520v3 SoC matrix clock and reset controller + +maintainers: + - Stefan Dösinger + +description: | + This controller contains clock and reset controls for high speed devices on + the zx297520v3 board: The CPU, RAM, SDIO and Ethernet clocks and resets are + found here. This controller requires PLL-generated clocks from Topcrm as well + as the fixed 26 MHz and 32 kHz oscillators found on this board. + + This controller also contains hardware mutex registers for synchronization + with different processors on this board. + + An additional curiosity are registers that allow setting (but not reading) the + ARM architected timer's CNTVAL. This is not exposed in the binding because + there shouldn't be a need to access it. + + All available clocks are defined as preprocessor macros in the + "include/dt-bindings/clock/zte,zx297520v3-clk.h" header. Resets are defined in + the "include/dt-bindings/reset/zte,zx297520v3-reset.h" header. + +properties: + compatible: + const: zte,zx297520v3-matrixcrm + + reg: + maxItems: 1 + + clocks: + items: + - description: 26 MHz external oscillator + - description: 32 kHz external oscillator + - description: AHB clock from topcrm + - description: Main PLL output from topcrm (usually 624 MHz) + - description: Main PLL subdivision factor 5 + - description: Dpll output from topcrm (usually 491.52 MHz) + - description: Gpll output from topcrm (usually 200 MHz) + - description: Gpll subdivision factor 2 + - description: osc26m work clock from topcrm + + clock-names: + items: + - const: osc26m + - const: osc32k + - const: ahb + - const: mpll + - const: mpll-d5 + - const: dpll + - const: gpll + - const: gpll-d2 + - const: wclk-osc26m + + "#clock-cells": + const: 1 + + "#hwlock-cells": + const: 1 + + "#reset-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - "#clock-cells" + - "#hwlock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + clock-controller@1306000 { + compatible = "zte,zx297520v3-matrixcrm"; + reg = <0x01306000 0x400>; + #clock-cells = <1>; + clocks = <&osc26m>, <&osc32k>, <&topcrm ZX297520V3_AHB_PCLK>, + <&topcrm ZX297520V3_MPLL>, <&topcrm ZX297520V3_MPLL_D5>, + <&topcrm ZX297520V3_DPLL>, <&topcrm ZX297520V3_GPLL>, + <&topcrm ZX297520V3_GPLL_D2>, + <&topcrm ZX297520V3_GATED_OSC26M>; + clock-names = "osc26m", "osc32k", "ahb", "mpll", "mpll-d5", "dpll", + "gpll", "gpll-d2", "wclk-osc26m"; + #hwlock-cells = <1>; + #reset-cells = <1>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 573341cca24a..e7f9a1a8db1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3909,6 +3909,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Odd fixes F: Documentation/arch/arm/zte/ F: Documentation/devicetree/bindings/arm/zte.yaml +F: Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml F: Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bindings/clock/zte,zx297520v3-clk.h index 1bc9267e4d62..d98bc38635b0 100644 --- a/include/dt-bindings/clock/zte,zx297520v3-clk.h +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -69,4 +69,49 @@ #define ZX297520V3_GSM_156M 60 #define ZX297520V3_ABB_WCLK 61 +#define ZX297520V3_SYS_TIMER_WCLK 0 +#define ZX297520V3_CPU_WCLK 1 +#define ZX297520V3_CPU_PCLK 2 +#define ZX297520V3_ZSP_WCLK 3 +#define ZX297520V3_ZSP_PCLK 4 +#define ZX297520V3_DDR_CTRL_PCLK 5 +#define ZX297520V3_DDR_CTRL_WCLK 6 +#define ZX297520V3_EDCP_WCLK 7 +#define ZX297520V3_EDCP_PCLK 8 +#define ZX297520V3_SD0_WCLK 9 +#define ZX297520V3_SD0_PCLK 10 +#define ZX297520V3_SD0_CDET 11 +#define ZX297520V3_SD1_WCLK 12 +#define ZX297520V3_SD1_PCLK 13 +#define ZX297520V3_SD1_CDET 14 +#define ZX297520V3_NAND_WCLK 15 +#define ZX297520V3_NAND_PCLK 16 +#define ZX297520V3_DMA_PCLK 17 +#define ZX297520V3_MBOX_PCLK 18 +#define ZX297520V3_PDCFG_WCLK 19 +#define ZX297520V3_PDCFG_PCLK 20 +#define ZX297520V3_RFFE_WCLK 21 +#define ZX297520V3_SSC_WCLK 22 +#define ZX297520V3_SSC_PCLK 23 +#define ZX297520V3_AXI_WCLK 24 +#define ZX297520V3_GMAC_WCLK 25 +#define ZX297520V3_GMAC_PCLK 26 +#define ZX297520V3_GMAC_AHB 27 +#define ZX297520V3_VOU_WCLK 28 +#define ZX297520V3_VOU_PCLK 29 +#define ZX297520V3_LSP_MPLL_D5_WCLK 30 +#define ZX297520V3_LSP_MPLL_D4_WCLK 31 +#define ZX297520V3_LSP_MPLL_D6_WCLK 32 +#define ZX297520V3_LSP_MPLL_D8_WCLK 33 +#define ZX297520V3_LSP_MPLL_D12_WCLK 34 +#define ZX297520V3_LSP_OSC26M_WCLK 35 +#define ZX297520V3_LSP_OSC32K_WCLK 36 +#define ZX297520V3_LSP_PCLK 37 +#define ZX297520V3_LSP_TDM_WCLK 38 +#define ZX297520V3_LSP_DPLL_D4_WCLK 39 +#define ZX297520V3_SRAM0_PCLK 40 +#define ZX297520V3_GSM_CFG_PCLK 41 +#define ZX297520V3_LTE_MODEM_WCLK 42 +#define ZX297520V3_LTE_MODEM_PCLK 43 + #endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */ diff --git a/include/dt-bindings/reset/zte,zx297520v3-reset.h b/include/dt-bindings/reset/zte,zx297520v3-reset.h index 4a0eaec0e981..54e5b24f859a 100644 --- a/include/dt-bindings/reset/zte,zx297520v3-reset.h +++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h @@ -27,4 +27,17 @@ #define ZX297520V3_USB_RESET 18 #define ZX297520V3_HSIC_RESET 19 +#define ZX297520V3_CPU_RESET 0 +#define ZX297520V3_ZSP_BUS_RESET 1 +#define ZX297520V3_DDR_CTRL_RESET 2 +#define ZX297520V3_EDCP_RESET 3 +#define ZX297520V3_SD0_RESET 4 +#define ZX297520V3_SD1_RESET 5 +#define ZX297520V3_NAND_RESET 6 +#define ZX297520V3_PDCFG_RESET 7 +#define ZX297520V3_SSC_RESET 8 +#define ZX297520V3_GMAC_RESET 9 +#define ZX297520V3_VOU_RESET 10 +#define ZX297520V3_LSP_RESET 11 + #endif /* __DT_BINDINGS_RESET_ZX297520V3_H */ From 244539a22fbd11e18dbcbc02453e0f07f1a6368c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:31 +0300 Subject: [PATCH 154/168] dt-bindings: clk: zte: Add zx297520v3 LSP clock and reset controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The clock controller of the zx297520v3 Low Speed Peripherals is relatively clean. One register per device with gates, muxes and resets and for some devices a divider. There are even bits in the matrix controller to control propagation of clock lines down to LSP. The clocks are sorted by register address and I am convinced that the device list is complete. There are, however, a few more registers that are likely extra dividers for TDM and I2S devices. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stefan Dösinger Signed-off-by: Brian Masney --- .../bindings/clock/zte,zx297520v3-lspcrm.yaml | 101 ++++++++++++++++++ MAINTAINERS | 1 + .../dt-bindings/clock/zte,zx297520v3-clk.h | 37 +++++++ .../dt-bindings/reset/zte,zx297520v3-reset.h | 19 ++++ 4 files changed, 158 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml new file mode 100644 index 000000000000..b0a176ffda12 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zte,zx297520v3-lspcrm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ZTE zx297520v3 SoC LSP clock and reset controller + +maintainers: + - Stefan Dösinger + +description: | + This clock and reset controller controls low speed peripherals on the board. + This is a relatively isolated subsystem containing UART, I2C, I2S and SPI + devices. The controller is responsible for bringing the devices out of reset + and enabling their clocks as needed. + + The controller receives its clock signals from the matrix controller, and + these signals need to be declared as clock inputs. + + All available clocks are defined as preprocessor macros in the + "include/dt-bindings/clock/zte,zx297520v3-clk.h" header. Resets are defined in + the "include/dt-bindings/reset/zte,zx297520v3-reset.h" header. + +properties: + compatible: + const: zte,zx297520v3-lspcrm + + reg: + maxItems: 1 + + clocks: + items: + - description: Main PLL divided by 5 output from matrixcrm (124.8 MHz) + - description: Main PLL divided by 4 output from matrixcrm (156 MHz) + - description: Main PLL divided by 6 output from matrixcrm (104 MHz) + - description: Main PLL divided by 8 output from matrixcrm (78 MHz) + - description: Main PLL divided by 12 output from matrixcrm (52 MHz) + - description: Main oscillator output from matrixcrm (26 MHz) + - description: Timer oscillator output from matrixcrm (32 kHz) + - description: LSP pclk output from matrixcrm (26 MHz) + - description: TDM wclk mux output from matrixcrm + - description: DPLL divided by 4 output from matrixcrm (122.88 MHz) + + clock-names: + items: + - const: mpll-d5 + - const: mpll-d4 + - const: mpll-d6 + - const: mpll-d8 + - const: mpll-d12 + - const: osc26m + - const: osc32k + - const: pclk + - const: tdm-wclk + - const: dpll-d4 + + resets: + maxItems: 1 + + "#clock-cells": + const: 1 + + "#reset-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - "#clock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + clock-controller@1400000 { + compatible = "zte,zx297520v3-lspcrm"; + reg = <0x01400000 0x100>; + #clock-cells = <1>; + clocks = <&matrixcrm ZX297520V3_LSP_MPLL_D5_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D4_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D6_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D8_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D12_WCLK>, + <&matrixcrm ZX297520V3_LSP_OSC26M_WCLK>, + <&matrixcrm ZX297520V3_LSP_OSC32K_WCLK>, + <&matrixcrm ZX297520V3_LSP_PCLK>, + <&matrixcrm ZX297520V3_LSP_TDM_WCLK>, + <&matrixcrm ZX297520V3_LSP_DPLL_D4_WCLK>; + clock-names = "mpll-d5", "mpll-d4", "mpll-d6", "mpll-d8", "mpll-d12", + "osc26m", "osc32k", "pclk", "tdm-wclk", "dpll-d4"; + #reset-cells = <1>; + resets = <&matrixcrm ZX297520V3_LSP_RESET>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e7f9a1a8db1a..828d63847966 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3909,6 +3909,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Odd fixes F: Documentation/arch/arm/zte/ F: Documentation/devicetree/bindings/arm/zte.yaml +F: Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml F: Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml F: Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml F: arch/arm/boot/dts/zte/ diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bindings/clock/zte,zx297520v3-clk.h index d98bc38635b0..a63283d5df5c 100644 --- a/include/dt-bindings/clock/zte,zx297520v3-clk.h +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -114,4 +114,41 @@ #define ZX297520V3_LTE_MODEM_WCLK 42 #define ZX297520V3_LTE_MODEM_PCLK 43 +#define ZX297520V3_TIMER_L1_WCLK 0 +#define ZX297520V3_TIMER_L1_PCLK 1 +#define ZX297520V3_WDT_L2_WCLK 2 +#define ZX297520V3_WDT_L2_PCLK 3 +#define ZX297520V3_WDT_L3_WCLK 4 +#define ZX297520V3_WDT_L3_PCLK 5 +#define ZX297520V3_PWM_WCLK 6 +#define ZX297520V3_PWM_PCLK 7 +#define ZX297520V3_I2S0_WCLK 8 +#define ZX297520V3_I2S0_PCLK 9 +#define ZX297520V3_I2S1_WCLK 10 +#define ZX297520V3_I2S1_PCLK 11 +#define ZX297520V3_QSPI_WCLK 12 +#define ZX297520V3_QSPI_PCLK 13 +#define ZX297520V3_UART1_WCLK 14 +#define ZX297520V3_UART1_PCLK 15 +#define ZX297520V3_I2C1_WCLK 16 +#define ZX297520V3_I2C1_PCLK 17 +#define ZX297520V3_SPI0_WCLK 18 +#define ZX297520V3_SPI0_PCLK 19 +#define ZX297520V3_TIMER_LB_WCLK 20 +#define ZX297520V3_TIMER_LB_PCLK 21 +#define ZX297520V3_TIMER_LC_WCLK 22 +#define ZX297520V3_TIMER_LC_PCLK 23 +#define ZX297520V3_UART2_WCLK 24 +#define ZX297520V3_UART2_PCLK 25 +#define ZX297520V3_WDT_LE_WCLK 26 +#define ZX297520V3_WDT_LE_PCLK 27 +#define ZX297520V3_TIMER_LF_WCLK 28 +#define ZX297520V3_TIMER_LF_PCLK 29 +#define ZX297520V3_SPI1_WCLK 30 +#define ZX297520V3_SPI1_PCLK 31 +#define ZX297520V3_TIMER_L11_WCLK 32 +#define ZX297520V3_TIMER_L11_PCLK 33 +#define ZX297520V3_TDM_WCLK 34 +#define ZX297520V3_TDM_PCLK 35 + #endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */ diff --git a/include/dt-bindings/reset/zte,zx297520v3-reset.h b/include/dt-bindings/reset/zte,zx297520v3-reset.h index 54e5b24f859a..b21d5901a7b9 100644 --- a/include/dt-bindings/reset/zte,zx297520v3-reset.h +++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h @@ -40,4 +40,23 @@ #define ZX297520V3_VOU_RESET 10 #define ZX297520V3_LSP_RESET 11 +#define ZX297520V3_TIMER_L1_RESET 0 +#define ZX297520V3_WDT_L2_RESET 1 +#define ZX297520V3_WDT_L3_RESET 2 +#define ZX297520V3_PWM_RESET 3 +#define ZX297520V3_I2S0_RESET 4 +#define ZX297520V3_I2S1_RESET 5 +#define ZX297520V3_QSPI_RESET 6 +#define ZX297520V3_UART1_RESET 7 +#define ZX297520V3_I2C1_RESET 8 +#define ZX297520V3_SPI0_RESET 9 +#define ZX297520V3_TIMER_LB_RESET 10 +#define ZX297520V3_TIMER_LC_RESET 11 +#define ZX297520V3_UART2_RESET 12 +#define ZX297520V3_WDT_LE_RESET 13 +#define ZX297520V3_TIMER_LF_RESET 14 +#define ZX297520V3_SPI1_RESET 15 +#define ZX297520V3_TIMER_L11_RESET 16 +#define ZX297520V3_TDM_RESET 17 + #endif /* __DT_BINDINGS_RESET_ZX297520V3_H */ From 8a9b53cc1370db72dd8eefc51bfe4f3dad45de19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:34 +0300 Subject: [PATCH 155/168] clk: zte: Add Clock registration infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The next patches will implement the regmap clocks and PLL driver. The actual hardware specific clock listing will live in a separate module. Signed-off-by: Stefan Dösinger Signed-off-by: Brian Masney --- MAINTAINERS | 1 + drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/zte/Kconfig | 17 ++++ drivers/clk/zte/Makefile | 5 + drivers/clk/zte/clk-regmap.c | 32 ++++++ drivers/clk/zte/clk-zx.c | 192 +++++++++++++++++++++++++++++++++++ drivers/clk/zte/clk-zx.h | 137 +++++++++++++++++++++++++ drivers/clk/zte/pll-zx.c | 18 ++++ 9 files changed, 404 insertions(+) create mode 100644 drivers/clk/zte/Kconfig create mode 100644 drivers/clk/zte/Makefile create mode 100644 drivers/clk/zte/clk-regmap.c create mode 100644 drivers/clk/zte/clk-zx.c create mode 100644 drivers/clk/zte/clk-zx.h create mode 100644 drivers/clk/zte/pll-zx.c diff --git a/MAINTAINERS b/MAINTAINERS index 828d63847966..5e566cb7f370 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3914,6 +3914,7 @@ F: Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml F: Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: drivers/clk/zte/ F: include/dt-bindings/clock/zte,zx297520v3-clk.h F: include/dt-bindings/phy/zte,zx297520v3-topcrm.h F: include/dt-bindings/reset/zte,zx297520v3-reset.h diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 983bf74b86fb..0e8d1d4326b6 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -552,6 +552,7 @@ source "drivers/clk/uniphier/Kconfig" source "drivers/clk/visconti/Kconfig" source "drivers/clk/x86/Kconfig" source "drivers/clk/xilinx/Kconfig" +source "drivers/clk/zte/Kconfig" source "drivers/clk/zynqmp/Kconfig" # Kunit test cases diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d94de2988167..52d138d4ffc8 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -183,5 +183,6 @@ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_X86) += x86/ endif obj-y += xilinx/ +obj-$(CONFIG_COMMON_CLK_ZTE) += zte/ obj-$(CONFIG_ARCH_ZYNQ) += zynq/ obj-$(CONFIG_COMMON_CLK_ZYNQMP) += zynqmp/ diff --git a/drivers/clk/zte/Kconfig b/drivers/clk/zte/Kconfig new file mode 100644 index 000000000000..152c2423b8f0 --- /dev/null +++ b/drivers/clk/zte/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# ZTE Clock Drivers +# + +config COMMON_CLK_ZTE + tristate "Clock driver for ZTE SoCs" + depends on HAS_IOMEM + depends on ARCH_ZTE || COMPILE_TEST + default ARCH_ZTE + select MFD_SYSCON + help + This option selects common clock infrastructure for ZTE based SoCs. + You will need to enable one or more SoC specific drivers to make use + of this. + + Enable this if you are building a kernel for a ZTE designed board. diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile new file mode 100644 index 000000000000..27db07293165 --- /dev/null +++ b/drivers/clk/zte/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_COMMON_CLK_ZTE) += clk-zte.o + +clk-zte-y += clk-zx.o pll-zx.o clk-regmap.o diff --git a/drivers/clk/zte/clk-regmap.c b/drivers/clk/zte/clk-regmap.c new file mode 100644 index 000000000000..80332dba97f6 --- /dev/null +++ b/drivers/clk/zte/clk-regmap.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2026 Stefan Dösinger + */ + +#include +#include +#include +#include + +#include "clk-zx.h" + +struct clk_hw *zx_clk_register_gate(struct device *dev, struct regmap *regmap, + const struct zx_gate_desc *desc, + struct clk_hw * const *clocks) +{ + return ERR_PTR(-ENODEV); +} + +struct clk_hw *zx_clk_register_divider(struct device *dev, struct regmap *regmap, + const struct zx_div_desc *desc, + struct clk_hw * const *clocks) +{ + return ERR_PTR(-ENODEV); +} + +struct clk_hw *zx_clk_register_mux(struct device *dev, struct regmap *regmap, + const struct zx_mux_desc *desc, + struct clk_hw * const *clocks) +{ + return ERR_PTR(-ENODEV); +} diff --git a/drivers/clk/zte/clk-zx.c b/drivers/clk/zte/clk-zx.c new file mode 100644 index 000000000000..aef0f7c753e6 --- /dev/null +++ b/drivers/clk/zte/clk-zx.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan Dösinger + */ + +#include +#include +#include +#include +#include +#include + +#include "clk-zx.h" + +static struct clk_hw *zx_clk_register_fixed_div(struct device *dev, + const struct zx_fixed_divider_desc *desc, + struct clk_hw * const *clocks) +{ + const struct zx_parent_desc *p = &desc->parent; + + switch (p->type) { + case ZX_PARENT_FW: + return devm_clk_hw_register_fixed_factor_fwname(dev, NULL, desc->name, p->fw_name, + CLK_SET_RATE_PARENT, 1, desc->div); + + case ZX_PARENT_ID: + return devm_clk_hw_register_fixed_factor_parent_hw(dev, desc->name, clocks[p->id], + CLK_SET_RATE_PARENT, 1, + desc->div); + } + WARN_ON_ONCE(1); + return ERR_PTR(-EINVAL); +} + +static int zx_clk_validate(struct device *dev, struct device_node *of_node, + const struct zx_clk_data *data) +{ + const struct zx_parent_desc *parents; + unsigned int i, p, num_parents; + struct clk *clk; + + /* + * Sanity check: Make sure all parents are there and write a clear message rather than + * leave potential orphans. + * + * This check is unusual in clock drivers. It is in this driver because the clock tree is + * based on manual reverse engineering rather than generated from a SoC datasheet. + */ + for (i = 0; i < data->num_clocks; ++i) { + switch (data->clocks[i].type) { + case ZX_CLOCK_PLL: + parents = data->clocks[i].pll.parents; + num_parents = data->clocks[i].pll.num_parents; + break; + + case ZX_CLOCK_FIXED_DIV: + parents = &data->clocks[i].fixed_div.parent; + num_parents = 1; + break; + + case ZX_CLOCK_MUX: + parents = data->clocks[i].mux.parents; + num_parents = data->clocks[i].mux.num_parents; + break; + + case ZX_CLOCK_DIV: + parents = &data->clocks[i].div.parent; + num_parents = 1; + break; + + case ZX_CLOCK_GATE: + parents = &data->clocks[i].gate.parent; + num_parents = 1; + break; + + default: + return dev_err_probe(dev, -EINVAL, "Invalid clock entry %u\n", i); + } + + for (p = 0; p < num_parents; ++p) { + switch (parents[p].type) { + case ZX_PARENT_FW: + clk = of_clk_get_by_name(of_node, parents[p].fw_name); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "Input clk %s failure\n", + parents[p].fw_name); + clk_put(clk); + break; + + case ZX_PARENT_ID: + if (parents[p].id >= i) + return dev_err_probe(dev, -EINVAL, + "Clock %u has parent %u\n", + i, parents[p].id); + break; + + default: + return dev_err_probe(dev, -EINVAL, + "Clock %u has unexpected parent of type %u\n", + i, parents[p].type); + } + } + } + + return 0; +} + +int zx_clk_common_probe(struct device *dev, struct device_node *of_node, + const struct zx_clk_data *data) +{ + struct clk_hw_onecell_data *exports; + struct clk_hw **clocks; + struct regmap *map; + unsigned int i; + int res; + + res = zx_clk_validate(dev, of_node, data); + if (res) + return res; + + map = device_node_to_regmap(of_node); + if (IS_ERR(map)) + return PTR_ERR(map); + + clocks = devm_kcalloc(dev, data->num_clocks, sizeof(*clocks), GFP_KERNEL); + if (!clocks) + return -ENOMEM; + + if (data->init) { + res = data->init(map); + if (res) + return res; + } + + for (i = 0; i < data->num_clocks; ++i) { + struct clk_hw *hw; + + switch (data->clocks[i].type) { + case ZX_CLOCK_PLL: + hw = zx_clk_register_pll(dev, map, &data->clocks[i].pll, clocks); + break; + + case ZX_CLOCK_FIXED_DIV: + hw = zx_clk_register_fixed_div(dev, &data->clocks[i].fixed_div, clocks); + break; + + case ZX_CLOCK_MUX: + hw = zx_clk_register_mux(dev, map, &data->clocks[i].mux, clocks); + break; + + case ZX_CLOCK_DIV: + hw = zx_clk_register_divider(dev, map, &data->clocks[i].div, clocks); + break; + + case ZX_CLOCK_GATE: + hw = zx_clk_register_gate(dev, map, &data->clocks[i].gate, clocks); + break; + + default: + return -EINVAL; + } + + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Failed to register clk %u\n", i); + + clocks[i] = hw; + } + + exports = devm_kzalloc(dev, struct_size(exports, hws, data->num_exports), GFP_KERNEL); + if (!exports) + return -ENOMEM; + exports->num = data->num_exports; + + for (i = 0; i < data->num_exports; ++i) { + if (data->exports[i] >= data->num_clocks) + return dev_err_probe(dev, -EINVAL, + "Export %u points to out of range clock %u\n", + i, data->exports[i]); + + exports->hws[i] = clocks[data->exports[i]]; + } + + devm_kfree(dev, clocks); + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, exports); +} +EXPORT_SYMBOL_NS_GPL(zx_clk_common_probe, "ZTE_CLK"); + +MODULE_AUTHOR("Stefan Dösinger "); +MODULE_DESCRIPTION("ZTE common clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/zte/clk-zx.h b/drivers/clk/zte/clk-zx.h new file mode 100644 index 000000000000..8137185f497f --- /dev/null +++ b/drivers/clk/zte/clk-zx.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 Stefan Dösinger + */ + +#ifndef __DRV_CLK_ZX_H +#define __DRV_CLK_ZX_H + +#include +#include +#include +#include + +#define CLK_ZX_PLL_PREPARE_IS_ENABLE 1 +#define CLK_ZX_MAX_PARENTS 8 + +enum zx_parent_type { + ZX_PARENT_FW, + ZX_PARENT_ID, +}; + +struct zx_parent_desc { + enum zx_parent_type type; + union { + const char *fw_name; + unsigned int id; + }; +}; + +#define PARENT_FW(_name) { .type = ZX_PARENT_FW, .fw_name = (_name) } + +#define PARENT_ID(_id) { .type = ZX_PARENT_ID, .id = (_id) } + +static inline struct clk_parent_data zx_get_parent(const struct zx_parent_desc *p, + struct clk_hw * const *clocks) +{ + struct clk_parent_data ret = {}; + + switch (p->type) { + case ZX_PARENT_FW: + ret.fw_name = p->fw_name; + ret.index = -1; + return ret; + + case ZX_PARENT_ID: + ret.hw = clocks[p->id]; + ret.index = -1; + return ret; + } + + WARN_ON_ONCE(1); + return ret; +} + +struct zx_pll_desc { + const char *name; + const struct zx_parent_desc *parents; + unsigned int num_parents; + unsigned long rate; + u16 reg; + u16 flags; +}; + +struct zx_fixed_divider_desc { + const char *name; + struct zx_parent_desc parent; + unsigned int div; +}; + +struct zx_mux_desc { + const char *name; + const struct zx_parent_desc *parents; + unsigned int num_parents; + u16 reg; + u8 shift, size; +}; + +struct zx_div_desc { + const char *name; + struct zx_parent_desc parent; + u16 reg; + u8 shift, size; +}; + +struct zx_gate_desc { + const char *name; + struct zx_parent_desc parent; + unsigned long flags; + u16 reg; + u8 shift; +}; + +enum zx_clock_type { + ZX_CLOCK_INVALID = 0, + ZX_CLOCK_PLL, + ZX_CLOCK_FIXED_DIV, + ZX_CLOCK_MUX, + ZX_CLOCK_DIV, + ZX_CLOCK_GATE, +}; + +struct zx_clock { + enum zx_clock_type type; + union { + struct zx_pll_desc pll; + struct zx_fixed_divider_desc fixed_div; + struct zx_mux_desc mux; + struct zx_div_desc div; + struct zx_gate_desc gate; + }; +}; + +struct clk_hw *zx_clk_register_pll(struct device *dev, struct regmap *regmap, + const struct zx_pll_desc *desc, + struct clk_hw * const *clocks); +struct clk_hw *zx_clk_register_mux(struct device *dev, struct regmap *regmap, + const struct zx_mux_desc *desc, + struct clk_hw * const *clocks); +struct clk_hw *zx_clk_register_divider(struct device *dev, struct regmap *regmap, + const struct zx_div_desc *desc, + struct clk_hw * const *clocks); +struct clk_hw *zx_clk_register_gate(struct device *dev, struct regmap *regmap, + const struct zx_gate_desc *desc, + struct clk_hw * const *clocks); + +struct zx_clk_data { + int (*init)(struct regmap *map); + const struct zx_clock *clocks; + unsigned int num_clocks; + const unsigned int *exports; + unsigned int num_exports; +}; + +int zx_clk_common_probe(struct device *dev, struct device_node *of_node, + const struct zx_clk_data *data); + +#endif /* __DRV_CLK_ZX_H */ diff --git a/drivers/clk/zte/pll-zx.c b/drivers/clk/zte/pll-zx.c new file mode 100644 index 000000000000..fc76c6524a16 --- /dev/null +++ b/drivers/clk/zte/pll-zx.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan Dösinger + */ + +#include +#include +#include +#include + +#include "clk-zx.h" + +struct clk_hw *zx_clk_register_pll(struct device *dev, struct regmap *regmap, + const struct zx_pll_desc *desc, + struct clk_hw * const *clocks) +{ + return ERR_PTR(-ENODEV); +} From 04b24f1dca694aa73a09102c8a19a766207381ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:35 +0300 Subject: [PATCH 156/168] clk: zte: Add regmap-based clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is based on meson/clk-regmap.c, although slightly simplified. I have kept the copyright lines at the top of the file to indicate its origin. Signed-off-by: Stefan Dösinger Signed-off-by: Brian Masney --- drivers/clk/zte/clk-regmap.c | 223 +++++++++++++++++++++++++++++++++-- 1 file changed, 214 insertions(+), 9 deletions(-) diff --git a/drivers/clk/zte/clk-regmap.c b/drivers/clk/zte/clk-regmap.c index 80332dba97f6..022b2be7bb3d 100644 --- a/drivers/clk/zte/clk-regmap.c +++ b/drivers/clk/zte/clk-regmap.c @@ -1,32 +1,237 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018 BayLibre, SAS. * Copyright (c) 2026 Stefan Dösinger */ +#include #include +#include #include +#include #include #include +#include #include "clk-zx.h" -struct clk_hw *zx_clk_register_gate(struct device *dev, struct regmap *regmap, - const struct zx_gate_desc *desc, - struct clk_hw * const *clocks) +struct zte_clk_regmap { + struct clk_hw hw; + struct regmap *map; + u16 reg; + u8 shift; + u8 size; +}; + +static inline struct zte_clk_regmap *to_zte_clk_regmap(struct clk_hw *hw) { - return ERR_PTR(-ENODEV); + return container_of(hw, struct zte_clk_regmap, hw); } +static int zte_clk_regmap_gate_enable(struct clk_hw *hw) +{ + struct zte_clk_regmap *clk = to_zte_clk_regmap(hw); + + return regmap_set_bits(clk->map, clk->reg, BIT(clk->shift)); +} + +static void zte_clk_regmap_gate_disable(struct clk_hw *hw) +{ + struct zte_clk_regmap *clk = to_zte_clk_regmap(hw); + + regmap_clear_bits(clk->map, clk->reg, BIT(clk->shift)); +} + +static int zte_clk_regmap_gate_is_enabled(struct clk_hw *hw) +{ + struct zte_clk_regmap *clk = to_zte_clk_regmap(hw); + + return regmap_test_bits(clk->map, clk->reg, BIT(clk->shift)); +} + +static const struct clk_ops zte_clk_regmap_gate_ops = { + .enable = zte_clk_regmap_gate_enable, + .disable = zte_clk_regmap_gate_disable, + .is_enabled = zte_clk_regmap_gate_is_enabled, +}; + +struct clk_hw *zx_clk_register_gate(struct device *dev, struct regmap *regmap, + const struct zx_gate_desc *desc, struct clk_hw * const *clocks) +{ + struct clk_parent_data parent = zx_get_parent(&desc->parent, clocks); + struct clk_init_data init = {}; + struct zte_clk_regmap *clk; + int res; + + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return ERR_PTR(-ENOMEM); + + init.name = desc->name; + init.ops = &zte_clk_regmap_gate_ops; + init.parent_data = &parent; + init.num_parents = 1; + init.flags = CLK_SET_RATE_PARENT | desc->flags; + clk->hw.init = &init; + clk->map = regmap; + clk->reg = desc->reg; + clk->shift = desc->shift; + clk->size = 1; + + res = devm_clk_hw_register(dev, &clk->hw); + if (res) + return ERR_PTR(res); + + return &clk->hw; +} + +static unsigned long zte_clk_regmap_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct zte_clk_regmap *clk = to_zte_clk_regmap(hw); + unsigned int val; + int ret; + + ret = regmap_read(clk->map, clk->reg, &val); + if (ret) + return 0; /* Gives a hint that something is wrong */ + + val >>= clk->shift; + val &= clk_div_mask(clk->size); + + return divider_recalc_rate(hw, prate, val, NULL, 0, clk->size); +} + +static int zte_clk_regmap_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct zte_clk_regmap *clk = to_zte_clk_regmap(hw); + + return divider_determine_rate(hw, req, NULL, clk->size, 0); +} + +static int zte_clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct zte_clk_regmap *clk = to_zte_clk_regmap(hw); + unsigned int val; + int ret; + + ret = divider_get_val(rate, parent_rate, NULL, clk->size, 0); + if (ret < 0) + return ret; + + val = (unsigned int)ret << clk->shift; + + return regmap_update_bits(clk->map, clk->reg, clk_div_mask(clk->size) << clk->shift, val); +} + +static const struct clk_ops zte_clk_regmap_divider_ops = { + .recalc_rate = zte_clk_regmap_div_recalc_rate, + .determine_rate = zte_clk_regmap_div_determine_rate, + .set_rate = zte_clk_regmap_div_set_rate, +}; + struct clk_hw *zx_clk_register_divider(struct device *dev, struct regmap *regmap, const struct zx_div_desc *desc, struct clk_hw * const *clocks) { - return ERR_PTR(-ENODEV); + struct clk_parent_data parent = zx_get_parent(&desc->parent, clocks); + struct clk_init_data init = {}; + struct zte_clk_regmap *clk; + int res; + + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return ERR_PTR(-ENOMEM); + + init.name = desc->name; + init.ops = &zte_clk_regmap_divider_ops; + init.parent_data = &parent; + init.num_parents = 1; + init.flags = CLK_SET_RATE_PARENT; + clk->hw.init = &init; + clk->map = regmap; + clk->reg = desc->reg; + clk->shift = desc->shift; + clk->size = desc->size; + + res = devm_clk_hw_register(dev, &clk->hw); + if (res) + return ERR_PTR(res); + + return &clk->hw; } -struct clk_hw *zx_clk_register_mux(struct device *dev, struct regmap *regmap, - const struct zx_mux_desc *desc, - struct clk_hw * const *clocks) +static u8 zte_clk_regmap_mux_get_parent(struct clk_hw *hw) { - return ERR_PTR(-ENODEV); + struct zte_clk_regmap *clk = to_zte_clk_regmap(hw); + unsigned int val; + int ret; + + ret = regmap_read(clk->map, clk->reg, &val); + if (ret) + return 0xff; + + val >>= clk->shift; + val &= GENMASK(clk->size - 1, 0); + + return clk_mux_val_to_index(hw, NULL, 0, val); +} + +static int zte_clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct zte_clk_regmap *clk = to_zte_clk_regmap(hw); + unsigned int val = clk_mux_index_to_val(NULL, 0, index); + + return regmap_update_bits(clk->map, clk->reg, + GENMASK(clk->size - 1, 0) << clk->shift, + val << clk->shift); +} + +static int zte_clk_regmap_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + return clk_mux_determine_rate_flags(hw, req, 0); +} + +static const struct clk_ops zte_clk_regmap_mux_ops = { + .get_parent = zte_clk_regmap_mux_get_parent, + .set_parent = zte_clk_regmap_mux_set_parent, + .determine_rate = zte_clk_regmap_mux_determine_rate, +}; + +struct clk_hw *zx_clk_register_mux(struct device *dev, struct regmap *regmap, + const struct zx_mux_desc *desc, struct clk_hw * const *clocks) +{ + struct clk_parent_data parents[CLK_ZX_MAX_PARENTS]; + struct clk_init_data init = {}; + struct zte_clk_regmap *clk; + unsigned int i; + int res; + + if (WARN_ON(desc->num_parents > ARRAY_SIZE(parents))) + return ERR_PTR(-EINVAL); + + for (i = 0; i < desc->num_parents; ++i) + parents[i] = zx_get_parent(&desc->parents[i], clocks); + + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return ERR_PTR(-ENOMEM); + + init.name = desc->name; + init.ops = &zte_clk_regmap_mux_ops; + init.parent_data = parents; + init.num_parents = desc->num_parents; + clk->hw.init = &init; + clk->map = regmap; + clk->reg = desc->reg; + clk->shift = desc->shift; + clk->size = desc->size; + + res = devm_clk_hw_register(dev, &clk->hw); + if (res) + return ERR_PTR(res); + + return &clk->hw; } From f29a49c216a8fb90afa5d450011a7a3e716f98ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:36 +0300 Subject: [PATCH 157/168] clk: zte: Add zx PLL support infrastructure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds code to decode and program PLL settings on ZTE's zx297520v3 SoC. The PLLs on this SoC are usually programmed to static values by the boot loader. The only situation where .set_rate matters is dpll, which is not programmed in some cases. The bootloader always sets fixed rates though: 624 MHz for mpll, 200 for gpll, 480 for upll. Parsing the bootloader-programmed values allows the clock driver to fill the clock tree with appropriately clocked parent clocks instead of registering fixed clocks with hardcoded rates. I only tested the code on zx297520v3. From looking at the hardcoded PLL values in the old zx296702 / zx296718 code I believe that these PLLs use the same encoding, so the code added by this patch should be reusable and the file has a relatively generic name pll-zx.c. Signed-off-by: Stefan Dösinger Signed-off-by: Brian Masney --- drivers/clk/zte/pll-zx.c | 566 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 562 insertions(+), 4 deletions(-) diff --git a/drivers/clk/zte/pll-zx.c b/drivers/clk/zte/pll-zx.c index fc76c6524a16..d3687495d06c 100644 --- a/drivers/clk/zte/pll-zx.c +++ b/drivers/clk/zte/pll-zx.c @@ -3,16 +3,574 @@ * Copyright (C) 2026 Stefan Dösinger */ +#include #include +#include +#include #include +#include #include +#include +#include #include +#include +#include #include "clk-zx.h" -struct clk_hw *zx_clk_register_pll(struct device *dev, struct regmap *regmap, - const struct zx_pll_desc *desc, - struct clk_hw * const *clocks) +/* + * This code has only been tested with zx297520v3 PLLs, but from reading the zx296718 clock code it + * looks like PLL registers are similar. ZTE's sources explain the PLL register contents only in a + * .cmm file (A Lauterbach TRACE32 script) and some unused headers in their U-Boot code dump, which + * may not be accurate. When calculating the frequencies from the default PLL configuration the + * results match the fixed rate clocks from their clock driver. + * + * The 26 MHz and 32 kHz clocks can be easily observed with the timers. The 104 MHz output can be + * observed through the UART. One 122.88 MHz clock can be observed through the TDM device. All + * others can only be indirectly inferred, e.g. by comparing CPU speed or SDIO transfer rate between + * the fixed 26 MHz oscillator and the provided PLL frequency. + * + * The formula to calculate the clock is ((ref / refdiv) * fbdiv) / postdiv1 / postdiv2. The masks + * are given below. There are a few control flags: + * + * Bit 31: Disables the PLL, but passes clock-26m through unmodified. Whether POSTDIV_OUT_DISABLE + * still matters is different between PLLs. + * Bit 30: Returns if the PLL is locked + * Bit 29: Not named in ZTE's code, but can be set. There is no obvious impact. Lock times are + * unchanged, so it doesn't influence or bypass lock detection. It doesn't raise any IRQs or + * influence GPIOs. + * Bit 27: Given its name it likely disables the Delta-Sigma Modulator, if one exists at all. The + * boot ROM sets it on every PLL. Unsetting it marginally decreases the time it takes to + * lock to the reference clock (from ~400 us to ~300 us). + * Bit 24: Bypasses the VCO, but still applies refdiv and postdiv. Doesn't matter if PLL_DISABLE=1. + * + * NB: Some PLLs have an automatic bypass logic that forwards clock-26m (REGARDLESS of reference) + * when they don't have a lock, regardless of reason. This can be triggered by disabling the PLL, + * setting an out-of-spec VCO frequency or disabling the parent. This shouldn't matter in regular + * operation, but caused me some confusion when reverse engineering the clock tree. E.g. clock-26m-> + * unknownpll(disabled) -> dpll(enabled) counterintuitively results in a 26 MHz output clock. + */ + +#define ZX29_PLL_DISABLE BIT(31) +#define ZX29_PLL_LOCKED BIT(30) +#define ZX29_PLL_LOCK_FILTER BIT(29) +#define ZX29_PLL_DSM_DISABLE BIT(27) +#define ZX29_PLL_PARENT_MASK GENMASK(26, 25) +#define ZX29_PLL_BYPASS BIT(24) +#define ZX29_PLL_REFDIV_MASK GENMASK(23, 18) +#define ZX29_PLL_FBDIV_MASK GENMASK(17, 6) +#define ZX29_PLL_POSTDIV1_MASK GENMASK(5, 3) +#define ZX29_PLL_POSTDIV2_MASK GENMASK(2, 0) + +/* + * The second register has a 24 bit fractional value, which only matters when ZX29_PLL_DSM_DISABLE + * is not set, and only seems to matter for dpll. ZTE's firmware does not make use of the fractional + * and it is unimplemented in this driver. Experimental testing confirms that it has an impact on + * dpll. + * + * Bits 27:24 contain more flags: + * + * Bit 27: Setting ZX29_PLL_DACAP slows down the lock time and obviates the speed gained from + * !DSM_DISABLE. No other effect observed. + * + * Bit 26: ZX29_PLL_4PHASE_OUT_DISABLE is set on some PLLs on boot but not on others. It is set on + * boot on mpll and upll, but not gpll, dpll or unknownpll. I am not sure what it does + * either. The SDIO devices break if they are fed from gpll with this flag set, but they + * work OK if they are fed from mpll without this flag set. + * + * Bit 25: ZX29_PLL_POSTDIV_OUT_DISABLE seems to disable the PLL output entirely. Whether it is + * bypassed by PLL_DISABLE differs between PLLs. gpll still produces an output clock if + * PLL_DISABLE = 1 and POSTDIV_DISABLE = 1, but produces no output if PLL_DISABLE = 0 and + * POSTDIV_DISABLE = 1. The dpll feeder ("unknownpll") at 0x100 produces no output clock if + * both PLL_DISABLE and POSTDIV_DISABLE are set to 1. + * + * Bit 24: ZX29_PLL_VCO_OUT_DISABLE probably disables the output of the VCO clock without + * post-VCO-dividers, but the raw VCO output is not a possible parent of any consumer clock, + * so I could not confirm this. It does not disable the VCO entirely - that's what + * PLL_DISABLE does. + * + * A spinlock should not be needed. PLLs don't share their registers with anything else and the + * global prepare mutex and enable spinlock should be enough. Beware of conflicts in reg2 between + * POSTDIV_OUT_DISABLE and the fractional value in case you find out how fractional dividers work + * and add support for them. + */ +#define ZX29_PLL_REG2_OFFSET 4 +#define ZX29_PLL_DACAP BIT(27) +#define ZX29_PLL_4PHASE_OUT_DISABLE BIT(26) +#define ZX29_PLL_POSTDIV_OUT_DISABLE BIT(25) +#define ZX29_PLL_VCO_OUT_DISABLE BIT(24) +#define ZX29_PLL_FRACT GENMASK(23, 0) + +/* + * The VCO's frequency range is limited. The stock settings run the VCO between 960 and 1248 MHz. + * Ad-hoc testing with gpll suggests that at least this PLL remains stable down to about 7 MHz and + * up to 2 GHz and produces a clock that can be used by the SDIO controller. Attempting to run the + * mpll VCO at 624 MHz and setting postdiv1 = postdiv2 = 1 - which should result in the same output + * frequency - or running it at 1872 MHz with an effective post divider of 3 crashes the CPU. Most + * likely the PLLs become unstable outside their core range and the SDIO controller is much more + * forgiving than CPU and DRAM are. + */ +#define ZX29_PLL_VCO_MAX_FREQ (1300 * HZ_PER_MHZ) +#define ZX29_PLL_VCO_MIN_FREQ (900 * HZ_PER_MHZ) + +struct zx29_clk_pll { + struct clk_hw hw; + struct device *dev; + struct regmap *map; + u16 reg; +}; + +static inline struct zx29_clk_pll *to_zx29_clk_pll(struct clk_hw *hw) { - return ERR_PTR(-ENODEV); + return container_of(hw, struct zx29_clk_pll, hw); +} + +static int zx29_pll_is_prepared(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + int res; + + res = regmap_test_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + if (res < 0) + return res; + + return !res; +} + +static int zx29_pll_prepare(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + u32 val = 0; + int res; + + res = regmap_clear_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + if (res < 0) + return res; + + /* Lock duration is usually between 300 us and 500 us */ + res = regmap_read_poll_timeout(pll->map, pll->reg, val, val & ZX29_PLL_LOCKED, 50, 2000); + if (res) { + regmap_set_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + dev_err(pll->dev, "%s: PLL prepare failed: %d. Config value 0x%08x\n", + clk_hw_get_name(&pll->hw), res, val); + } + return res; +} + +static void zx29_pll_unprepare(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + + regmap_set_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); +} + +static int zx29_pll_is_enabled(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + int res; + + res = regmap_test_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); + if (res < 0) + return res; + + return !res; +} + +static int zx29_pll_enable(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + + return regmap_clear_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); +} + +static void zx29_pll_disable(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + + regmap_set_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); +} + +static unsigned long zx29_pll_get_rate(const struct zx29_clk_pll *pll, unsigned long parent_rate, + u32 setting) +{ + unsigned long refdiv, fbdiv, postdiv1, postdiv2, freq; + const char *name = clk_hw_get_name(&pll->hw); + u64 vco; + + refdiv = FIELD_GET(ZX29_PLL_REFDIV_MASK, setting); + fbdiv = FIELD_GET(ZX29_PLL_FBDIV_MASK, setting); + postdiv1 = FIELD_GET(ZX29_PLL_POSTDIV1_MASK, setting); + postdiv2 = FIELD_GET(ZX29_PLL_POSTDIV2_MASK, setting); + dev_dbg(pll->dev, "%s: reference clock %lu Hz, PLL setting 0x%08x\n", + name, parent_rate, setting); + + if (!refdiv || !postdiv1 || !postdiv2) { + dev_err(pll->dev, "%s: divide by zero (%lu, %lu, %lu)\n", name, refdiv, postdiv1, + postdiv2); + return 0; + } + + vco = div_u64((u64)parent_rate * fbdiv, refdiv); + freq = div_u64(div_u64(vco, postdiv1), postdiv2); + dev_dbg(pll->dev, "%s: refdiv %lu fbdiv %lu\n", name, refdiv, fbdiv); + dev_dbg(pll->dev, "%s: postdiv1 %lu postdiv2 %lu\n", name, postdiv1, postdiv2); + + dev_dbg(pll->dev, "%s: %lu MHz\n", name, freq / HZ_PER_MHZ); + + return freq; +} + +static unsigned long zx29_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + u32 val; + int res; + + res = regmap_read(pll->map, pll->reg, &val); + if (res < 0) { + dev_err(pll->dev, "%s: Failed to read PLL settings\n", clk_hw_get_name(&pll->hw)); + return 0; + } + + return zx29_pll_get_rate(pll, parent_rate, val); +} + +static u32 zx29_pll_calc_values(const struct zx29_clk_pll *pll, unsigned long parent_rate, + unsigned long rate, unsigned long min_rate, unsigned long max_rate) +{ + const unsigned int postdiv1_max = (1 << hweight32(ZX29_PLL_POSTDIV1_MASK)) - 1; + const unsigned int postdiv2_max = (1 << hweight32(ZX29_PLL_POSTDIV2_MASK)) - 1; + unsigned long fbdiv, refdiv, best_fbdiv = 0, best_refdiv = 0; + u32 postdiv1 = 0, postdiv2 = 0, i, j, setting; + const char *name = clk_hw_get_name(&pll->hw); + long best = LONG_MAX; + + /* + * This code produces the same VCO settings that the boot loader and stock firmware use for + * the standard frequencies. It has seen only very little manual testing beyond that. + * + * The goal is to find a VCO setting that gets us as close as possible to the desired output + * rate, while being within the VCO's operating limits and achievable with the input value + * range. It is iterating over possible post-VCO divider values (1-7)*(1-7) to look for + * valid VCO target frequencies and then looks for refdiv and fbdiv values to achieve the + * VCO frequency from the reference frequency. + */ + for (j = 1; j <= postdiv2_max; j++) { + for (i = 1; i <= postdiv1_max; i++) { + u64 vco = (u64)rate * i * j; + unsigned long out; + + if (vco > ZX29_PLL_VCO_MAX_FREQ || vco < ZX29_PLL_VCO_MIN_FREQ) + continue; + + rational_best_approximation(vco, parent_rate, + (1 << hweight32(ZX29_PLL_FBDIV_MASK)) - 1, + (1 << hweight32(ZX29_PLL_REFDIV_MASK)) - 1, + &fbdiv, &refdiv); + setting = FIELD_PREP(ZX29_PLL_FBDIV_MASK, fbdiv); + setting |= FIELD_PREP(ZX29_PLL_REFDIV_MASK, refdiv); + setting |= FIELD_PREP(ZX29_PLL_POSTDIV1_MASK, i); + setting |= FIELD_PREP(ZX29_PLL_POSTDIV2_MASK, j); + out = zx29_pll_get_rate(pll, parent_rate, setting); + + if (out < min_rate || out > max_rate) + continue; + + if (abs_diff(out, rate) > best) + continue; + + if (abs_diff(out, rate) < best) { + postdiv1 = i; + postdiv2 = j; + best_fbdiv = fbdiv; + best_refdiv = refdiv; + best = abs_diff(out, rate); + + if (!best) + goto search_done; + } + } + } +search_done: + + if (!postdiv1) { + dev_err(pll->dev, "Did not find a setting for %lu Hz, parent %lu Hz\n", + rate, parent_rate); + return 0; + } + + dev_dbg(pll->dev, "%s: parent rate %lu\n", name, parent_rate); + dev_dbg(pll->dev, "%s: found VCO dividers %u and %u\n", name, postdiv1, postdiv2); + dev_dbg(pll->dev, "%s: VCO target rate %lu\n", name, rate * postdiv1 * postdiv2); + + dev_dbg(pll->dev, "%s: Got fbdiv = %lu refdiv = %lu\n", name, best_fbdiv, best_refdiv); + + setting = FIELD_PREP(ZX29_PLL_FBDIV_MASK, best_fbdiv); + setting |= FIELD_PREP(ZX29_PLL_REFDIV_MASK, best_refdiv); + setting |= FIELD_PREP(ZX29_PLL_POSTDIV1_MASK, postdiv1); + setting |= FIELD_PREP(ZX29_PLL_POSTDIV2_MASK, postdiv2); + dev_dbg(pll->dev, "%s: Final setting 0x%08x\n", name, setting); + + return setting; +} + +static int zx29_pll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + unsigned long new_rate; + u32 setting; + + /* + * TODO: DPLL can switch between two parents, one of which is another PLL. Take this into + * account when searching the config space and set req->best_parent_rate. + * + * In practice it shouldn't matter though. Dpll is always configured to a fixed frequency + * and is the only clock with a switchable parent. + */ + if (!req->best_parent_rate) { + dev_err(pll->dev, "Did not expect best_parent_rate=0\n"); + return -EINVAL; + } + + setting = zx29_pll_calc_values(pll, req->best_parent_rate, req->rate, req->min_rate, + req->max_rate); + if (!setting) + return -EINVAL; + + new_rate = zx29_pll_get_rate(pll, req->best_parent_rate, setting); + if (new_rate != req->rate) { + dev_dbg(pll->dev, "Did not find an exact match. Want %lu, got %lu\n", + req->rate, new_rate); + req->rate = new_rate; + } + + return 0; +} + +static int zx29_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + u32 setting; + + /* + * TODO: Implement gradual PLL rate change. PLLs can be changed while they are running and + * downstream hardware is generally fine with that. The exception is DRAM, which reads + * incorrect values if changed too fast. + * + * Changing the mpll rate is potentially useful for over/underclocking. Gating mpll is + * unrealistic because too many devices depend on it. + */ + setting = zx29_pll_calc_values(pll, parent_rate, rate, rate, rate); + if (!setting) + return -EINVAL; + + dev_dbg(pll->dev, "%s: Setting new configuration: 0x%08x\n", clk_hw_get_name(hw), setting); + + return regmap_update_bits(pll->map, pll->reg, 0x00ffffff, setting); +} + +static u8 zx29_pll_get_parent(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + u32 val; + int res; + + res = regmap_read(pll->map, pll->reg, &val); + if (res < 0) + return 0xff; + + val = FIELD_GET(ZX29_PLL_PARENT_MASK, val); + dev_dbg(pll->dev, "%s: Parent 0x%x\n", clk_hw_get_name(hw), val); + + return val; +} + +static int zx29_pll_set_parent(struct clk_hw *hw, u8 index) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + u32 parent = FIELD_PREP(ZX29_PLL_PARENT_MASK, index); + int res; + u32 val; + + res = regmap_update_bits(pll->map, pll->reg, ZX29_PLL_PARENT_MASK, parent); + if (res < 0) + return res; + + res = regmap_read(pll->map, pll->reg, &val); + if (res < 0) + return res; + + if ((val & ZX29_PLL_PARENT_MASK) != parent) { + dev_err(pll->dev, "Hardware rejected PLL parent %u\n", index); + return -EINVAL; + } + + return 0; +} + +static int zx29_pll_init(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + const char *name = clk_hw_get_name(hw); + int res; + u32 val; + + dev_dbg(pll->dev, "%s: initializing\n", name); + + /* + * The fractional value is not yet implemented. It works at least with dpll, but I have + * never seen it used on actual hardware. + */ + res = regmap_read(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, &val); + if (res < 0) + return res; + + if (val & ZX29_PLL_FRACT) { + dev_warn(pll->dev, "%s: unsupported nonzero fractional value 0x%08lx\n", + name, val & ZX29_PLL_FRACT); + } + + /* + * Remove the bypass flag so we don't have to bother with it in enable/disable. I have never + * seen it set by the earlier boot stages anyhow. + */ + res = regmap_clear_bits(pll->map, pll->reg, ZX29_PLL_BYPASS); + if (res < 0) + return res; + + res = regmap_test_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + if (res > 0) { + /* + * Set ZX29_PLL_POSTDIV_OUT_DISABLE for PLLs that have ZX29_PLL_DISABLE for + * consistency with .enable and .prepare. This ensures that .prepare doesn't + * inadvertently enable PLLs without .enable being called. + */ + res = regmap_set_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); + } + + return res; +} + +static const struct clk_ops zx29_pll_ops = { + .init = zx29_pll_init, + .is_prepared = zx29_pll_is_prepared, + .prepare = zx29_pll_prepare, + .unprepare = zx29_pll_unprepare, + .is_enabled = zx29_pll_is_enabled, + .enable = zx29_pll_enable, + .disable = zx29_pll_disable, + .recalc_rate = zx29_pll_recalc_rate, + .determine_rate = zx29_pll_determine_rate, + .get_parent = zx29_pll_get_parent, + .set_parent = zx29_pll_set_parent, + .set_rate = zx29_pll_set_rate, +}; + +/* + * A PLL that can be a parent of another PLL needs to produce an output signal when prepared, + * otherwise the downstream PLL's prepare() will fail to acquire a lock. + */ +static int zx29_pll_nodisable_init(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll = to_zx29_clk_pll(hw); + const char *name = clk_hw_get_name(hw); + int res; + u32 val; + + dev_dbg(pll->dev, "%s: initializing, prepare-is-enabled\n", name); + + res = regmap_read(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, &val); + if (res < 0) + return res; + + if (val & ZX29_PLL_FRACT) { + dev_warn(pll->dev, "%s: unsupported nonzero fractional value 0x%08lx\n", + name, val & ZX29_PLL_FRACT); + } + + res = regmap_clear_bits(pll->map, pll->reg, ZX29_PLL_BYPASS); + if (res < 0) + return res; + + return regmap_clear_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); +} + +static const struct clk_ops zx29_pll_nodisable_ops = { + .init = zx29_pll_nodisable_init, + .is_prepared = zx29_pll_is_prepared, + .prepare = zx29_pll_prepare, + .unprepare = zx29_pll_unprepare, + .recalc_rate = zx29_pll_recalc_rate, + .determine_rate = zx29_pll_determine_rate, + .get_parent = zx29_pll_get_parent, + .set_parent = zx29_pll_set_parent, + .set_rate = zx29_pll_set_rate, +}; + +struct clk_hw *zx_clk_register_pll(struct device *dev, struct regmap *regmap, + const struct zx_pll_desc *desc, struct clk_hw * const *clocks) +{ + struct clk_parent_data parents[CLK_ZX_MAX_PARENTS]; + struct clk_init_data init = {}; + struct zx29_clk_pll *pll; + unsigned int i; + int res; + + pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + if (desc->flags & CLK_ZX_PLL_PREPARE_IS_ENABLE) + init.ops = &zx29_pll_nodisable_ops; + else + init.ops = &zx29_pll_ops; + + if (WARN_ON(desc->num_parents > ARRAY_SIZE(parents))) + return ERR_PTR(-EINVAL); + + for (i = 0; i < desc->num_parents; ++i) + parents[i] = zx_get_parent(&desc->parents[i], clocks); + + init.name = desc->name; + init.parent_data = parents; + init.num_parents = desc->num_parents; + + /* + * Disallow live reparent, but allow rate changes. PLLs can handle gradual changes fine, but + * large ones cause a temporary incorrect output, which can break downstream devices. + * See zx29_pll_set_rate for considerations on that. + */ + init.flags = CLK_SET_PARENT_GATE; + pll->hw.init = &init; + pll->dev = dev; + pll->map = regmap; + pll->reg = desc->reg; + + res = devm_clk_hw_register(dev, &pll->hw); + if (res) + return ERR_PTR(res); + + /* + * Set the PLL rate only if the bootloader left it disabled. Keep the bootloader setup + * otherwise. + */ + res = regmap_test_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + if (res < 0) + return ERR_PTR(res); + + if (res > 0 && desc->rate) { + dev_dbg(pll->dev, "%s: setting to %lu Hz\n", desc->name, desc->rate); + res = clk_set_rate(pll->hw.clk, desc->rate); + if (res) + return ERR_PTR(dev_err_probe(dev, res, "%s: failed to set rate\n", + desc->name)); + } + + return &pll->hw; } From 913e9c3b026975e01615a8e00ac773ed1790ef47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:37 +0300 Subject: [PATCH 158/168] clk: zte: Introduce a driver for zx297520v3 top clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This register space controls core devices: PLLs, the AHB bus, a lot of timers, the USB controller, the Cortex M0 processor that boots the board and a few other devices. For some reason the LTE coprocessor is also partially controlled by it. The main application processor and DDR memory are not found here though. The register to reboot the board is found here, as well as a register to control whether watchdog expiries cause a board reset. Signed-off-by: Stefan Dösinger Signed-off-by: Brian Masney --- drivers/clk/zte/Kconfig | 11 + drivers/clk/zte/Makefile | 1 + drivers/clk/zte/clk-zx297520v3.c | 846 +++++++++++++++++++++++++++++++ 3 files changed, 858 insertions(+) create mode 100644 drivers/clk/zte/clk-zx297520v3.c diff --git a/drivers/clk/zte/Kconfig b/drivers/clk/zte/Kconfig index 152c2423b8f0..0ccc6edf3c5b 100644 --- a/drivers/clk/zte/Kconfig +++ b/drivers/clk/zte/Kconfig @@ -15,3 +15,14 @@ config COMMON_CLK_ZTE of this. Enable this if you are building a kernel for a ZTE designed board. + +config CLK_ZTE_ZX297520V3 + tristate "Clock driver for ZTE zx297520v3 based SoCs" + depends on COMMON_CLK_ZTE && (MFD_ZTE_ZX297520V3_CRM || COMPILE_TEST) + default SOC_ZX297520V3 + help + This driver supports ZTE zx297520v3 basic clocks. + + Enable this if you want to build a kernel that is able to run on + boards based on this SoC. You can safely enable multiple clock + drivers. The one(s) matching the device tree will be used. diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile index 27db07293165..2c073512e919 100644 --- a/drivers/clk/zte/Makefile +++ b/drivers/clk/zte/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_COMMON_CLK_ZTE) += clk-zte.o +obj-$(CONFIG_CLK_ZTE_ZX297520V3) += clk-zx297520v3.o clk-zte-y += clk-zx.o pll-zx.o clk-regmap.o diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx297520v3.c new file mode 100644 index 000000000000..68bfeab84d74 --- /dev/null +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -0,0 +1,846 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan Dösinger + * + * There are no public datasheets for zx297520v3. The controls on this clock controller have been + * extracted from ZTE's kernel and U-Boot sources and a LOT of manual testing. Some clocks can be + * found in the power management (evb_cpurpm.img) and LTE (cpko.ko) blobs shipped with the routers. + * + * Because ZTE's sources are wrong or misleading in some parts and testing can be misinterpreted, + * this file contains a LOT of comments on how particular clocks were tested and how the impact of + * changes to them can be observed. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk-zx.h" + +MODULE_IMPORT_NS("ZTE_CLK"); + +/* + * AXI speed is either determined by a fixed selection in matrix+0x0, bits 0:2 or by a voting system + * with ballots in matrix+0x120, 0x124, 0x128. The voting system is enabled by setting matrix 0x12c + * to 1. Otherwise the selection in 0x0 applies. + * + * The fastest selected speed wins. This holds true for values 0 (26 MHz) and 7 (6.5 MHz) too, so it + * isn't a case of lowest selector wins. I haven't tested what happens if mpll is changed to output + * 5x the normal clock, so 7 beats 0. Presumably value 0 would still win the election. + * + * AXI speed 6.5 is a child of matrix-osc26m, not a PLL. This can be seen by gating it off in + * topcrm+0x140. + * + * The system initializes with voting disabled and all preferences set to the lowest setting, 7. + * The zx297520v3_matrix_init function transfers the global mux to our vote and enables voting. + * + * Because rprocs may change their selection without notice, all possible parents of the AXI mux are + * marked critical. This can however obscure bugs in the clock tree. Define ZX297520V3_AXI_CANDIDATE + * to 0 to disable this protection for testing and either not run anything on the rprocs or make + * sure Linux votes for the fastest rate. + */ +#define ZX297520V3_AXI_CANDIDATE CLK_IS_CRITICAL + +/* + * Top and matrix clocks are chaotic - I haven't found a consistent pattern behind their register + * and bit locations. Generally there are two gates (pclk, wclk), one mux, two resets and sometimes + * one divider, but exceptions apply. For some devices there is only a reset and some general + * (parent) clocks need setup. This structure plus macro handles the somewhat regular parts. + * + * There are some patterns that can be observed. + * mux 0x3c, div 0x48, gate 0x54 + * mux 0x40, div 0x4c, gate 0x5c + * mux 0x44, div 0x50, gate 0x60 + * + * For a 0 - 0xc - 0x18 pattern. Muxes from 0x3c to 0x44, dividers from 0x48 to 0x50, gates 0x54 to + * 0x60. The pattern is broken for timer t17 though. + * + * Gates have 4 bits per clock - usually, but not always, bit 0 for wclk, bit 1 for pclk, bit 2 for + * something the ZTE kernel calls "gate" (the bits we use here are called "en"), which presumably + * enables automatic clock gating. Bit 3, if settable, seems unused. E.g. offset 0x54 accepts all + * bits in 0xF77F7F7F - suggesting RTC, I2C0 have an extra gate bit. + * + * The default mpll settings multiply the 26 MHz reference clock times 24. A mux selection of 26 MHz + * could mean using the 26 MHz oscillator directly, or passing it through the PLL and divide by 24. + * + * If a UART is set to mpll-d6 (default 104 MHz), changing the mpll multipliers does affect UART + * timing as it should. This does not happen when the UART is set to 26 MHz input or timers that + * read 26 MHz input. This suggests 26 MHz clocks use the reference clock directly. + * + * The general clock flow on this board goes from osc26m into the PLLs. The PLL output is + * branched into a small number of divided frequencies (mpll, mpll-d4, mpll-d5, mpll-d6, mpll-d8, + * gpll, gpll-d2, gpll-d4) at a high level. These divided frequencies as well as osc26m go + * through a series of gates at offset 0x140 in topcrm. The output of these gates provide wclks for + * everything. + * + * At least 3 of those gate outputs (mpll, dpll, gpll-d2) are further divided behind those gates, + * presumably in the matrix controller. There are multiple paths how 104 and 78 MHz are derived, + * some specific to topcrm (0x140 bits 1 and 4), some specific to matrix (0x140 bit 9). There are + * likely 3 "copies" of the 78 MHz clock and two 50 MHz ones. + * + * Pclk is not gated by the 0x140 gates at all. Likewise osc32k is fed to the timers without + * passing through this gate, even for consumers on matrix/LSP. Topcrm osc26m wclks are not gated + * either, but top-consumed PLL clocks are. + */ + +enum top_clock_ids { + ZX_CLK_MPLL, + ZX_CLK_UPLL, + ZX_CLK_DPLL2, + ZX_CLK_DPLL2_D2, + ZX_CLK_DPLL, + ZX_CLK_GPLL, + + ZX_CLK_OSC26M_D2, + ZX_CLK_TOP_MPLL_D2_PREGATE, + ZX_CLK_TOP_MPLL_D4_PREGATE, + ZX_CLK_TOP_MPLL_D5_PREGATE, + ZX_CLK_TOP_MPLL_D6_PREGATE, + ZX_CLK_TOP_MPLL_D8_PREGATE, + ZX_CLK_TOP_UPLL_D12_PREGATE, + ZX_CLK_TOP_GPLL_D2_PREGATE, + ZX_CLK_TOP_GPLL_D4_PREGATE, + + ZX_CLK_TOP_MPLL_D2, + ZX_CLK_TOP_MPLL_D8, + ZX_CLK_TOP_MPLL_D6, + ZX_CLK_TOP_MPLL_D4, + ZX_CLK_TOMATRIX_MPLL_D5, + ZX_CLK_TOMATRIX_MPLL, + ZX_CLK_TOMATRIX_DPLL, + ZX_CLK_TOP_UPLL_D12, + ZX_CLK_TOP_UPLL, + ZX_CLK_TOP_GPLL_D4, + ZX_CLK_TOMATRIX_GPLL_D2, + ZX_CLK_TOMATRIX_GPLL, + ZX_CLK_TOMATRIX_OSC26M, + + ZX_CLK_TOP_MPLL_D2_D4, + ZX_CLK_TOP_MPLL_D2_D13, + ZX_CLK_TOP_UPLL_D12_D2, + ZX_CLK_TOP_GPLL_D4_D2, + + ZX_CLK_M0_MUX, + ZX_CLK_AHB_MUX, + ZX_CLK_TIMER_T08_MUX, + ZX_CLK_TIMER_T09_MUX, + ZX_CLK_TIMER_T12_MUX, + ZX_CLK_TIMER_T13_MUX, + ZX_CLK_TIMER_T14_MUX, + ZX_CLK_TIMER_T15_MUX, + ZX_CLK_TIMER_T16_MUX, + ZX_CLK_TIMER_T17_MUX, + ZX_CLK_WDT_T18_MUX, + ZX_CLK_I2C0_MUX, + ZX_CLK_UART0_MUX, + ZX_CLK_OUT0_MUX, + ZX_CLK_OUT1_MUX, + ZX_CLK_OUT2_MUX, + ZX_CLK_RMIIPHY_MUX, + + ZX_CLK_TIMER_T08_DIV, + ZX_CLK_TIMER_T09_DIV, + ZX_CLK_TIMER_T12_DIV, + ZX_CLK_TIMER_T13_DIV, + ZX_CLK_TIMER_T14_DIV, + ZX_CLK_TIMER_T15_DIV, + ZX_CLK_TIMER_T16_DIV, + ZX_CLK_TIMER_T17_DIV, + ZX_CLK_WDT_T18_DIV, + ZX_CLK_USIM1_DIV, + + ZX_CLK_AHB_PCLK, + ZX_CLK_AHB_WCLK, + ZX_CLK_SRAM1_PCLK, + ZX_CLK_SRAM2_PCLK, + ZX_CLK_PMM_WCLK, + ZX_CLK_PMM_PCLK, + ZX_CLK_TIMER_T08_WCLK, + ZX_CLK_TIMER_T08_PCLK, + ZX_CLK_TIMER_T09_WCLK, + ZX_CLK_TIMER_T09_PCLK, + ZX_CLK_TIMER_T12_WCLK, + ZX_CLK_TIMER_T12_PCLK, + ZX_CLK_TIMER_T13_WCLK, + ZX_CLK_TIMER_T13_PCLK, + ZX_CLK_TIMER_T14_WCLK, + ZX_CLK_TIMER_T14_PCLK, + ZX_CLK_TIMER_T15_WCLK, + ZX_CLK_TIMER_T15_PCLK, + ZX_CLK_TIMER_T16_WCLK, + ZX_CLK_TIMER_T16_PCLK, + ZX_CLK_TIMER_T17_WCLK, + ZX_CLK_TIMER_T17_PCLK, + ZX_CLK_WDT_T18_WCLK, + ZX_CLK_WDT_T18_PCLK, + ZX_CLK_I2C0_WCLK, + ZX_CLK_I2C0_PCLK, + ZX_CLK_UART0_WCLK, + ZX_CLK_UART0_PCLK, + ZX_CLK_USB_WCLK, + ZX_CLK_USB_PCLK, + ZX_CLK_HSIC_WCLK, + ZX_CLK_HSIC_PCLK, + ZX_CLK_RTC_WCLK, + ZX_CLK_RTC_PCLK, + ZX_CLK_USIM1_WCLK, + ZX_CLK_USIM1_PCLK, + ZX_CLK_LPM_GSM_WCLK, + ZX_CLK_LPM_GSM_PCLK, + ZX_CLK_LPM_LTE_WCLK, + ZX_CLK_LPM_LTE_PCLK, + ZX_CLK_LPM_TD_WCLK, + ZX_CLK_LPM_TD_PCLK, + ZX_CLK_LPM_W_WCLK, + ZX_CLK_LPM_W_PCLK, + ZX_CLK_OUT0_WCLK, + ZX_CLK_OUT1_WCLK, + ZX_CLK_OUT2_WCLK, + ZX_CLK_OUT32K_WCLK, + ZX_CLK_RMIIPHY_WCLK, + ZX_CLK_GSM_32K, + ZX_CLK_GSM_26M, + ZX_CLK_GSM_48M, + ZX_CLK_GSM_104M, + ZX_CLK_GSM_156M, + ZX_CLK_ABB_WCLK, +}; + +/* Used for gates where we don't know the parent input(s). Assume general oscillator */ +static const struct zx_parent_desc clk_unknown = PARENT_FW("osc26m"); + +/* For clocks that are known to use the ungated osc26m input */ +static const struct zx_parent_desc clk_main[] = { + PARENT_FW("osc26m"), +}; + +static const struct zx_parent_desc dpll_parents[] = { + PARENT_ID(ZX_CLK_DPLL2_D2), + PARENT_FW("osc26m"), +}; + +/* + * AHB: The clock mux works and impact can be tested e.g. with iperf speed testing of the USB + * network connection. Values 2 and 3 give the same speed and depend on the same bit (3) in 0x140. + * The mpll-d6 rate is gated off by the same bit in 0x140 as m0's mpll-d6, but the d8 is different. + * This may indicate that one of the two uses a different clock rate than documented in ZTE's + * kernel. The M0 speed is easy to measure, so I am confident in the M0's 78 MHz rate. AHB looks + * like 78 rather than 52, but confidence is lower because RAM read tests are influenced by CPU + * overhead too. + */ + +static const struct zx_parent_desc ahb_sel[] = { + PARENT_FW("osc26m"), + PARENT_ID(ZX_CLK_TOP_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_TOP_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_TOP_MPLL_D8), /* 78 MHz */ +}; + +static const struct zx_parent_desc timer_top_sel[] = { + PARENT_FW("osc32k"), + PARENT_FW("osc26m"), +}; + +static const struct zx_parent_desc uart_top_sel[] = { + PARENT_FW("osc26m"), + PARENT_ID(ZX_CLK_TOP_MPLL_D6), /* 104 MHz, sharing M0's and ahb's 0x140 gate */ +}; + +/* + * The Cortex M0 coprocessor. It is responsible for booting the board and runs some power management + * helper code on the stock firmware. The M0 rproc itself is not critical, but most of topcrm's + * registers become unreadable if this is gated off or become slow when clocked at 32 kHz, e.g. GPIO + * becomes borderline unusable at 32 kHz. + * + * There is no dedicated M0 gate. Disabling ahb-wclk looks like the M0 stops from A53's point of + * view, but it merely breaks the A53's ability to communicate with it, and M0's ability to + * communicate with the standard UART on LSP. M0 keeps running with both ahb-wclk and ahb-pclk + * gated off and can re-enable the gates. + */ +static const struct zx_parent_desc m0_sel[] = { + PARENT_FW("osc26m"), + PARENT_ID(ZX_CLK_TOP_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_TOP_MPLL_D2_D4), /* 78 MHz, but different gate than the ahb 78 MHz */ + PARENT_FW("osc32k"), /* Yes, tested. It is SLLLLOOOOOWWW. */ +}; + +/* + * Clk-out0/1/2/32k: These clocks are exposed on GPIOs 15, 16, 17 and 18 respectively. They are used + * in ZTE's camera and sound code, by directly poking into the clock registers from the device + * drivers. Until the respective devices are supported they can safely be switched off. + * + * For clk-out1 ZTE's camera code says the following: + * + * 0 -> 20 MHz + * 1 -> 40 MHz + * 2 -> 13 MHz + * 3 -> 26 MHz + * + * 0 and 1 read from upll. I confirmed their rates (upll-d24 and upll-d12) by setting upll to a very + * low frequency and sampling the clock by GPIO reads. The outputs of 2 and 3 are way too high to + * test that way. Neither is reading from any PLL, they keep oscillating when all PLLs are disabled. + * I am fairly sure that 3 is just direct osc26m because it perfectly matches what out2 is + * showing in its 26 MHz setting. + * + * Clk-out2 is similar, but it has only one control bit in top 0x34 bit 8. Neither setting selects + * a PLL output. When setting *0x34 = 0x080, clk-out1 and clk-out2 are in lockstep, presumably + * running at 13 MHz. 0x1c0 also runs in lockstep, presumably 26 MHz. + * + * clk-out0 has a mux in bit 5. Value 0 most likely selects osc26m. I am not entirely sure about + * value 1 (which is the default), but the m0 mux has an impact on it. It looks like a debug pin + * that exposes some core clock. + */ +static const struct zx_parent_desc out0_sel[] = { + PARENT_FW("osc26m"), + PARENT_ID(ZX_CLK_M0_MUX), +}; + +static const struct zx_parent_desc out1_sel[] = { + PARENT_ID(ZX_CLK_TOP_UPLL_D12_D2), /* 20 MHz */ + PARENT_ID(ZX_CLK_TOP_UPLL_D12), /* 40 MHz */ + PARENT_ID(ZX_CLK_OSC26M_D2), /* 13 MHz */ + PARENT_FW("osc26m"), +}; + +static const struct zx_parent_desc out2_sel[] = { + PARENT_ID(ZX_CLK_OSC26M_D2), /* 13 MHz */ + PARENT_FW("osc26m"), +}; + +/* + * Clk-o is similar to clk-out*, providing a clock on GPIO 20, presumably for driving a (R)MII phy. + * The 50 MHz value is documented in a stray comment in ZTE's GMAC driver. I tested it similarly to + * the above pins. Mux setting 0 gives half the count as setting 1 and setting 1 gives gpll divided + * by 4 - matching the 50 MHz suggested by the ZTE comment at the default gpll settings. Gating gpll + * stops the clock for values 0 and 1. + * + * Settings 2 and 3 are possible, but seem to return garbage. It is generally pulsing up and down, + * except if both gpll and upll are stopped. I suspect it just reads random electrical fluctuation + * from other places in the board. Yes, I had a pull-down enabled when testing this. + * + * I am not aware of any board that uses this though. The Ethernet-equipped ones I have all run the + * PHY with its own oscillator. + */ +static const struct zx_parent_desc rmii_sel[] = { + PARENT_ID(ZX_CLK_TOP_GPLL_D4_D2), /* 25 MHz */ + PARENT_ID(ZX_CLK_TOP_GPLL_D4), /* 50 MHz */ +}; + +#define PLL(_name, _parents, _rate, _reg, _flags) \ + { \ + .type = ZX_CLOCK_PLL, \ + .pll = { \ + .name = _name, \ + .parents = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .rate = _rate, \ + .reg = _reg, \ + .flags = _flags, \ + }, \ + } + +#define FIXED_DIV(_name, _parent, _div) \ + { \ + .type = ZX_CLOCK_FIXED_DIV, \ + .fixed_div = { \ + .name = _name, \ + .parent = _parent, \ + .div = _div, \ + }, \ + } + +#define MUX(_name, _parents, _reg, _shift, _size) \ + { \ + .type = ZX_CLOCK_MUX, \ + .mux = { \ + .name = _name, \ + .parents = _parents, \ + .num_parents = ARRAY_SIZE(_parents), \ + .reg = _reg, \ + .shift = _shift, \ + .size = _size, \ + }, \ + } + +#define DIV(_name, _parent, _reg, _shift, _size) \ + { \ + .type = ZX_CLOCK_DIV, \ + .div = { \ + .name = _name, \ + .parent = _parent, \ + .reg = _reg, \ + .shift = _shift, \ + .size = _size, \ + }, \ + } + +#define GATE(_name, _parent, _reg, _shift, _flags) \ + { \ + .type = ZX_CLOCK_GATE, \ + .gate = { \ + .name = _name, \ + .parent = _parent, \ + .reg = _reg, \ + .flags = _flags, \ + .shift = _shift, \ + }, \ + } + +static const struct zx_clock zx297520v3_top_clocks[] = { + /* + * Default setting: 0x48040c11. 624/312/156. Only a single possible parent. This is the + * PLL for pretty much everything, including CPU, RAM and USB. + * + * Changing this PLL makes it possible to overclock the CPU or do more fine grained + * underclocking than the CPU's mux allows. It does run into two problems though: The USB + * device uses this PLL's output directly and is *very* sensitive to differences. DRAM + * is also fed by this clock and needs to be re-trained on larger changes, which needs to + * be done by the stage 1 boot loader. + */ + [ZX_CLK_MPLL] = PLL("mpll", clk_main, 0, 0x8, 0), + + /* + * ZTE's code calls this PLL "upll". The only possible consumers I found are clk-out1, + * which outputs this clock on GPIO 16 and HSIC. HSIC doesn't have anything connected to + * it on the devices I tested. The device that consumes clk-out1 seems to be an SPI + * camera, which I haven't seen in any device so far. ZTE manipulates this PLL directly out + * of the camera code, so it is unlikely to have another consumer. + * + * Long story short, shut it off. + */ + [ZX_CLK_UPLL] = PLL("upll", clk_main, 0, 0x10, 0), + + /* + * Default value 0x4834902d. Feeds dpll. 46.08 MHz. Bit 25 can be set, so two parents are + * possible. It looks like both values select the 26 MHz oscillator though. + * + * Since dpll's prepare may depend on this clock generating a usable signal, it needs to be + * enabled when prepared. + * + * It isn't named anywhere in ZTE's code, but cpko.ko has the string "dpll2" somewhere in + * its clock tables. + */ + [ZX_CLK_DPLL2] = PLL("dpll2", clk_main, 0, 0x100, CLK_ZX_PLL_PREPARE_IS_ENABLE), + [ZX_CLK_DPLL2_D2] = FIXED_DIV("dpll2-d2", PARENT_ID(ZX_CLK_DPLL2), 2), + + /* + * The documentation says 491.52 MHz and measurement with the LSP TDM device supports this. + * The default value is 0x480c2011, but not all boot loaders set it up. To get to 491.52 + * with these settings it needs a 23.04 MHz reference clock, which matches dpll2-d2. If + * dpll2 is disabled, dpll loses its lock. We set the frequency on this PLL if we find it is + * not prepared by the boot loader. + * + * The proprietary LTE driver and/or rproc prepare and unprepare it. TDM and I2S can use it. + * + * It accepts parent values 0, 1, 2 and 3. Parent 0 is dpll2-d2. The others look like + * osc26m. With a parent != 0 dpll never loses its lock even when all other PLLs are off + * and the TDM counter register increases at a rate consistent with a 26.0/23.04 clock + * increase. + */ + [ZX_CLK_DPLL] = PLL("dpll", dpll_parents, 491520000, 0x18, 0), + + /* + * "g" is either for "general" or "gigahertz". The VCO runs at 1 GHz. Output clocks are 200, + * 100, 50, 25, ... MHz. It is used optionally by SDIO and QSPI and can drive a GPIO clock + * output for RMII, so it doesn't seem very general. + */ + [ZX_CLK_GPLL] = PLL("gpll", clk_main, 0, 0x110, 0), + + /* osc26m division for clk_outX */ + [ZX_CLK_OSC26M_D2] = FIXED_DIV("osc26m-d2", clk_main[0], 2), + + /* Pre-0x140 distribution fixed divs */ + [ZX_CLK_TOP_MPLL_D2_PREGATE] = FIXED_DIV("mpll-d2", PARENT_ID(ZX_CLK_MPLL), 2), + [ZX_CLK_TOP_MPLL_D4_PREGATE] = FIXED_DIV("mpll-d4", PARENT_ID(ZX_CLK_MPLL), 4), + [ZX_CLK_TOP_MPLL_D5_PREGATE] = FIXED_DIV("mpll-d5", PARENT_ID(ZX_CLK_MPLL), 5), + [ZX_CLK_TOP_MPLL_D6_PREGATE] = FIXED_DIV("mpll-d6", PARENT_ID(ZX_CLK_MPLL), 6), + [ZX_CLK_TOP_MPLL_D8_PREGATE] = FIXED_DIV("mpll-d8", PARENT_ID(ZX_CLK_MPLL), 8), + [ZX_CLK_TOP_UPLL_D12_PREGATE] = FIXED_DIV("upll-d12", PARENT_ID(ZX_CLK_UPLL), 12), + [ZX_CLK_TOP_GPLL_D2_PREGATE] = FIXED_DIV("gpll-d2", PARENT_ID(ZX_CLK_GPLL), 2), + [ZX_CLK_TOP_GPLL_D4_PREGATE] = FIXED_DIV("gpll-d4", PARENT_ID(ZX_CLK_GPLL), 4), + + /* + * topcrm distribution gates. These are complicated, but shed a lot of light on the board's + * clock distribution. + * + * Settable mask: 0x017333FF. Generally one nibble per PLL, except for MPLL that has more. + * One for osc26m work clock. pclk and osc32k are not gated globally here or anywhere else + * as far as I can see. + * + * If you want to test your understanding of this board, try to manually configure it into a + * setup where bit 24 or bit 9 are off without crashing it. + */ + + /* Bit 0: No known consumer */ + /* Bit 1: M0's 78 MHz selection, but somehow also involved in USB too */ + [ZX_CLK_TOP_MPLL_D2] = GATE("top-mpll-d2", PARENT_ID(ZX_CLK_TOP_MPLL_D2_PREGATE), + 0x140, 1, 0), + /* Bit 2: No known consumer, named "mpll_48m_clk" in ZTE's cpko.ko blob */ + [ZX_CLK_TOP_MPLL_D8] = GATE("top-mpll-d8", PARENT_ID(ZX_CLK_TOP_MPLL_D8_PREGATE), + 0x140, 3, 0), + [ZX_CLK_TOP_MPLL_D6] = GATE("top-mpll-d6", PARENT_ID(ZX_CLK_TOP_MPLL_D6_PREGATE), + 0x140, 4, 0), + [ZX_CLK_TOP_MPLL_D4] = GATE("top-mpll-d4", PARENT_ID(ZX_CLK_TOP_MPLL_D4_PREGATE), + 0x140, 5, 0), + [ZX_CLK_TOMATRIX_MPLL_D5] = GATE("matrix-mpll-d5", PARENT_ID(ZX_CLK_TOP_MPLL_D5_PREGATE), + 0x140, 6, ZX297520V3_AXI_CANDIDATE), + /* Bit 7: No known consumer */ + /* Bit 8: Has a consumer, LTE depends on it. But unknown what and how. */ + /* + * Bit 9: Big MPLL provider for Matrix. It is an AXI voting candidate, but it is protected + * in Matrix's 0x118 gates. + */ + [ZX_CLK_TOMATRIX_MPLL] = GATE("matrix-mpll", PARENT_ID(ZX_CLK_MPLL), 0x140, 9, 0), + /* Bit 10: Always 0 */ + /* Bit 11: Always 0 */ + + /* Bit 12: No known consumer. Existing patterns indicate a dpll consumer in top itself */ + [ZX_CLK_TOMATRIX_DPLL] = GATE("matrix-dpll", PARENT_ID(ZX_CLK_DPLL), 0x140, 13, 0), + /* Bit 14: Always 0 */ + /* Bit 15: Always 0 */ + + [ZX_CLK_TOP_UPLL_D12] = GATE("top-upll-d12", PARENT_ID(ZX_CLK_TOP_UPLL_D12_PREGATE), + 0x140, 16, 0), + [ZX_CLK_TOP_UPLL] = GATE("top-upll", PARENT_ID(ZX_CLK_UPLL), 0x140, 17, 0), + /* Bit 18: Always 0 */ + /* Bit 19: Always 0 */ + + [ZX_CLK_TOP_GPLL_D4] = GATE("top-gpll-d4", PARENT_ID(ZX_CLK_TOP_GPLL_D4_PREGATE), + 0x140, 20, 0), + [ZX_CLK_TOMATRIX_GPLL_D2] = GATE("matrix-gpll-d2", PARENT_ID(ZX_CLK_TOP_GPLL_D2_PREGATE), + 0x140, 21, 0), + [ZX_CLK_TOMATRIX_GPLL] = GATE("matrix-gpll", PARENT_ID(ZX_CLK_GPLL), 0x140, 22, 0), + /* Bit 23: Always 0 */ + + /* + * Bit 24 covers all 26 MHz on matrix, but not pclks. Osc26m consumers on topcrm do not + * use this, they get the ungated osc26m. It is an AXI voting candidate, but does not + * need protection because it is the slowest speed. It will only be used if every processor, + * including us, votes for it. + */ + [ZX_CLK_TOMATRIX_OSC26M] = GATE("matrix-osc26m", clk_main[0], 0x140, 24, 0), + + /* + * Post-140 divisions. They enter through the same bit and can be selected by different mux + * values of their consumers or get piped to multiple consumers with different documented + * rates - in particular, USB wclk (24 MHz according to ZTE) shares bit 1 with M0's 78 MHz. + */ + [ZX_CLK_TOP_MPLL_D2_D4] = FIXED_DIV("top-mpll-d2-d4", PARENT_ID(ZX_CLK_TOP_MPLL_D2), 4), + [ZX_CLK_TOP_MPLL_D2_D13] = FIXED_DIV("top-mpll-d2-d13", PARENT_ID(ZX_CLK_TOP_MPLL_D2), + 13), + [ZX_CLK_TOP_UPLL_D12_D2] = FIXED_DIV("top-upll-d12-d2", PARENT_ID(ZX_CLK_TOP_UPLL_D12), + 2), + [ZX_CLK_TOP_GPLL_D4_D2] = FIXED_DIV("top-gpll-d4-d2", PARENT_ID(ZX_CLK_TOP_GPLL_D4), 2), + + /* Device-specific Muxes */ + [ZX_CLK_M0_MUX] = MUX("m0-mux", m0_sel, 0x38, 0, 2), + [ZX_CLK_AHB_MUX] = MUX("ahb-mux", ahb_sel, 0x3c, 4, 2), + [ZX_CLK_TIMER_T08_MUX] = MUX("timer-t08-mux", timer_top_sel, 0x40, 1, 1), + [ZX_CLK_TIMER_T09_MUX] = MUX("timer-t09-mux", timer_top_sel, 0x40, 0, 1), + [ZX_CLK_TIMER_T12_MUX] = MUX("timer-t12-mux", timer_top_sel, 0x3c, 0, 1), + [ZX_CLK_TIMER_T13_MUX] = MUX("timer-t13-mux", timer_top_sel, 0x44, 0, 1), + [ZX_CLK_TIMER_T14_MUX] = MUX("timer-t14-mux", timer_top_sel, 0x44, 1, 1), + [ZX_CLK_TIMER_T15_MUX] = MUX("timer-t15-mux", timer_top_sel, 0x3c, 3, 1), + [ZX_CLK_TIMER_T16_MUX] = MUX("timer-t16-mux", timer_top_sel, 0x44, 2, 1), + [ZX_CLK_TIMER_T17_MUX] = MUX("timer-t17-mux", timer_top_sel, 0x120, 0, 1), + [ZX_CLK_WDT_T18_MUX] = MUX("wdt-t18-mux", timer_top_sel, 0x3c, 6, 1), + [ZX_CLK_I2C0_MUX] = MUX("i2c0-mux", uart_top_sel, 0x3c, 1, 1), + [ZX_CLK_UART0_MUX] = MUX("uart0-mux", uart_top_sel, 0x40, 2, 1), + [ZX_CLK_OUT0_MUX] = MUX("out0-mux", out0_sel, 0x34, 5, 1), + [ZX_CLK_OUT1_MUX] = MUX("out1-mux", out1_sel, 0x34, 6, 2), + [ZX_CLK_OUT2_MUX] = MUX("out2-mux", out2_sel, 0x34, 8, 1), + [ZX_CLK_RMIIPHY_MUX] = MUX("rmiiphy-mux", rmii_sel, 0x11c, 0, 2), + + /* Device-specific dividers */ + [ZX_CLK_TIMER_T08_DIV] = DIV("timer-t08-div", PARENT_ID(ZX_CLK_TIMER_T08_MUX), + 0x4c, 8, 4), + [ZX_CLK_TIMER_T09_DIV] = DIV("timer-t09-div", PARENT_ID(ZX_CLK_TIMER_T09_MUX), + 0x4c, 0, 4), + [ZX_CLK_TIMER_T12_DIV] = DIV("timer-t12-div", PARENT_ID(ZX_CLK_TIMER_T12_MUX), + 0x48, 0, 4), + [ZX_CLK_TIMER_T13_DIV] = DIV("timer-t13-div", PARENT_ID(ZX_CLK_TIMER_T13_MUX), + 0x50, 0, 4), + [ZX_CLK_TIMER_T14_DIV] = DIV("timer-t14-div", PARENT_ID(ZX_CLK_TIMER_T14_MUX), + 0x50, 4, 4), + [ZX_CLK_TIMER_T15_DIV] = DIV("timer-t15-div", PARENT_ID(ZX_CLK_TIMER_T15_MUX), + 0x48, 4, 4), + [ZX_CLK_TIMER_T16_DIV] = DIV("timer-t16-div", PARENT_ID(ZX_CLK_TIMER_T16_MUX), + 0x50, 8, 4), + [ZX_CLK_TIMER_T17_DIV] = DIV("timer-t17-div", PARENT_ID(ZX_CLK_TIMER_T17_MUX), + 0x124, 0, 4), + [ZX_CLK_WDT_T18_DIV] = DIV("wdt-t18-div", PARENT_ID(ZX_CLK_WDT_T18_MUX), + 0x48, 8, 4), + [ZX_CLK_USIM1_DIV] = DIV("usim1-div", clk_unknown, + 0x48, 12, 1), + + /* Device specific gates */ + + /* + * AHB clock gates: Disabling these cuts off the A53 from register access into 0x130000/ + * 0x140000, including the topcrm region, so it can't be re-enabled. Mark them critical for + * that reason. + * + * Gating this off does not stop the M0 rproc, nor does it stop M0 from accessing topcrm. It + * does however gate off M0 from the AXI interconnect, so it can't read RAM, Matrix, etc. So + * these bits here merely gate the bus, not the actual devices. + */ + [ZX_CLK_AHB_PCLK] = GATE("ahb-pclk", PARENT_ID(ZX_CLK_AHB_MUX), 0x54, 12, + CLK_IS_CRITICAL), + [ZX_CLK_AHB_WCLK] = GATE("ahb-wclk", PARENT_ID(ZX_CLK_M0_MUX), 0x54, 13, + CLK_IS_CRITICAL), + + /* SRAM1 and 2 clocks. Leave them on for now, as turning them off carelessly hangs the M0 */ + [ZX_CLK_SRAM1_PCLK] = GATE("sram1-pclk", clk_main[0], 0x54, 18, CLK_IS_CRITICAL), + [ZX_CLK_SRAM2_PCLK] = GATE("sram2-pclk", clk_main[0], 0x54, 16, CLK_IS_CRITICAL), + + /* + * Pinmux (AON, TOP, IOCFG but not PDCFG). Critical as well until we have a driver that + * consumes it. I don't think we'll realistically shut this off ever. + * + * Setting either bit 0 or 1 in register 0x58 makes the device work. + */ + [ZX_CLK_PMM_WCLK] = GATE("pmm-wclk", clk_main[0], 0x58, 0, CLK_IS_CRITICAL), + [ZX_CLK_PMM_PCLK] = GATE("pmm-pclk", clk_main[0], 0x58, 1, CLK_IS_CRITICAL), + + /* + * Timers. We don't use any of them, just shut them off. The timers are named and sorted + * by the IO address of the main timer controls. Some of the controls are documented in + * ZTE's kernel, the others I found by trial and error. Timers in register 0x54 have the + * pclk first, the others have the wclk first. + * + * Timer T17 is used by the ZSP firmware. The rproc driver will enable it as needed. + */ + [ZX_CLK_TIMER_T08_WCLK] = GATE("timer-t08-wclk", PARENT_ID(ZX_CLK_TIMER_T08_DIV), + 0x5c, 8, 0), + [ZX_CLK_TIMER_T08_PCLK] = GATE("timer-t08-pclk", clk_main[0], 0x5c, 9, 0), + [ZX_CLK_TIMER_T09_WCLK] = GATE("timer-t09-wclk", PARENT_ID(ZX_CLK_TIMER_T09_DIV), + 0x5c, 4, 0), + [ZX_CLK_TIMER_T09_PCLK] = GATE("timer-t09-pclk", clk_main[0], 0x5c, 5, 0), + [ZX_CLK_TIMER_T12_WCLK] = GATE("timer-t12-wclk", PARENT_ID(ZX_CLK_TIMER_T12_DIV), + 0x54, 5, 0), + [ZX_CLK_TIMER_T12_PCLK] = GATE("timer-t12-pclk", clk_main[0], 0x54, 4, 0), + [ZX_CLK_TIMER_T13_WCLK] = GATE("timer-t13-wclk", PARENT_ID(ZX_CLK_TIMER_T13_DIV), + 0x60, 0, 0), + [ZX_CLK_TIMER_T13_PCLK] = GATE("timer-t13-pclk", clk_main[0], 0x60, 1, 0), + [ZX_CLK_TIMER_T14_WCLK] = GATE("timer-t14-wclk", PARENT_ID(ZX_CLK_TIMER_T14_DIV), + 0x60, 4, 0), + [ZX_CLK_TIMER_T14_PCLK] = GATE("timer-t14-pclk", clk_main[0], 0x60, 5, 0), + [ZX_CLK_TIMER_T15_WCLK] = GATE("timer-t15-wclk", PARENT_ID(ZX_CLK_TIMER_T15_DIV), + 0x54, 21, 0), + [ZX_CLK_TIMER_T15_PCLK] = GATE("timer-t15-pclk", clk_main[0], 0x54, 20, 0), + [ZX_CLK_TIMER_T16_WCLK] = GATE("timer-t16-wclk", PARENT_ID(ZX_CLK_TIMER_T16_DIV), + 0x60, 8, 0), + [ZX_CLK_TIMER_T16_PCLK] = GATE("timer-t16-pclk", clk_main[0], 0x60, 9, 0), + [ZX_CLK_TIMER_T17_WCLK] = GATE("timer-t17-wclk", PARENT_ID(ZX_CLK_TIMER_T17_DIV), + 0x128, 0, 0), + [ZX_CLK_TIMER_T17_PCLK] = GATE("timer-t17-pclk", clk_main[0], 0x128, 1, 0), + + /* + * This watchdog is set up by ZTE's bootloader and in ZTE's OS the m0 firmware will feed the + * dog. The m0 firmware in turn wants to be fed in its own way. Since we normally don't run + * any m0 firmware we shut it off by default and expose it to userspace via the watchdog + * driver. + */ + [ZX_CLK_WDT_T18_WCLK] = GATE("wdt-t18-wclk", PARENT_ID(ZX_CLK_WDT_T18_DIV), + 0x54, 25, 0), + [ZX_CLK_WDT_T18_PCLK] = GATE("wdt-t18-pclk", clk_main[0], 0x54, 24, 0), + + [ZX_CLK_I2C0_WCLK] = GATE("i2c0-wclk", PARENT_ID(ZX_CLK_I2C0_MUX), 0x54, 9, 0), + [ZX_CLK_I2C0_PCLK] = GATE("i2c0-pclk", clk_main[0], 0x54, 8, 0), + [ZX_CLK_UART0_WCLK] = GATE("uart0-wclk", PARENT_ID(ZX_CLK_UART0_MUX), 0x5c, 12, 0), + [ZX_CLK_UART0_PCLK] = GATE("uart0-pclk", clk_main[0], 0x5c, 13, 0), + + /* + * ZTE says the USB input is a 24 MHz clock based on mpll. Testing shows that upll is not + * involved. The USB register space can be accessed with ahb-pclk gated, but not with + * ahb-wclk gated. ZTE also lists ahb-wclk as parent for the second clock. + * + * There doesn't seem to be a separate PHY clock. usb-wclk stops controller registers from + * updating, but doesn't cause the USB device to disconnect like asserting the PHY reset + * does. Bit 0 in this register can't be set, so no PHY clock is hiding there either. + */ + [ZX_CLK_USB_WCLK] = GATE("usb-wclk", PARENT_ID(ZX_CLK_TOP_MPLL_D2_D13), 0x6c, 3, 0), + [ZX_CLK_USB_PCLK] = GATE("usb-pclk", PARENT_ID(ZX_CLK_AHB_WCLK), 0x6c, 4, 0), + /* + * The HSIC hardware is listed in ZTE's code with a physical address of 0x01600000. Unlike + * the USB controller, it does consume upll. ZTE says 240 MHz, but 480 is the usual one for + * HSIC. + */ + [ZX_CLK_HSIC_WCLK] = GATE("hsic-wclk", PARENT_ID(ZX_CLK_TOP_UPLL), 0x6c, 1, 0), + [ZX_CLK_HSIC_PCLK] = GATE("hsic-pclk", PARENT_ID(ZX_CLK_AHB_WCLK), 0x6c, 2, 0), + + /* + * How does this RTC work? I don't know, the ZTE kernel does not talk to it. The actual RTC + * is on the I2C-connected PMIC. + */ + [ZX_CLK_RTC_WCLK] = GATE("rtc-wclk", clk_unknown, 0x54, 1, 0), + [ZX_CLK_RTC_PCLK] = GATE("rtc-pclk", clk_main[0], 0x54, 0, 0), + + [ZX_CLK_USIM1_WCLK] = GATE("usim1-wclk", PARENT_ID(ZX_CLK_USIM1_DIV), 0x54, 29, 0), + [ZX_CLK_USIM1_PCLK] = GATE("usim1-pclk", clk_main[0], 0x54, 28, 0), + + /* + * LTE: gate only as far as I can see. I looked for resets and did not find any. There may + * be mux/div, but without understanding the behavior of this hardware it is impossible to + * tell. They are sorted by physical MMIO address of the devices, which happens to be the + * inverse order of the bits. + * + * Like PMM in this register, either bit enables register access, whether they control pclk + * or wclk cannot be distinguished. + * + * The work parent of GSM, TD and W is without doubt osc26m. The mmio space has registers + * that count up at an integer fraction of 26000000. Gating PLLs does not affect them, + * including gating mpll. + * + * LPM_LTE has some interaction with LTE_MODEM_WCLK. If LTE_MODEM_WCLK is disabled, LPM_LTE + * stops counting, and just flips between two states. This makes it look like LPM_LTE in + * topcrm has a clock parent in matrixcrm, which wouldn't make much sense. I think this + * behavior is a result of the devices interacting rather than a clock parentage. + * + * As for what these devices do? I am not sure. They generate a lot of IRQs, but the IRQs + * are independent of actual radio activity. The ZSP firmware programs them + */ + [ZX_CLK_LPM_GSM_WCLK] = GATE("lpm-gsm-wclk", clk_main[0], 0x58, 10, 0), + [ZX_CLK_LPM_GSM_PCLK] = GATE("lpm-gsm-pclk", clk_main[0], 0x58, 11, 0), + [ZX_CLK_LPM_LTE_WCLK] = GATE("lpm-lte-wclk", clk_unknown, 0x58, 8, 0), + [ZX_CLK_LPM_LTE_PCLK] = GATE("lpm-lte-pclk", clk_main[0], 0x58, 9, 0), + [ZX_CLK_LPM_TD_WCLK] = GATE("lpm-td-wclk", clk_main[0], 0x58, 6, 0), + [ZX_CLK_LPM_TD_PCLK] = GATE("lpm-td-pclk", clk_main[0], 0x58, 7, 0), + [ZX_CLK_LPM_W_WCLK] = GATE("lpm-w-wclk", clk_main[0], 0x58, 4, 0), + [ZX_CLK_LPM_W_PCLK] = GATE("lpm-w-pclk", clk_main[0], 0x58, 5, 0), + + [ZX_CLK_OUT0_WCLK] = GATE("out0-wclk", PARENT_ID(ZX_CLK_OUT0_MUX), 0x34, 0, 0), + [ZX_CLK_OUT1_WCLK] = GATE("out1-wclk", PARENT_ID(ZX_CLK_OUT1_MUX), 0x90, 2, 0), + [ZX_CLK_OUT2_WCLK] = GATE("out2-wclk", PARENT_ID(ZX_CLK_OUT2_MUX), 0x94, 2, 0), + [ZX_CLK_OUT32K_WCLK] = GATE("out32k-wclk", PARENT_FW("osc32k"), 0x34, 1, 0), + [ZX_CLK_RMIIPHY_WCLK] = GATE("rmiiphy-wclk", PARENT_ID(ZX_CLK_RMIIPHY_MUX), + 0x11c, 2, 0), + + /* + * GSM clocks - they feed the 2G/3G radio components and SIM controller. + * + * The names are from the clock table in cpko.ko. The parents of gsm-104m and gsm-156m are + * experimentally verified. The gsm-48m parent is likely bit 2 in topcrm+0x140. I have not + * found an consumer that I understand well enough to say if it is running or not, so I have + * not been able to confirm this yet. + */ + [ZX_CLK_GSM_32K] = GATE("gsm-32k", PARENT_FW("osc32k"), 0x68, 0, 0), + [ZX_CLK_GSM_26M] = GATE("gsm-26m", PARENT_FW("osc26m"), 0x68, 1, 0), + [ZX_CLK_GSM_48M] = GATE("gsm-48m", clk_unknown, 0x68, 2, 0), + [ZX_CLK_GSM_104M] = GATE("gsm-104m", PARENT_ID(ZX_CLK_TOP_MPLL_D6), 0x68, 3, 0), + [ZX_CLK_GSM_156M] = GATE("gsm-156m", PARENT_ID(ZX_CLK_TOP_MPLL_D4), 0x68, 4, 0), + + /* Analog Baseband, probably. cpko.ko enables it for LTE, and LTE scans come back empty + * without it. The MMIO location of the device is unknown. It is likely connected only to + * ZSP and inaccessible to the main CPU. + */ + [ZX_CLK_ABB_WCLK] = GATE("abb-wclk", clk_unknown, 0x144, 1, 0), +}; + +static const unsigned int zx297520v3_top_exports[] = { + [ZX297520V3_M0_WCLK] = ZX_CLK_M0_MUX, + [ZX297520V3_SRAM1_PCLK] = ZX_CLK_SRAM1_PCLK, + [ZX297520V3_SRAM2_PCLK] = ZX_CLK_SRAM2_PCLK, + [ZX297520V3_UART0_WCLK] = ZX_CLK_UART0_WCLK, + [ZX297520V3_UART0_PCLK] = ZX_CLK_UART0_PCLK, + [ZX297520V3_I2C0_WCLK] = ZX_CLK_I2C0_WCLK, + [ZX297520V3_I2C0_PCLK] = ZX_CLK_I2C0_PCLK, + [ZX297520V3_RTC_WCLK] = ZX_CLK_RTC_WCLK, + [ZX297520V3_RTC_PCLK] = ZX_CLK_RTC_PCLK, + [ZX297520V3_LPM_GSM_WCLK] = ZX_CLK_LPM_GSM_WCLK, + [ZX297520V3_LPM_GSM_PCLK] = ZX_CLK_LPM_GSM_PCLK, + [ZX297520V3_LPM_LTE_WCLK] = ZX_CLK_LPM_LTE_WCLK, + [ZX297520V3_LPM_LTE_PCLK] = ZX_CLK_LPM_LTE_PCLK, + [ZX297520V3_LPM_TD_WCLK] = ZX_CLK_LPM_TD_WCLK, + [ZX297520V3_LPM_TD_PCLK] = ZX_CLK_LPM_TD_PCLK, + [ZX297520V3_LPM_W_WCLK] = ZX_CLK_LPM_W_WCLK, + [ZX297520V3_LPM_W_PCLK] = ZX_CLK_LPM_W_PCLK, + [ZX297520V3_TIMER_T08_WCLK] = ZX_CLK_TIMER_T08_WCLK, + [ZX297520V3_TIMER_T08_PCLK] = ZX_CLK_TIMER_T08_PCLK, + [ZX297520V3_TIMER_T09_WCLK] = ZX_CLK_TIMER_T09_WCLK, + [ZX297520V3_TIMER_T09_PCLK] = ZX_CLK_TIMER_T09_PCLK, + [ZX297520V3_MPLL] = ZX_CLK_TOMATRIX_MPLL, + [ZX297520V3_MPLL_D5] = ZX_CLK_TOMATRIX_MPLL_D5, + [ZX297520V3_DPLL] = ZX_CLK_TOMATRIX_DPLL, + [ZX297520V3_GPLL] = ZX_CLK_TOMATRIX_GPLL, + [ZX297520V3_GPLL_D2] = ZX_CLK_TOMATRIX_GPLL_D2, + [ZX297520V3_GATED_OSC26M] = ZX_CLK_TOMATRIX_OSC26M, + [ZX297520V3_PMM_WCLK] = ZX_CLK_PMM_WCLK, + [ZX297520V3_PMM_PCLK] = ZX_CLK_PMM_PCLK, + [ZX297520V3_OUT0_WCLK] = ZX_CLK_OUT0_WCLK, + [ZX297520V3_OUT1_WCLK] = ZX_CLK_OUT1_WCLK, + [ZX297520V3_OUT2_WCLK] = ZX_CLK_OUT2_WCLK, + [ZX297520V3_OUT32K_WCLK] = ZX_CLK_OUT32K_WCLK, + [ZX297520V3_RMIIPHY_WCLK] = ZX_CLK_RMIIPHY_WCLK, + [ZX297520V3_TIMER_T12_WCLK] = ZX_CLK_TIMER_T12_WCLK, + [ZX297520V3_TIMER_T12_PCLK] = ZX_CLK_TIMER_T12_PCLK, + [ZX297520V3_TIMER_T13_WCLK] = ZX_CLK_TIMER_T13_WCLK, + [ZX297520V3_TIMER_T13_PCLK] = ZX_CLK_TIMER_T13_PCLK, + [ZX297520V3_TIMER_T14_WCLK] = ZX_CLK_TIMER_T14_WCLK, + [ZX297520V3_TIMER_T14_PCLK] = ZX_CLK_TIMER_T14_PCLK, + [ZX297520V3_TIMER_T15_WCLK] = ZX_CLK_TIMER_T15_WCLK, + [ZX297520V3_TIMER_T15_PCLK] = ZX_CLK_TIMER_T15_PCLK, + [ZX297520V3_TIMER_T16_WCLK] = ZX_CLK_TIMER_T16_WCLK, + [ZX297520V3_TIMER_T16_PCLK] = ZX_CLK_TIMER_T16_PCLK, + [ZX297520V3_TIMER_T17_WCLK] = ZX_CLK_TIMER_T17_WCLK, + [ZX297520V3_TIMER_T17_PCLK] = ZX_CLK_TIMER_T17_PCLK, + [ZX297520V3_WDT_T18_WCLK] = ZX_CLK_WDT_T18_WCLK, + [ZX297520V3_WDT_T18_PCLK] = ZX_CLK_WDT_T18_PCLK, + [ZX297520V3_USIM1_WCLK] = ZX_CLK_USIM1_WCLK, + [ZX297520V3_USIM1_PCLK] = ZX_CLK_USIM1_PCLK, + [ZX297520V3_AHB_WCLK] = ZX_CLK_AHB_WCLK, + [ZX297520V3_AHB_PCLK] = ZX_CLK_AHB_PCLK, + [ZX297520V3_USB_WCLK] = ZX_CLK_USB_WCLK, + [ZX297520V3_USB_PCLK] = ZX_CLK_USB_PCLK, + [ZX297520V3_HSIC_WCLK] = ZX_CLK_HSIC_WCLK, + [ZX297520V3_HSIC_PCLK] = ZX_CLK_HSIC_PCLK, + [ZX297520V3_GSM_32K] = ZX_CLK_GSM_32K, + [ZX297520V3_GSM_26M] = ZX_CLK_GSM_26M, + [ZX297520V3_GSM_48M] = ZX_CLK_GSM_48M, + [ZX297520V3_GSM_104M] = ZX_CLK_GSM_104M, + [ZX297520V3_GSM_156M] = ZX_CLK_GSM_156M, + [ZX297520V3_ABB_WCLK] = ZX_CLK_ABB_WCLK, +}; + +static const struct zx_clk_data zx297520v3_topclk_data = { + .clocks = zx297520v3_top_clocks, + .num_clocks = ARRAY_SIZE(zx297520v3_top_clocks), + .exports = zx297520v3_top_exports, + .num_exports = ARRAY_SIZE(zx297520v3_top_exports), +}; + +static int clk_zx297520v3_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + + if (!id) + return -ENODEV; + + return zx_clk_common_probe(&pdev->dev, pdev->dev.parent->of_node, + (const struct zx_clk_data *)id->driver_data); +} + +static const struct platform_device_id clk_zx297520v3_ids[] = { + { + .name = "zx297520v3-topclk", + .driver_data = (kernel_ulong_t)&zx297520v3_topclk_data, + }, + { } +}; +MODULE_DEVICE_TABLE(platform, clk_zx297520v3_ids); + +static struct platform_driver clk_zx297520v3 = { + .probe = clk_zx297520v3_probe, + .driver = { + .name = "clk-zx297520v3", + }, + .id_table = clk_zx297520v3_ids, +}; +module_platform_driver(clk_zx297520v3); + +MODULE_AUTHOR("Stefan Dösinger "); +MODULE_DESCRIPTION("ZTE zx297520v3 clock driver"); +MODULE_LICENSE("GPL"); From 0d852cd2ae8cd6e79e5dde0c274c8281b1e62a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:38 +0300 Subject: [PATCH 159/168] clk: zte: Introduce a driver for zx297520v3 matrix clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This clock controller controls high speed devices: CPU, DMA, RAM, SDIO, Ethernet. The only non-clock, non-reset registers I have spotted here are hardware spinlocks. Signed-off-by: Stefan Dösinger Signed-off-by: Brian Masney --- drivers/clk/zte/clk-zx297520v3.c | 526 +++++++++++++++++++++++++++++++ 1 file changed, 526 insertions(+) diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx297520v3.c index 68bfeab84d74..d5f8bc4064bd 100644 --- a/drivers/clk/zte/clk-zx297520v3.c +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -812,6 +812,528 @@ static const struct zx_clk_data zx297520v3_topclk_data = { .num_exports = ARRAY_SIZE(zx297520v3_top_exports), }; +enum matrix_clock_ids { + ZX_CLK_MATRIX_OSC26M_D4, + ZX_CLK_MATRIX_MPLL_D2_PREGATE, + ZX_CLK_MATRIX_MPLL_D4_PREGATE, + ZX_CLK_MATRIX_MPLL_D6_PREGATE, + ZX_CLK_MATRIX_MPLL_D8_PREGATE, + ZX_CLK_MATRIX_MPLL_D12_PREGATE, + ZX_CLK_MATRIX_MPLL_D16_PREGATE, + ZX_CLK_MATRIX_GPLL_D2_D2_PREGATE, + ZX_CLK_MATRIX_GPLL_D2_D4_PREGATE, + ZX_CLK_MATRIX_DPLL_D2_PREGATE, + ZX_CLK_MATRIX_DPLL_D4_PREGATE, + + ZX_CLK_MATRIX_MPLL_D16, + ZX_CLK_MATRIX_MPLL_D12, + ZX_CLK_MATRIX_MPLL_D8, + ZX_CLK_MATRIX_MPLL_D6, + ZX_CLK_MATRIX_MPLL_D4, + ZX_CLK_MATRIX_MPLL_D2, + ZX_CLK_MATRIX_DPLL_D4, + ZX_CLK_MATRIX_DPLL_D2, + ZX_CLK_MATRIX_GPLL_D2_D4, + ZX_CLK_MATRIX_GPLL_D2_D2, + + ZX_CLK_CPU_MUX, + ZX_CLK_ZSP_MUX, + ZX_CLK_DDR_CTRL_MUX, + ZX_CLK_SD0_MUX, + ZX_CLK_SD1_MUX, + ZX_CLK_NAND_MUX, + ZX_CLK_EDCP_MUX, + ZX_CLK_TDM_MUX, + ZX_CLK_AXI_MUX, + + ZX_CLK_SYS_TIMER_WCLK, + ZX_CLK_CPU_WCLK, + ZX_CLK_CPU_PCLK, + ZX_CLK_ZSP_WCLK, + ZX_CLK_ZSP_PCLK, + ZX_CLK_DDR_CTRL_PCLK, + ZX_CLK_DDR_CTRL_WCLK, + ZX_CLK_SD0_PCLK, + ZX_CLK_SD0_WCLK, + ZX_CLK_SD0_CDET, + ZX_CLK_SD1_PCLK, + ZX_CLK_SD1_WCLK, + ZX_CLK_SD1_CDET, + ZX_CLK_NAND_WCLK, + ZX_CLK_NAND_PCLK, + ZX_CLK_LTE_MODEM_WCLK, + ZX_CLK_LTE_MODEM_PCLK, + ZX_CLK_EDCP_PCLK, + ZX_CLK_EDCP_WCLK, + ZX_CLK_RFFE_WCLK, + ZX_CLK_SSC_WCLK, + ZX_CLK_SSC_PCLK, + ZX_CLK_PDCFG_WCLK, + ZX_CLK_PDCFG_PCLK, + ZX_CLK_MBOX_PCLK, + ZX_CLK_SRAM0_PCLK, + ZX_CLK_GSM_CFG_PCLK, + ZX_CLK_GMAC_WCLK, + ZX_CLK_GMAC_PCLK, + ZX_CLK_GMAC_AHB, + ZX_CLK_AXI_WCLK, + ZX_CLK_DMA_PCLK, + ZX_CLK_VOU_WCLK, + ZX_CLK_VOU_PCLK, + ZX_CLK_TOLSP_MPLL_D5_WCLK, + ZX_CLK_TOLSP_MPLL_D4_WCLK, + ZX_CLK_TOLSP_MPLL_D6_WCLK, + ZX_CLK_TOLSP_MPLL_D8_WCLK, + ZX_CLK_TOLSP_MPLL_D12_WCLK, + ZX_CLK_TOLSP_OSC26M_WCLK, + ZX_CLK_TOLSP_OSC32K_WCLK, + ZX_CLK_TOLSP_PCLK, + ZX_CLK_TOLSP_TDM_WCLK, + ZX_CLK_TOLSP_DPLL_D4_WCLK, +}; + +/* + * For devices which have a working driver the work clock can be figured out by gating off registers + * in topcrm+0x140. This is used for devices where I can't interpret the register contents yet. + */ +static const struct zx_parent_desc matrix_unk = PARENT_FW("wclk-osc26m"); + +static const struct zx_parent_desc cpu_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_FW("mpll"), /* 624 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D2), /* 312 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ +}; + +/* + * Figuring these values out is a bit tricky. The best liveness check of the ZSP is reading its TCM + * at 0x81000000. If it is clocked up and out of reset reading it will succeed. Otherwise, reading + * will stall. Value 1 depends on topcrm+0x140, bit 13, but not any matrixcrm+0x118 gate, so it is + * likely dpll without a div. Mux value 2 depends on 0x118 bit 5, so mpll-d2. Mux value 3 depends on + * 0x118 bit 4, so mpll-d4. Mux value 0 in turn depends on topcrm+0x140, bit 24 (osc26m), so it + * follows the usual pattern that mux 0 is osc26m. + * + * If the firmware is running and fed with initialization data it will start writing status messages + * on UART1. An interruption of these messages or a failure to respond to rpmsg is not proof that + * the ZSP's clock has been disabled. The firmware's workings depend on regular timer and LTE device + * IRQs, so one of these devices might have been stopped instead. + */ +static const struct zx_parent_desc zsp_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_FW("dpll"), /* 491.52 MHz, boot default */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D2), /* 312 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ +}; + +/* + * We can't realistically change DDR speed while running an OS out of DDR (it reads garbage for a + * short while on transition), but we need to know if we have to keep gpll alive. 32 MB devices use + * 200 MHz, while 64/128 MB ones use 156 MHz. + */ +static const struct zx_parent_desc ddr_ctrl_sel[] = { + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("gpll"), /* 200 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ +}; + +static const struct zx_parent_desc sd0_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("gpll-d2"), /* 100 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D2), /* 50 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D4), /* 25 MHz */ +}; + +static const struct zx_parent_desc sd1_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_FW("gpll-d2"), /* 100 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D2), /* 50 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D16), /* 39 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D4), /* 25 MHz */ +}; + +/* + * ZTE's kernel puts the high frequency first, but this is against the usual convention on this SoC. + * I don't have any device that has a raw NAND controller though. + */ +static const struct zx_parent_desc nand_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ +}; + +static const struct zx_parent_desc edcp_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("mpll-d5"), /* 124.8 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ +}; + +/* + * The 122.88 MHz selection of value 1 is given in ZTE's kernel and matches up to observation: Print + * the TDM counter at regular intervals and look at its increase at values 0/1/2. It increases by + * about 310*26 for value 0, 310*122.88 for value 1 and 310*104 for value 2. + * + * Mux value 1 is gated off by matrix+0x118 bit 8. Values 2 and 3 are both gated off by 0x118 bit 3, + * suggesting that they select the same parent. + */ +static const struct zx_parent_desc tdm_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_DPLL_D4), /* 122.88 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), +}; + +/* + * ZTE's firmware uses 0x128 as the PHY's vote and names 0x120 as "PS" and 0x124 as "AP" vote. + * However, their cpufreq driver ultimately uses the "PS" define and thus writes to 0x120, which can + * be observed in the running system. + */ +#define ZX297520V3_AXI_AP_VOTE 0x120 +static const struct zx_parent_desc axi_sel[] = { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("mpll-d5"), /* 124.8 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D12), /* 52 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D16), /* 39 MHz */ + PARENT_ID(ZX_CLK_MATRIX_OSC26M_D4), /* 6.5 MHz */ +}; + +static const struct zx_clock zx297520v3_matrix_clocks[] = { + [ZX_CLK_MATRIX_OSC26M_D4] = FIXED_DIV("matrix-osc26m-d4", PARENT_FW("wclk-osc26m"), 4), + [ZX_CLK_MATRIX_MPLL_D2_PREGATE] = FIXED_DIV("matrix-mpll-d2-pregate", PARENT_FW("mpll"), 2), + [ZX_CLK_MATRIX_MPLL_D4_PREGATE] = FIXED_DIV("matrix-mpll-d4-pregate", PARENT_FW("mpll"), 4), + /* div 5: provided as a separate line from topcrm */ + [ZX_CLK_MATRIX_MPLL_D6_PREGATE] = FIXED_DIV("matrix-mpll-d6-pregate", PARENT_FW("mpll"), 6), + [ZX_CLK_MATRIX_MPLL_D8_PREGATE] = FIXED_DIV("matrix-mpll-d8-pregate", PARENT_FW("mpll"), 8), + [ZX_CLK_MATRIX_MPLL_D12_PREGATE] = FIXED_DIV("matrix-mpll-d12-pregate", PARENT_FW("mpll"), + 12), + [ZX_CLK_MATRIX_MPLL_D16_PREGATE] = FIXED_DIV("matrix-mpll-d16-pregate", PARENT_FW("mpll"), + 16), + + [ZX_CLK_MATRIX_GPLL_D2_D2_PREGATE] = FIXED_DIV("matrix-gpll-d2-d2-pregate", + PARENT_FW("gpll-d2"), 2), + [ZX_CLK_MATRIX_GPLL_D2_D4_PREGATE] = FIXED_DIV("matrix-gpll-d2-d4-pregate", + PARENT_FW("gpll-d2"), 4), + + [ZX_CLK_MATRIX_DPLL_D2_PREGATE] = FIXED_DIV("matrix-dpll-d2-pregate", PARENT_FW("dpll"), 2), + [ZX_CLK_MATRIX_DPLL_D4_PREGATE] = FIXED_DIV("matrix-dpll-d4-pregate", PARENT_FW("dpll"), 4), + + /* + * Matrix distribution gates: Every matrix-generated subdivision of the input PLLs + * has a gate in 0x118. The original inputs from topcrm (mpll 624, mpll 124.8, gpll 200, + * gpll 100, dpll 491.52) do not. + * + * Bit 8 is consumed by TDM and the frequency dpll/4 holds up to observation. Bit 9 is + * consumed by an unknown device and the frequency is guessed from the pattern that lower + * bits gate lower frequencies. + */ + [ZX_CLK_MATRIX_MPLL_D16] = GATE("matrix-mpll-d16", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D16_PREGATE), 0x118, 0, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D12] = GATE("matrix-mpll-d12", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D12_PREGATE), 0x118, 1, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D8] = GATE("matrix-mpll-d8", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8_PREGATE), 0x118, 2, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D6] = GATE("matrix-mpll-d6", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6_PREGATE), 0x118, 3, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D4] = GATE("matrix-mpll-d4", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4_PREGATE), 0x118, 4, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D2] = GATE("matrix-mpll-d2", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D2_PREGATE), 0x118, 5, 0), + + [ZX_CLK_MATRIX_DPLL_D4] = GATE("matrix-dpll-d4", + PARENT_ID(ZX_CLK_MATRIX_DPLL_D4_PREGATE), 0x118, 8, 0), + [ZX_CLK_MATRIX_DPLL_D2] = GATE("matrix-dpll-d2", + PARENT_ID(ZX_CLK_MATRIX_DPLL_D2_PREGATE), 0x118, 9, 0), + + [ZX_CLK_MATRIX_GPLL_D2_D4] = GATE("matrix-gpll-d2-d4", + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D4_PREGATE), + 0x118, 12, 0), + [ZX_CLK_MATRIX_GPLL_D2_D2] = GATE("matrix-gpll-d2-d2", + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D2_PREGATE), + 0x118, 13, 0), + + [ZX_CLK_CPU_MUX] = MUX("cpu-mux", cpu_sel, 0x20, 0, 2), + [ZX_CLK_ZSP_MUX] = MUX("zsp-mux", zsp_sel, 0x30, 0, 2), + [ZX_CLK_DDR_CTRL_MUX] = MUX("ddr-ctrl-mux", ddr_ctrl_sel, 0x50, 0, 2), + [ZX_CLK_SD0_MUX] = MUX("sd0-mux", sd0_sel, 0x50, 4, 3), + [ZX_CLK_SD1_MUX] = MUX("sd1-mux", sd1_sel, 0x50, 8, 3), + [ZX_CLK_NAND_MUX] = MUX("nand-mux", nand_sel, 0x50, 12, 2), + [ZX_CLK_EDCP_MUX] = MUX("edcp-mux", edcp_sel, 0x50, 16, 2), + [ZX_CLK_TDM_MUX] = MUX("tdm-mux", tdm_sel, 0x50, 24, 2), + [ZX_CLK_AXI_MUX] = MUX("axi-mux", axi_sel, ZX297520V3_AXI_AP_VOTE, 0, 3), + + /* + * This bit cuts off the clock signal to the ARM architected timer, which the kernel uses + * as its main timer. It isn't critical per se - there are plenty of proprietary timers + * available that could be used - but the arm arch timer binding does not accept a clock, so + * this CCF driver won't know if the timer is in use. + * + * This clock is fed by the osc26m gate in topcrm+0x140 - this critical clock here protects + * its parent. + * + * Registers 0x148, 0x14c, 0x150, 0x154 allow setting and clearing the timer counter. To + * set the timer, load a value into 0x148 (high 32 bits) and 0x14c (low 32 bits), then + * toggle 0x150 to 1. 0x150 will automatically reset to 0. 0x154 sets the timer to some + * "clear" value, but this value isn't 0. + */ + [ZX_CLK_SYS_TIMER_WCLK] = GATE("sys-timer-wclk", PARENT_FW("wclk-osc26m"), 0x144, 1, + CLK_IS_CRITICAL), + + /* + * Both 0x24 and 0x28 bits 1 and 2 stop the CPU. There is also a bit in topcrm+0x138, which + * ZTE's uboot calls "A53 reset", which also stops the CPU. I can't really tell the + * difference between matrix+0x28 and top+0x138. The clock (matrix+0x24) can be disabled + * and enabled from the Cortex M0 and it will nicely stop and restart the A53, retaining + * all state. + */ + [ZX_CLK_CPU_WCLK] = GATE("cpu-wclk", PARENT_ID(ZX_CLK_CPU_MUX), 0x24, 1, + CLK_IS_CRITICAL), + [ZX_CLK_CPU_PCLK] = GATE("cpu-pclk", clk_main[0], 0x24, 2, CLK_IS_CRITICAL), + + /* + * There are a lot more controls in matrix+0x100. 13-16 appear to be 4 different AXI + * channels for different priorities. Bit 19 appears to be the DDR PHY wclk. + * + * The important task is to keep gpll enabled if the bootloader selected a gpll-based rate + * for RAM. + */ + [ZX_CLK_DDR_CTRL_PCLK] = GATE("ddr-ctrl-pclk", clk_main[0], 0x100, 17, CLK_IS_CRITICAL), + [ZX_CLK_DDR_CTRL_WCLK] = GATE("ddr-ctrl-wclk", PARENT_ID(ZX_CLK_DDR_CTRL_MUX), 0x100, 18, + CLK_IS_CRITICAL), + + [ZX_CLK_ZSP_PCLK] = GATE("zsp-pclk", clk_main[0], 0x34, 0, 0), + [ZX_CLK_ZSP_WCLK] = GATE("zsp-wclk", PARENT_ID(ZX_CLK_ZSP_MUX), 0x34, 1, 0), + + /* Both SDIO controllers depend on the ahb-pclk for register access. */ + [ZX_CLK_SD0_PCLK] = GATE("sd0-pclk", PARENT_FW("ahb"), 0x54, 12, 0), + [ZX_CLK_SD0_WCLK] = GATE("sd0-wclk", PARENT_ID(ZX_CLK_SD0_MUX), 0x54, 13, 0), + [ZX_CLK_SD0_CDET] = GATE("sd0-cdet", PARENT_FW("osc32k"), 0x54, 14, 0), + [ZX_CLK_SD1_PCLK] = GATE("sd1-pclk", PARENT_FW("ahb"), 0x54, 4, 0), + [ZX_CLK_SD1_WCLK] = GATE("sd1-wclk", PARENT_ID(ZX_CLK_SD1_MUX), 0x54, 5, 0), + /* + * I don't know how the cdet clock works. Card detection in the way the dwc,mmc driver uses + * it appears broken no matter this clock's setting. + */ + [ZX_CLK_SD1_CDET] = GATE("sd1-cdet", PARENT_FW("osc32k"), 0x54, 6, 0), + + /* This is some "denali" NAND, not the qspi connected one */ + [ZX_CLK_NAND_WCLK] = GATE("nand-wclk", PARENT_ID(ZX_CLK_NAND_MUX), 0x54, 20, 0), + [ZX_CLK_NAND_PCLK] = GATE("nand-pclk", clk_main[0], 0x54, 21, 0), + + /* + * There is a set of gates for an unknown device at matrix+0x60. It is some LTE related + * device and the pclk gates off mmio areas 0xf8000000 and 0xfc000000. These areas are only + * accessible to M0 and ZSP, not the AP. + * + * If it is fed an incorrect clock, e.g. because dpll is not locked and outputs 26 MHz, it + * will spam IRQs at SPI 68. This is likely a distress notification that some + * internal PLL did not lock or similar. ZTE's kernel has two defines for SPI 68: + * "LTE_TPU_INT_PS_INT" and "VOU_OSD_INT". The latter is unlikely because VOU related clocks + * sit in matrix+0x168. + * + * The address space in 0xfc000000 appears to contain a number of different devices, so I + * have named the clock LTE_MODEM_{W/P}CLK. It is not known how this mmio area and clock + * relates to SPI 68 or the ABB clock in topcrm+0x144. Because it is not accessible to the + * AP at all, I don't think we need to care beyond turning on the clocks before booting the + * ZSP. + * + * Bit 9 in register 0x118 turns the IRQs off, so it is the immediate wclk parent. It isn't + * clear what divisor of dpll it is using though. Following the pattern that lower + * frequencies are gated by lower bits, it would indicate dpll/2 or dpll/3. + */ + [ZX_CLK_LTE_MODEM_WCLK] = GATE("lte-modem-wclk", PARENT_ID(ZX_CLK_MATRIX_DPLL_D2), + 0x60, 0, 0), + [ZX_CLK_LTE_MODEM_PCLK] = GATE("lte-modem-pclk", clk_main[0], + 0x60, 2, 0), + + [ZX_CLK_EDCP_PCLK] = GATE("edcp-pclk", clk_main[0], 0x64, 1, 0), + [ZX_CLK_EDCP_WCLK] = GATE("edcp-wclk", PARENT_ID(ZX_CLK_EDCP_MUX), 0x64, 2, 0), + + /* + * This seems to be another SPI-Like device. cpko.ko uses it to send calibration blobs to + * the LTE radio hardware. After initialization the ZSP firmware takes over control of this + * device. + * + * Testing reveals the parent as matrix's 104 MHz mpll fraction. + */ + [ZX_CLK_RFFE_WCLK] = GATE("rffe-wclk", PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), 0x84, 0, 0), + [ZX_CLK_SSC_WCLK] = GATE("ssc-wclk", PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), 0x84, 1, 0), + [ZX_CLK_SSC_PCLK] = GATE("ssc-pclk", clk_main[0], 0x84, 2, 0), + + /* + * PDCFG. Like PMM, either clock bit will allow the device to function. Probably there is + * no wclk line at all and the two bits are just an artifact of generally having two bits + * per device. + */ + [ZX_CLK_PDCFG_WCLK] = GATE("pdcfg-wclk", matrix_unk, 0x88, 0, CLK_IS_CRITICAL), + [ZX_CLK_PDCFG_PCLK] = GATE("pdcfg-pclk", clk_main[0], 0x88, 1, CLK_IS_CRITICAL), + [ZX_CLK_MBOX_PCLK] = GATE("mbox-pclk", clk_main[0], 0x88, 2, 0), + [ZX_CLK_SRAM0_PCLK] = GATE("sram0-pclk", clk_main[0], 0x88, 4, 0), + [ZX_CLK_GSM_CFG_PCLK] = GATE("gsm-cfg-pclk", clk_main[0], 0x88, 8, 0), + + /* + * ZTE's driver has a statement to the effect of *(top->base+0x11c) = 5, with a comment + * suggesting that this sets a 50 MHz clock. The clock code itself lists GMAC clocks in + * matrix+0x110 and lists the parents of these clocks as 50 MHz gpll output, but + * the downstream ZTE GMAC driver never enables the clocks. It turns out ZTE's code is + * highly misleading. + * + * The GMAC's work clock is definitely not any gpll output because it keeps working fine + * with gpll disabled. Gating off matrix-osc26m breaks GMAC, so it must be its parent. + * + * The GMAC Gates are left enabled by the boot loader and are required for the GMAC to work. + * + * As for the 50 MHz comment: See rmiiphy-wclk. + * + * The gmac-ahb clock is a child of topcrm's ahb-pclk and is required for DMA transfers in + * and out of GMAC. Without it, GMAC still receives ethernet frames, but can't drain them + * to memory and will eventually set the RX FIFO overflow flag. + */ + [ZX_CLK_GMAC_WCLK] = GATE("gmac-wclk", PARENT_FW("wclk-osc26m"), 0x110, 0, 0), + [ZX_CLK_GMAC_PCLK] = GATE("gmac-pclk", clk_main[0], 0x110, 1, 0), + [ZX_CLK_GMAC_AHB] = GATE("gmac-ahb", PARENT_FW("ahb"), 0x110, 2, 0), + + /* + * Is there an AXI bus gate? The symptom of cutting off the AXI mux selection in top+0x140 + * is that matrixcrm becomes unreadable from m0 and A53 hangs. Inside matrix itself only 3 + * bits fit that bill: 0x8c bits 5, 6, 7. It seems a bit self-defeating to have a clock + * gate that shuts off access to itself though. I expect a clock gate for the bus + * somewhere, and the mux exists, so exposing one AXI clock in the bindings is the correct + * thing to do. It also serves to tell the kernel to keep the mux's parent enabled. + * + * Register 0x8c has 12 settable bits (0xfff). Ultimately it doesn't matter much which + * do-not-remove bit we don't remove. Other bits in this register behave like gates (e.g + * bits 11:8 cut off USB temporarily), so I think we are looking in the right place. + * + * If an explanation for the remaining bits surfaces and they are further gates and/or + * resets, add them to the bindings. + */ + [ZX_CLK_AXI_WCLK] = GATE("axi-wclk", PARENT_ID(ZX_CLK_AXI_MUX), 0x8c, 5, + CLK_IS_CRITICAL), + + [ZX_CLK_DMA_PCLK] = GATE("dma-pclk", clk_main[0], 0x94, 3, 0), + + /* + * There are a lot more VOU related controls in these registers, but turning off the main + * clock seems to shut off the entire VOU MMIO range. + */ + [ZX_CLK_VOU_WCLK] = GATE("vou-wclk", matrix_unk, 0x168, 0, 0), + [ZX_CLK_VOU_PCLK] = GATE("vou-pclk", clk_main[0], 0x168, 1, 0), + + /* + * LSP uplink clocks. The pclk is fairly obvious (disabling it shuts off the entire LSP + * register area). The wclk speeds were deduced by setting timers and qspi muxes to a + * specific speed and seeing which bit in matrix+0x7c needs to be enabled for the device + * to work. + * + * Due to the timers I am certain about the 26 MHz and 32 kHz clocks. I cannot directly + * observe the qspi mux frequency, so the clock rates depend on ZTE's qspi mux selection + * being correct. + * + * Two additional bits are specific to sound components - the mux for the LSP's TDM IP is + * in matrixcrm and gets passed down. I2S has a mux in LSP, which can select the dpll-d4 + * clock. + */ + [ZX_CLK_TOLSP_MPLL_D5_WCLK] = GATE("lsp-mpll-d5", PARENT_FW("mpll-d5"), 0x7c, 0, 0), + [ZX_CLK_TOLSP_MPLL_D4_WCLK] = GATE("lsp-mpll-d4", PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), + 0x7c, 1, 0), + [ZX_CLK_TOLSP_MPLL_D6_WCLK] = GATE("lsp-mpll-d6", PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), + 0x7c, 2, 0), + [ZX_CLK_TOLSP_MPLL_D8_WCLK] = GATE("lsp-mpll-d8", PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), + 0x7c, 3, 0), + [ZX_CLK_TOLSP_MPLL_D12_WCLK] = GATE("lsp-mpll-d12", PARENT_ID(ZX_CLK_MATRIX_MPLL_D12), + 0x7c, 4, 0), + [ZX_CLK_TOLSP_OSC26M_WCLK] = GATE("lsp-osc26m", PARENT_FW("wclk-osc26m"), 0x7c, 5, 0), + [ZX_CLK_TOLSP_OSC32K_WCLK] = GATE("lsp-osc32k", PARENT_FW("osc32k"), 0x7c, 6, 0), + [ZX_CLK_TOLSP_PCLK] = GATE("lsp-pclk", clk_main[0], 0x7c, 7, 0), + [ZX_CLK_TOLSP_TDM_WCLK] = GATE("lsp-tdm-wclk", PARENT_ID(ZX_CLK_TDM_MUX), 0x7c, 8, 0), + [ZX_CLK_TOLSP_DPLL_D4_WCLK] = GATE("lsp-dpll-d4", PARENT_ID(ZX_CLK_MATRIX_DPLL_D4), + 0x7c, 9, 0), +}; + +static int zx297520v3_matrix_init(struct regmap *map) +{ + u32 axi_val; + int res; + + /* Read the global AXI speed selection, insert it into our ballot and enable voting */ + res = regmap_read(map, 0x0, &axi_val); + if (res) + return res; + + axi_val &= 0x7; + res = regmap_write(map, ZX297520V3_AXI_AP_VOTE, axi_val); + if (res) + return res; + + return regmap_write(map, 0x12c, 1); +} + +static const unsigned int zx297520v3_matrix_exports[] = { + [ZX297520V3_SYS_TIMER_WCLK] = ZX_CLK_SYS_TIMER_WCLK, + [ZX297520V3_CPU_WCLK] = ZX_CLK_CPU_WCLK, + [ZX297520V3_CPU_PCLK] = ZX_CLK_CPU_PCLK, + [ZX297520V3_ZSP_WCLK] = ZX_CLK_ZSP_WCLK, + [ZX297520V3_ZSP_PCLK] = ZX_CLK_ZSP_PCLK, + [ZX297520V3_DDR_CTRL_PCLK] = ZX_CLK_DDR_CTRL_PCLK, + [ZX297520V3_DDR_CTRL_WCLK] = ZX_CLK_DDR_CTRL_WCLK, + [ZX297520V3_EDCP_WCLK] = ZX_CLK_EDCP_WCLK, + [ZX297520V3_EDCP_PCLK] = ZX_CLK_EDCP_PCLK, + [ZX297520V3_SD0_WCLK] = ZX_CLK_SD0_WCLK, + [ZX297520V3_SD0_PCLK] = ZX_CLK_SD0_PCLK, + [ZX297520V3_SD0_CDET] = ZX_CLK_SD0_CDET, + [ZX297520V3_SD1_WCLK] = ZX_CLK_SD1_WCLK, + [ZX297520V3_SD1_PCLK] = ZX_CLK_SD1_PCLK, + [ZX297520V3_SD1_CDET] = ZX_CLK_SD1_CDET, + [ZX297520V3_NAND_WCLK] = ZX_CLK_NAND_WCLK, + [ZX297520V3_NAND_PCLK] = ZX_CLK_NAND_PCLK, + [ZX297520V3_DMA_PCLK] = ZX_CLK_DMA_PCLK, + [ZX297520V3_MBOX_PCLK] = ZX_CLK_MBOX_PCLK, + [ZX297520V3_PDCFG_WCLK] = ZX_CLK_PDCFG_WCLK, + [ZX297520V3_PDCFG_PCLK] = ZX_CLK_PDCFG_PCLK, + [ZX297520V3_RFFE_WCLK] = ZX_CLK_RFFE_WCLK, + [ZX297520V3_SSC_WCLK] = ZX_CLK_SSC_WCLK, + [ZX297520V3_SSC_PCLK] = ZX_CLK_SSC_PCLK, + [ZX297520V3_AXI_WCLK] = ZX_CLK_AXI_WCLK, + [ZX297520V3_GMAC_WCLK] = ZX_CLK_GMAC_WCLK, + [ZX297520V3_GMAC_PCLK] = ZX_CLK_GMAC_PCLK, + [ZX297520V3_GMAC_AHB] = ZX_CLK_GMAC_AHB, + [ZX297520V3_VOU_WCLK] = ZX_CLK_VOU_WCLK, + [ZX297520V3_VOU_PCLK] = ZX_CLK_VOU_PCLK, + [ZX297520V3_LSP_MPLL_D5_WCLK] = ZX_CLK_TOLSP_MPLL_D5_WCLK, + [ZX297520V3_LSP_MPLL_D4_WCLK] = ZX_CLK_TOLSP_MPLL_D4_WCLK, + [ZX297520V3_LSP_MPLL_D6_WCLK] = ZX_CLK_TOLSP_MPLL_D6_WCLK, + [ZX297520V3_LSP_MPLL_D8_WCLK] = ZX_CLK_TOLSP_MPLL_D8_WCLK, + [ZX297520V3_LSP_MPLL_D12_WCLK] = ZX_CLK_TOLSP_MPLL_D12_WCLK, + [ZX297520V3_LSP_OSC26M_WCLK] = ZX_CLK_TOLSP_OSC26M_WCLK, + [ZX297520V3_LSP_OSC32K_WCLK] = ZX_CLK_TOLSP_OSC32K_WCLK, + [ZX297520V3_LSP_PCLK] = ZX_CLK_TOLSP_PCLK, + [ZX297520V3_LSP_TDM_WCLK] = ZX_CLK_TOLSP_TDM_WCLK, + [ZX297520V3_LSP_DPLL_D4_WCLK] = ZX_CLK_TOLSP_DPLL_D4_WCLK, + [ZX297520V3_SRAM0_PCLK] = ZX_CLK_SRAM0_PCLK, + [ZX297520V3_GSM_CFG_PCLK] = ZX_CLK_GSM_CFG_PCLK, + [ZX297520V3_LTE_MODEM_WCLK] = ZX_CLK_LTE_MODEM_WCLK, + [ZX297520V3_LTE_MODEM_PCLK] = ZX_CLK_LTE_MODEM_PCLK, +}; + +static const struct zx_clk_data zx297520v3_matrixclk_data = { + .init = zx297520v3_matrix_init, + .clocks = zx297520v3_matrix_clocks, + .num_clocks = ARRAY_SIZE(zx297520v3_matrix_clocks), + .exports = zx297520v3_matrix_exports, + .num_exports = ARRAY_SIZE(zx297520v3_matrix_exports), +}; + static int clk_zx297520v3_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); @@ -828,6 +1350,10 @@ static const struct platform_device_id clk_zx297520v3_ids[] = { .name = "zx297520v3-topclk", .driver_data = (kernel_ulong_t)&zx297520v3_topclk_data, }, + { + .name = "zx297520v3-matrixclk", + .driver_data = (kernel_ulong_t)&zx297520v3_matrixclk_data, + }, { } }; MODULE_DEVICE_TABLE(platform, clk_zx297520v3_ids); From 227db8dc09fe3f5e8a507b3efed6868f936e0030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:39 +0300 Subject: [PATCH 160/168] clk: zte: Introduce a driver for zx297520v3 LSP clocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "LSP" is ZTE's term for this part of the SoC, I suspect it stands for "low speed peripherals". The main UART is here, together with the flash controller and more surplus proprietary timers. It also has one more I2C controller that supposedly connects to a battery charger, SPI for displays and I2S for analog telephones. The boards I have don't have any of these components though. Signed-off-by: Stefan Dösinger Signed-off-by: Brian Masney --- drivers/clk/zte/clk-zx297520v3.c | 285 +++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx297520v3.c index d5f8bc4064bd..e0f78f841bde 100644 --- a/drivers/clk/zte/clk-zx297520v3.c +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -1334,6 +1334,287 @@ static const struct zx_clk_data zx297520v3_matrixclk_data = { .num_exports = ARRAY_SIZE(zx297520v3_matrix_exports), }; +/* + * LSP clock entries have a common pattern: Bit 0 for pclk, Bit 1 for wclk. Bit 4 (and sometimes + * more) for wclk mux. + * + * Bit 8 and 9 are resets handled by the reset-zte-zx297520v3 driver. + * + * Bits 15:12 can be a divisor, but not all clocks have it. Some clocks have a divisor in 19:16. + * + * The ID given in this table is the first register in the device's MMIO space. ZTE's drivers + * usually call this a version register, but it looks more like a device identifier. + * + * It looks like the registers map to devices like this: + * + * CRM Reg function div dev offset(lsp + xxxx) ID + * 0x0: Read-only, probably device identifier 0x00752100 + * 0x4: timer_l1 Y 0x1000 0x02020000 + * 0x8: watchdog_l2 Y 0x2000 0x02020000 + * 0xc: watchdog_l3 Y 0x3000 0x02020000 + * 0x10: pwm N 0x4000 0x01020000 + * 0x14: i2s0 Yh 0x5000 0x01030000 + * 0x18: always 0 - - - + * 0x1c: i2s1 Yh 0x6000 0x01030000 + * 0x20: always 0 - - - + * 0x24: qspi N 0x7000 0x01040000 + * 0x28: uart1 N 0x8000 0x01060000 + * 0x2c: i2c1 N 0x9000 0x01020000 + * 0x30: spi0 Y 0xa000 0x01040000 + * 0x34: timer_lb Y 0xb000 0x02020000 + * 0x38: timer_lc Y 0xc000 0x02020000 + * 0x3c: uart2 N 0xd000 0x01060000 + * 0x40: watchdog_le Y 0xe000 0x02020000 + * 0x44: timer_lf Y 0xf000 0x02020000 + * 0x48: spi1 Y 0x10000 0x01040000 + * 0x4c: timer_l11 Y 0x11000 0x02020000 + * 0x50: tdm Yh 0x12000 0x01040000 + * + * Registers 0x58, 0x5c, 0x60, 0x64, 0x68 seem to contain more controls for i2s and tdm. + * + * The device at offset 0x4000 (clk reg 0x10) is a PWM device. The ID matches that of i2c, it has a + * larger register set. ZTE's kernel does not operate it at all. The old upstream pwm-zx.c driver + * provided enough instructions to blink the Wifi led and isolate the parent. + */ + +enum lsp_clock_ids { + ZX_CLK_TIMER_L1_MUX, + ZX_CLK_WDT_L2_MUX, + ZX_CLK_WDT_L3_MUX, + ZX_CLK_I2S0_MUX, + ZX_CLK_I2S1_MUX, + ZX_CLK_QSPI_MUX, + ZX_CLK_UART1_MUX, + ZX_CLK_I2C1_MUX, + ZX_CLK_SPI0_MUX, + ZX_CLK_TIMER_LB_MUX, + ZX_CLK_TIMER_LC_MUX, + ZX_CLK_UART2_MUX, + ZX_CLK_WDT_LE_MUX, + ZX_CLK_TIMER_LF_MUX, + ZX_CLK_SPI1_MUX, + ZX_CLK_TIMER_L11_MUX, + + ZX_CLK_TIMER_L1_DIV, + ZX_CLK_WDT_L2_DIV, + ZX_CLK_WDT_L3_DIV, + ZX_CLK_I2S0_DIV, + ZX_CLK_I2S1_DIV, + ZX_CLK_SPI0_DIV, + ZX_CLK_TIMER_LB_DIV, + ZX_CLK_TIMER_LC_DIV, + ZX_CLK_WDT_LE_DIV, + ZX_CLK_TIMER_LF_DIV, + ZX_CLK_SPI1_DIV, + ZX_CLK_TIMER_L11_DIV, + ZX_CLK_TDM_DIV, + + ZX_CLK_TIMER_L1_PCLK, + ZX_CLK_TIMER_L1_WCLK, + ZX_CLK_WDT_L2_PCLK, + ZX_CLK_WDT_L2_WCLK, + ZX_CLK_WDT_L3_PCLK, + ZX_CLK_WDT_L3_WCLK, + ZX_CLK_PWM_PCLK, + ZX_CLK_PWM_WCLK, + ZX_CLK_I2S0_PCLK, + ZX_CLK_I2S0_WCLK, + ZX_CLK_I2S1_PCLK, + ZX_CLK_I2S1_WCLK, + ZX_CLK_QSPI_PCLK, + ZX_CLK_QSPI_WCLK, + ZX_CLK_UART1_PCLK, + ZX_CLK_UART1_WCLK, + ZX_CLK_I2C1_PCLK, + ZX_CLK_I2C1_WCLK, + ZX_CLK_SPI0_PCLK, + ZX_CLK_SPI0_WCLK, + ZX_CLK_TIMER_LB_PCLK, + ZX_CLK_TIMER_LB_WCLK, + ZX_CLK_TIMER_LC_PCLK, + ZX_CLK_TIMER_LC_WCLK, + ZX_CLK_UART2_PCLK, + ZX_CLK_UART2_WCLK, + ZX_CLK_WDT_LE_PCLK, + ZX_CLK_WDT_LE_WCLK, + ZX_CLK_TIMER_LF_PCLK, + ZX_CLK_TIMER_LF_WCLK, + ZX_CLK_SPI1_PCLK, + ZX_CLK_SPI1_WCLK, + ZX_CLK_TIMER_L11_PCLK, + ZX_CLK_TIMER_L11_WCLK, + ZX_CLK_TDM_PCLK, + ZX_CLK_TDM_WCLK, +}; + +static const struct zx_parent_desc timer_lsp_sel[] = { + PARENT_FW("osc32k"), + PARENT_FW("osc26m"), +}; + +static const struct zx_parent_desc uart_lsp_sel[] = { + PARENT_FW("osc26m"), + PARENT_FW("mpll-d6"), +}; + +static const struct zx_parent_desc i2s_lsp_sel[] = { + PARENT_FW("osc26m"), + PARENT_FW("dpll-d4"), + PARENT_FW("mpll-d6"), + /* Unknown */ +}; + +static const struct zx_parent_desc spi_lsp_sel[] = { + PARENT_FW("osc26m"), + PARENT_FW("mpll-d4"), + PARENT_FW("mpll-d6"), + /* Unknown */ +}; + +static const struct zx_parent_desc qspi_lsp_sel[] = { + PARENT_FW("osc26m"), + PARENT_FW("mpll-d4"), + PARENT_FW("mpll-d5"), + PARENT_FW("mpll-d6"), + PARENT_FW("mpll-d8"), + PARENT_FW("mpll-d12"), + PARENT_FW("osc26m"), + PARENT_FW("osc26m"), +}; + +static const struct zx_clock zx297520v3_lsp_clocks[] = { + [ZX_CLK_TIMER_L1_MUX] = MUX("timer-l1-mux", timer_lsp_sel, 0x04, 4, 1), + [ZX_CLK_WDT_L2_MUX] = MUX("wdt-l2-mux", timer_lsp_sel, 0x08, 4, 1), + [ZX_CLK_WDT_L3_MUX] = MUX("wdt-l3-mux", timer_lsp_sel, 0x0c, 4, 1), + /* PWM: No mux bit can be set */ + [ZX_CLK_I2S0_MUX] = MUX("i2s0-mux", i2s_lsp_sel, 0x14, 4, 2), + /* 0x18: Always 0 */ + [ZX_CLK_I2S1_MUX] = MUX("i2s1-mux", i2s_lsp_sel, 0x1c, 4, 2), + /* 0x20: Always 0 */ + [ZX_CLK_QSPI_MUX] = MUX("qspi-mux", qspi_lsp_sel, 0x24, 4, 3), + [ZX_CLK_UART1_MUX] = MUX("uart1-mux", uart_lsp_sel, 0x28, 4, 1), + [ZX_CLK_I2C1_MUX] = MUX("i2c1-mux", uart_lsp_sel, 0x2c, 4, 1), + [ZX_CLK_SPI0_MUX] = MUX("spi0-mux", spi_lsp_sel, 0x30, 4, 2), + [ZX_CLK_TIMER_LB_MUX] = MUX("timer-lb-mux", timer_lsp_sel, 0x34, 4, 1), + [ZX_CLK_TIMER_LC_MUX] = MUX("timer-lc-mux", timer_lsp_sel, 0x38, 4, 1), + [ZX_CLK_UART2_MUX] = MUX("uart2-mux", uart_lsp_sel, 0x3c, 4, 1), + [ZX_CLK_WDT_LE_MUX] = MUX("wdt-le-mux", timer_lsp_sel, 0x40, 4, 1), + [ZX_CLK_TIMER_LF_MUX] = MUX("timer-lf-mux", timer_lsp_sel, 0x44, 4, 1), + [ZX_CLK_SPI1_MUX] = MUX("spi1-mux", spi_lsp_sel, 0x48, 4, 2), + [ZX_CLK_TIMER_L11_MUX] = MUX("timer-l11-mux", timer_lsp_sel, 0x4c, 4, 1), + /* TDM: No mux in LSP. Instead, it is in matrix with a separate clk line to LSP */ + + [ZX_CLK_TIMER_L1_DIV] = DIV("timer-l1-div", PARENT_ID(ZX_CLK_TIMER_L1_MUX), + 0x04, 12, 4), + [ZX_CLK_WDT_L2_DIV] = DIV("wdt-l2-div", PARENT_ID(ZX_CLK_WDT_L2_MUX), 0x08, 12, 4), + [ZX_CLK_WDT_L3_DIV] = DIV("wdt-l3-div", PARENT_ID(ZX_CLK_WDT_L3_MUX), 0x0c, 12, 4), + /* PWM: No div */ + [ZX_CLK_I2S0_DIV] = DIV("i2s0-div", PARENT_ID(ZX_CLK_I2S0_MUX), 0x14, 16, 4), + /* 0x18: Always 0 */ + [ZX_CLK_I2S1_DIV] = DIV("i2s1-div", PARENT_ID(ZX_CLK_I2S1_MUX), 0x1c, 16, 4), + /* 0x20: Always 0 */ + /* qspi, uart1, i2c1: No div */ + [ZX_CLK_SPI0_DIV] = DIV("spi0-div", PARENT_ID(ZX_CLK_SPI0_MUX), 0x30, 12, 4), + [ZX_CLK_TIMER_LB_DIV] = DIV("timer-lb-div", PARENT_ID(ZX_CLK_TIMER_LB_MUX), + 0x34, 12, 4), + [ZX_CLK_TIMER_LC_DIV] = DIV("timer-lc-div", PARENT_ID(ZX_CLK_TIMER_LC_MUX), + 0x38, 12, 4), + /* uart2: No div */ + [ZX_CLK_WDT_LE_DIV] = DIV("wdt-le-div", PARENT_ID(ZX_CLK_WDT_LE_MUX), 0x40, 12, 4), + [ZX_CLK_TIMER_LF_DIV] = DIV("timer-lf-div", PARENT_ID(ZX_CLK_TIMER_LF_MUX), + 0x44, 12, 4), + [ZX_CLK_SPI1_DIV] = DIV("spi1-div", PARENT_ID(ZX_CLK_SPI1_MUX), 0x48, 12, 4), + [ZX_CLK_TIMER_L11_DIV] = DIV("timer-l11-div", PARENT_ID(ZX_CLK_TIMER_L11_MUX), + 0x4c, 12, 4), + [ZX_CLK_TDM_DIV] = DIV("tdm-div", PARENT_FW("tdm-wclk"), 0x50, 16, 4), + + [ZX_CLK_TIMER_L1_PCLK] = GATE("timer-l1-pclk", PARENT_FW("pclk"), 0x04, 0, 0), + [ZX_CLK_TIMER_L1_WCLK] = GATE("timer-l1-wclk", PARENT_ID(ZX_CLK_TIMER_L1_DIV), 0x04, 1, 0), + [ZX_CLK_WDT_L2_PCLK] = GATE("wdt-l2-pclk", PARENT_FW("pclk"), 0x08, 0, 0), + [ZX_CLK_WDT_L2_WCLK] = GATE("wdt-l2-wclk", PARENT_ID(ZX_CLK_WDT_L2_DIV), 0x08, 1, 0), + [ZX_CLK_WDT_L3_PCLK] = GATE("wdt-l3-pclk", PARENT_FW("pclk"), 0x0c, 0, 0), + [ZX_CLK_WDT_L3_WCLK] = GATE("wdt-l3-wclk", PARENT_ID(ZX_CLK_WDT_L3_DIV), 0x0c, 1, 0), + [ZX_CLK_PWM_PCLK] = GATE("pwm-pclk", PARENT_FW("pclk"), 0x10, 0, 0), + [ZX_CLK_PWM_WCLK] = GATE("pwm-wclk", PARENT_FW("mpll-d6"), 0x10, 1, 0), + [ZX_CLK_I2S0_PCLK] = GATE("i2s0-pclk", PARENT_FW("pclk"), 0x14, 0, 0), + [ZX_CLK_I2S0_WCLK] = GATE("i2s0-wclk", PARENT_ID(ZX_CLK_I2S0_DIV), 0x14, 1, 0), + /* 0x18: Always 0 */ + [ZX_CLK_I2S1_PCLK] = GATE("i2s1-pclk", PARENT_FW("pclk"), 0x1c, 0, 0), + [ZX_CLK_I2S1_WCLK] = GATE("i2s1-wclk", PARENT_ID(ZX_CLK_I2S1_DIV), 0x1c, 1, 0), + /* 0x20: Always 0 */ + [ZX_CLK_QSPI_PCLK] = GATE("qspi-pclk", PARENT_FW("pclk"), 0x24, 0, 0), + [ZX_CLK_QSPI_WCLK] = GATE("qspi-wclk", PARENT_ID(ZX_CLK_QSPI_MUX), 0x24, 1, 0), + [ZX_CLK_UART1_PCLK] = GATE("uart1-pclk", PARENT_FW("pclk"), 0x28, 0, 0), + [ZX_CLK_UART1_WCLK] = GATE("uart1-wclk", PARENT_ID(ZX_CLK_UART1_MUX), 0x28, 1, 0), + [ZX_CLK_I2C1_PCLK] = GATE("i2c1-pclk", PARENT_FW("pclk"), 0x2c, 0, 0), + [ZX_CLK_I2C1_WCLK] = GATE("i2c1-wclk", PARENT_ID(ZX_CLK_I2C1_MUX), 0x2c, 1, 0), + [ZX_CLK_SPI0_PCLK] = GATE("spi0-pclk", PARENT_FW("pclk"), 0x30, 0, 0), + [ZX_CLK_SPI0_WCLK] = GATE("spi0-wclk", PARENT_ID(ZX_CLK_SPI0_DIV), 0x30, 1, 0), + [ZX_CLK_TIMER_LB_PCLK] = GATE("timer-lb-pclk", PARENT_FW("pclk"), 0x34, 0, 0), + [ZX_CLK_TIMER_LB_WCLK] = GATE("timer-lb-wclk", PARENT_ID(ZX_CLK_TIMER_LB_DIV), 0x34, 1, 0), + [ZX_CLK_TIMER_LC_PCLK] = GATE("timer-lc-pclk", PARENT_FW("pclk"), 0x38, 0, 0), + [ZX_CLK_TIMER_LC_WCLK] = GATE("timer-lc-wclk", PARENT_ID(ZX_CLK_TIMER_LC_DIV), 0x38, 1, 0), + [ZX_CLK_UART2_PCLK] = GATE("uart2-pclk", PARENT_FW("pclk"), 0x3c, 0, 0), + [ZX_CLK_UART2_WCLK] = GATE("uart2-wclk", PARENT_ID(ZX_CLK_UART2_MUX), 0x3c, 1, 0), + [ZX_CLK_WDT_LE_PCLK] = GATE("wdt-le-pclk", PARENT_FW("pclk"), 0x40, 0, 0), + [ZX_CLK_WDT_LE_WCLK] = GATE("wdt-le-wclk", PARENT_ID(ZX_CLK_WDT_LE_DIV), 0x40, 1, 0), + [ZX_CLK_TIMER_LF_PCLK] = GATE("timer-lf-pclk", PARENT_FW("pclk"), 0x44, 0, 0), + [ZX_CLK_TIMER_LF_WCLK] = GATE("timer-lf-wclk", PARENT_ID(ZX_CLK_TIMER_LF_DIV), 0x44, 1, 0), + [ZX_CLK_SPI1_PCLK] = GATE("spi1-pclk", PARENT_FW("pclk"), 0x48, 0, 0), + [ZX_CLK_SPI1_WCLK] = GATE("spi1-wclk", PARENT_ID(ZX_CLK_SPI1_DIV), 0x48, 1, 0), + [ZX_CLK_TIMER_L11_PCLK] = GATE("timer-l11-pclk", PARENT_FW("pclk"), 0x4c, 0, 0), + [ZX_CLK_TIMER_L11_WCLK] = GATE("timer-l11-wclk", PARENT_ID(ZX_CLK_TIMER_L11_DIV), + 0x4c, 1, 0), + [ZX_CLK_TDM_PCLK] = GATE("tdm-pclk", PARENT_FW("pclk"), 0x50, 0, 0), + [ZX_CLK_TDM_WCLK] = GATE("tdm-wclk", PARENT_ID(ZX_CLK_TDM_DIV), 0x50, 1, 0), +}; + +static const unsigned int zx297520v3_lsp_exports[] = { + [ZX297520V3_TIMER_L1_WCLK] = ZX_CLK_TIMER_L1_WCLK, + [ZX297520V3_TIMER_L1_PCLK] = ZX_CLK_TIMER_L1_PCLK, + [ZX297520V3_WDT_L2_WCLK] = ZX_CLK_WDT_L2_WCLK, + [ZX297520V3_WDT_L2_PCLK] = ZX_CLK_WDT_L2_PCLK, + [ZX297520V3_WDT_L3_WCLK] = ZX_CLK_WDT_L3_WCLK, + [ZX297520V3_WDT_L3_PCLK] = ZX_CLK_WDT_L3_PCLK, + [ZX297520V3_PWM_WCLK] = ZX_CLK_PWM_WCLK, + [ZX297520V3_PWM_PCLK] = ZX_CLK_PWM_PCLK, + [ZX297520V3_I2S0_WCLK] = ZX_CLK_I2S0_WCLK, + [ZX297520V3_I2S0_PCLK] = ZX_CLK_I2S0_PCLK, + [ZX297520V3_I2S1_WCLK] = ZX_CLK_I2S1_WCLK, + [ZX297520V3_I2S1_PCLK] = ZX_CLK_I2S1_PCLK, + [ZX297520V3_QSPI_WCLK] = ZX_CLK_QSPI_WCLK, + [ZX297520V3_QSPI_PCLK] = ZX_CLK_QSPI_PCLK, + [ZX297520V3_UART1_WCLK] = ZX_CLK_UART1_WCLK, + [ZX297520V3_UART1_PCLK] = ZX_CLK_UART1_PCLK, + [ZX297520V3_I2C1_WCLK] = ZX_CLK_I2C1_WCLK, + [ZX297520V3_I2C1_PCLK] = ZX_CLK_I2C1_PCLK, + [ZX297520V3_SPI0_WCLK] = ZX_CLK_SPI0_WCLK, + [ZX297520V3_SPI0_PCLK] = ZX_CLK_SPI0_PCLK, + [ZX297520V3_TIMER_LB_WCLK] = ZX_CLK_TIMER_LB_WCLK, + [ZX297520V3_TIMER_LB_PCLK] = ZX_CLK_TIMER_LB_PCLK, + [ZX297520V3_TIMER_LC_WCLK] = ZX_CLK_TIMER_LC_WCLK, + [ZX297520V3_TIMER_LC_PCLK] = ZX_CLK_TIMER_LC_PCLK, + [ZX297520V3_UART2_WCLK] = ZX_CLK_UART2_WCLK, + [ZX297520V3_UART2_PCLK] = ZX_CLK_UART2_PCLK, + [ZX297520V3_WDT_LE_WCLK] = ZX_CLK_WDT_LE_WCLK, + [ZX297520V3_WDT_LE_PCLK] = ZX_CLK_WDT_LE_PCLK, + [ZX297520V3_TIMER_LF_WCLK] = ZX_CLK_TIMER_LF_WCLK, + [ZX297520V3_TIMER_LF_PCLK] = ZX_CLK_TIMER_LF_PCLK, + [ZX297520V3_SPI1_WCLK] = ZX_CLK_SPI1_WCLK, + [ZX297520V3_SPI1_PCLK] = ZX_CLK_SPI1_PCLK, + [ZX297520V3_TIMER_L11_WCLK] = ZX_CLK_TIMER_L11_WCLK, + [ZX297520V3_TIMER_L11_PCLK] = ZX_CLK_TIMER_L11_PCLK, + [ZX297520V3_TDM_WCLK] = ZX_CLK_TDM_WCLK, + [ZX297520V3_TDM_PCLK] = ZX_CLK_TDM_PCLK, +}; + +static const struct zx_clk_data zx297520v3_lspclk_data = { + .clocks = zx297520v3_lsp_clocks, + .num_clocks = ARRAY_SIZE(zx297520v3_lsp_clocks), + .exports = zx297520v3_lsp_exports, + .num_exports = ARRAY_SIZE(zx297520v3_lsp_exports), +}; + static int clk_zx297520v3_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); @@ -1354,6 +1635,10 @@ static const struct platform_device_id clk_zx297520v3_ids[] = { .name = "zx297520v3-matrixclk", .driver_data = (kernel_ulong_t)&zx297520v3_matrixclk_data, }, + { + .name = "zx297520v3-lspclk", + .driver_data = (kernel_ulong_t)&zx297520v3_lspclk_data, + }, { } }; MODULE_DEVICE_TABLE(platform, clk_zx297520v3_ids); From eb938f033b7b8a578570e9918c0ba2b242aba818 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 30 Sep 2026 22:23:43 -0700 Subject: [PATCH 161/168] clk: mmp2-audio: add missing PM_CLK dependency pm_clk_suspend() and pm_clk_resume() are used but a PM_CLK dependency is needed to expose them as actual functions. Otherwise they are defined as NULL, which does not work with functions having parameters. NULL is probably used as these functions are normally passed as function pointers. While here, convert the block from spaces to tabs so it matches the surrounding Kconfig style. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202610010151.2W0MrmxE-lkp@intel.com/ Assisted-by: LLM Signed-off-by: Rosen Penev Signed-off-by: Brian Masney --- drivers/clk/Kconfig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 0e8d1d4326b6..37a8e35d4178 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -456,11 +456,12 @@ config COMMON_CLK_MMP2 Support for Marvell MMP2 and MMP3 SoC clocks config COMMON_CLK_MMP2_AUDIO - tristate "Clock driver for MMP2 Audio subsystem" - depends on COMMON_CLK_MMP2 || COMPILE_TEST - select COMMON_CLK_MMP - help - This driver supports clocks for Audio subsystem on MMP2 SoC. + tristate "Clock driver for MMP2 Audio subsystem" + depends on COMMON_CLK_MMP2 || COMPILE_TEST + depends on PM_CLK + select COMMON_CLK_MMP + help + This driver supports clocks for Audio subsystem on MMP2 SoC. config COMMON_CLK_BD718XX tristate "Clock driver for 32K clk gates on ROHM PMICs" From abd14114b229181db33391c8fb30ead74f7cd1e8 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Wed, 30 Sep 2026 22:47:01 -0700 Subject: [PATCH 162/168] clk: tegra: bpmp: remove kcalloc Use a flexible array member to avoid allocating separately. Use __counted_by for extra runtime analysis. Signed-off-by: Rosen Penev Signed-off-by: Brian Masney --- drivers/clk/tegra/clk-bpmp.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index 067a8555c4e7..15b976162b59 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -32,7 +32,7 @@ struct tegra_bpmp_clk { unsigned int id; unsigned int num_parents; - unsigned int *parents; + unsigned int parents[] __counted_by(num_parents); }; static inline struct tegra_bpmp_clk *to_tegra_bpmp_clk(struct clk_hw *hw) @@ -518,20 +518,14 @@ tegra_bpmp_clk_register(struct tegra_bpmp *bpmp, unsigned int i; int err; - clk = devm_kzalloc(bpmp->dev, sizeof(*clk), GFP_KERNEL); + clk = devm_kzalloc(bpmp->dev, struct_size(clk, parents, info->num_parents), GFP_KERNEL); if (!clk) return ERR_PTR(-ENOMEM); + clk->num_parents = info->num_parents; clk->id = info->id; clk->bpmp = bpmp; - clk->parents = devm_kcalloc(bpmp->dev, info->num_parents, - sizeof(*clk->parents), GFP_KERNEL); - if (!clk->parents) - return ERR_PTR(-ENOMEM); - - clk->num_parents = info->num_parents; - /* hardware clock initialization */ memset(&init, 0, sizeof(init)); init.name = info->name; From fcfe685cde2f49fe6195b62cdbcaa1c906a853ae Mon Sep 17 00:00:00 2001 From: Junhui Liu Date: Sat, 3 Oct 2026 00:28:39 +0800 Subject: [PATCH 163/168] dt-bindings: clock: anlogic,dr1v90-cru: make external clocks optional The main oscillator is the only required input clock for the CRU, while the external CAN and WDT clocks are optional board-level inputs. The binding currently requires all three clocks, forcing device trees for boards without these external inputs to add stub fixed-clock nodes for which no meaningful clock-frequency can be specified. Allow the clocks and clock-names properties to contain just "osc", optionally followed by either or both of "can_ext" and "wdt_ext". Fixes: 155d900e4c7d ("dt-bindings: clock: add Anlogic DR1V90 CRU") Signed-off-by: Junhui Liu Acked-by: Conor Dooley Signed-off-by: Brian Masney --- .../bindings/clock/anlogic,dr1v90-cru.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/anlogic,dr1v90-cru.yaml b/Documentation/devicetree/bindings/clock/anlogic,dr1v90-cru.yaml index 11a92588e494..482640bcf644 100644 --- a/Documentation/devicetree/bindings/clock/anlogic,dr1v90-cru.yaml +++ b/Documentation/devicetree/bindings/clock/anlogic,dr1v90-cru.yaml @@ -17,15 +17,17 @@ properties: maxItems: 1 clocks: - items: - - description: Main oscillator - - description: External CAN clock - - description: External WDT clock + minItems: 1 + maxItems: 3 + description: + The main oscillator is always required. Either or both of the external CAN + and WDT clocks may also be provided if the board routes them to the SoC. clock-names: + minItems: 1 items: - const: osc - - const: can_ext + - enum: [can_ext, wdt_ext] - const: wdt_ext "#clock-cells": From 5c7c0cbf81bba69695efa12e451f0f2ecd4b92a5 Mon Sep 17 00:00:00 2001 From: bui duc phuc Date: Tue, 6 Oct 2026 18:05:01 +0700 Subject: [PATCH 164/168] clk: lmk04832: Handle reset GPIO lookup errors devm_gpiod_get_optional() may return -EPROBE_DEFER or other errors, but lmk04832_probe() currently ignores them. Check the return value and propagate errors from the reset GPIO lookup. Fixes: 3bc61cfd6f4a ("clk: add support for the lmk04832") Signed-off-by: bui duc phuc Link: https://patch.msgid.link/20261006110501.57051-1-phucduc.bui@gmail.com Signed-off-by: Jerome Brunet Signed-off-by: Brian Masney --- drivers/clk/clk-lmk04832.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c index 10e5cfa96e6b..755f9837c53a 100644 --- a/drivers/clk/clk-lmk04832.c +++ b/drivers/clk/clk-lmk04832.c @@ -1410,6 +1410,9 @@ static int lmk04832_probe(struct spi_device *spi) lmk->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(lmk->reset_gpio)) + return dev_err_probe(lmk->dev, PTR_ERR(lmk->reset_gpio), + "failed to get reset GPIO\n"); lmk->dclk = devm_kcalloc(lmk->dev, info->num_channels >> 1, sizeof(struct lmk_dclk), GFP_KERNEL); From bb1d071a54fefaa43161368f34d8dd13f1720531 Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Thu, 1 Oct 2026 16:20:48 -0500 Subject: [PATCH 165/168] dt-bindings: clock: Convert HiSilicon clocks to DT schema Convert the HiSilicon Hi6220/Hi3660/Hi3670 clock bindings to DT schema format. Rearrange the binding documents splitting out the stub clock binding from everything else. Signed-off-by: Rob Herring (Arm) Acked-by: Wei Xu Link: https://patch.msgid.link/20261001212051.2227941-1-robh@kernel.org Signed-off-by: Brian Masney --- .../bindings/clock/hi3660-clock.txt | 47 ----------------- .../bindings/clock/hi3670-clock.txt | 43 --------------- .../bindings/clock/hi6220-clock.txt | 52 ------------------- .../bindings/clock/hisilicon,clocks.yaml | 51 ++++++++++++++++++ .../clock/hisilicon,hi6220-stub-clk.yaml | 49 +++++++++++++++++ 5 files changed, 100 insertions(+), 142 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/hi3660-clock.txt delete mode 100644 Documentation/devicetree/bindings/clock/hi3670-clock.txt delete mode 100644 Documentation/devicetree/bindings/clock/hi6220-clock.txt create mode 100644 Documentation/devicetree/bindings/clock/hisilicon,clocks.yaml create mode 100644 Documentation/devicetree/bindings/clock/hisilicon,hi6220-stub-clk.yaml diff --git a/Documentation/devicetree/bindings/clock/hi3660-clock.txt b/Documentation/devicetree/bindings/clock/hi3660-clock.txt deleted file mode 100644 index 946da7cee54f..000000000000 --- a/Documentation/devicetree/bindings/clock/hi3660-clock.txt +++ /dev/null @@ -1,47 +0,0 @@ -* Hisilicon Hi3660 Clock Controller - -The Hi3660 clock controller generates and supplies clock to various -controllers within the Hi3660 SoC. - -Required Properties: - -- compatible: the compatible should be one of the following strings to - indicate the clock controller functionality. - - - "hisilicon,hi3660-crgctrl" - - "hisilicon,hi3660-pctrl" - - "hisilicon,hi3660-pmuctrl" - - "hisilicon,hi3660-sctrl" - - "hisilicon,hi3660-iomcu" - - "hisilicon,hi3660-stub-clk" - -- reg: physical base address of the controller and length of memory mapped - region. - -- #clock-cells: should be 1. - -Optional Properties: - -- mboxes: Phandle to the mailbox for sending message to MCU. - (See: ../mailbox/hisilicon,hi3660-mailbox.txt for more info) - -Each clock is assigned an identifier and client nodes use this identifier -to specify the clock which they consume. - -All these identifier could be found in . - -Examples: - crg_ctrl: clock-controller@fff35000 { - compatible = "hisilicon,hi3660-crgctrl", "syscon"; - reg = <0x0 0xfff35000 0x0 0x1000>; - #clock-cells = <1>; - }; - - uart0: serial@fdf02000 { - compatible = "arm,pl011", "arm,primecell"; - reg = <0x0 0xfdf02000 0x0 0x1000>; - interrupts = ; - clocks = <&crg_ctrl HI3660_CLK_MUX_UART0>, - <&crg_ctrl HI3660_PCLK>; - clock-names = "uartclk", "apb_pclk"; - }; diff --git a/Documentation/devicetree/bindings/clock/hi3670-clock.txt b/Documentation/devicetree/bindings/clock/hi3670-clock.txt deleted file mode 100644 index 66f3697eca78..000000000000 --- a/Documentation/devicetree/bindings/clock/hi3670-clock.txt +++ /dev/null @@ -1,43 +0,0 @@ -* Hisilicon Hi3670 Clock Controller - -The Hi3670 clock controller generates and supplies clock to various -controllers within the Hi3670 SoC. - -Required Properties: - -- compatible: the compatible should be one of the following strings to - indicate the clock controller functionality. - - - "hisilicon,hi3670-crgctrl" - - "hisilicon,hi3670-pctrl" - - "hisilicon,hi3670-pmuctrl" - - "hisilicon,hi3670-sctrl" - - "hisilicon,hi3670-iomcu" - - "hisilicon,hi3670-media1-crg" - - "hisilicon,hi3670-media2-crg" - -- reg: physical base address of the controller and length of memory mapped - region. - -- #clock-cells: should be 1. - -Each clock is assigned an identifier and client nodes use this identifier -to specify the clock which they consume. - -All these identifier could be found in . - -Examples: - crg_ctrl: clock-controller@fff35000 { - compatible = "hisilicon,hi3670-crgctrl", "syscon"; - reg = <0x0 0xfff35000 0x0 0x1000>; - #clock-cells = <1>; - }; - - uart0: serial@fdf02000 { - compatible = "arm,pl011", "arm,primecell"; - reg = <0x0 0xfdf02000 0x0 0x1000>; - interrupts = ; - clocks = <&crg_ctrl HI3670_CLK_GATE_UART0>, - <&crg_ctrl HI3670_PCLK>; - clock-names = "uartclk", "apb_pclk"; - }; diff --git a/Documentation/devicetree/bindings/clock/hi6220-clock.txt b/Documentation/devicetree/bindings/clock/hi6220-clock.txt deleted file mode 100644 index 17ac4a3dd26a..000000000000 --- a/Documentation/devicetree/bindings/clock/hi6220-clock.txt +++ /dev/null @@ -1,52 +0,0 @@ -* Hisilicon Hi6220 Clock Controller - -Clock control registers reside in different Hi6220 system controllers, -please refer the following document to know more about the binding rules -for these system controllers: - -Documentation/devicetree/bindings/arm/hisilicon/hisilicon.yaml - -Required Properties: - -- compatible: the compatible should be one of the following strings to - indicate the clock controller functionality. - - - "hisilicon,hi6220-acpu-sctrl" - - "hisilicon,hi6220-aoctrl" - - "hisilicon,hi6220-sysctrl" - - "hisilicon,hi6220-mediactrl" - - "hisilicon,hi6220-pmctrl" - - "hisilicon,hi6220-stub-clk" - -- reg: physical base address of the controller and length of memory mapped - region. - -- #clock-cells: should be 1. - -Optional Properties: - -- hisilicon,hi6220-clk-sram: phandle to the syscon managing the SoC internal sram; - the driver need use the sram to pass parameters for frequency change. - -- mboxes: use the label reference for the mailbox as the first parameter, the - second parameter is the channel number. - -Example 1: - sys_ctrl: sys_ctrl@f7030000 { - compatible = "hisilicon,hi6220-sysctrl", "syscon"; - reg = <0x0 0xf7030000 0x0 0x2000>; - #clock-cells = <1>; - }; - -Example 2: - stub_clock: stub_clock { - compatible = "hisilicon,hi6220-stub-clk"; - hisilicon,hi6220-clk-sram = <&sram>; - #clock-cells = <1>; - mboxes = <&mailbox 1>; - }; - -Each clock is assigned an identifier and client nodes use this identifier -to specify the clock which they consume. - -All these identifier could be found in . diff --git a/Documentation/devicetree/bindings/clock/hisilicon,clocks.yaml b/Documentation/devicetree/bindings/clock/hisilicon,clocks.yaml new file mode 100644 index 000000000000..345c6d0e7a13 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/hisilicon,clocks.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/hisilicon,clocks.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Hisilicon Hi6220/Hi3660/Hi3670 Clock Controllers + +maintainers: + - Wei Xu + +description: > + The Hi3670 clock controller generates and supplies clock to various + controllers within the Hi3670 SoC. + + All these identifiers can be found in: + dt-bindings/clock/hi3660-clock.h. + dt-bindings/clock/hi3670-clock.h. + dt-bindings/clock/hi6220-clock.h. + +properties: + compatible: + items: + - enum: + - hisilicon,hi3660-crgctrl + - hisilicon,hi3660-pctrl + - hisilicon,hi3660-pmuctrl + - hisilicon,hi3660-sctrl + - hisilicon,hi3660-iomcu + - hisilicon,hi3670-crgctrl + - hisilicon,hi3670-pctrl + - hisilicon,hi3670-pmuctrl + - hisilicon,hi3670-sctrl + - hisilicon,hi3670-iomcu + - hisilicon,hi3670-media1-crg + - hisilicon,hi3670-media2-crg + - hisilicon,hi6220-acpu-sctrl + - const: syscon + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - '#clock-cells' + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/clock/hisilicon,hi6220-stub-clk.yaml b/Documentation/devicetree/bindings/clock/hisilicon,hi6220-stub-clk.yaml new file mode 100644 index 000000000000..4dd6a01bfd9d --- /dev/null +++ b/Documentation/devicetree/bindings/clock/hisilicon,hi6220-stub-clk.yaml @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/hisilicon,hi6220-stub-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Hisilicon Stub Clock Controller + +maintainers: + - Wei Xu + +description: > + Each clock is assigned an identifier and client nodes use this identifier + to specify the clock which they consume. + + All these identifiers can be found in: + dt-bindings/clock/hi3660-clock.h. + dt-bindings/clock/hi6220-clock.h. + +properties: + compatible: + enum: + - hisilicon,hi3660-stub-clk + - hisilicon,hi6220-stub-clk + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + hisilicon,hi6220-clk-sram: + description: + syscon managing the SoC internal SRAM; driver needs the SRAM to pass + parameters for frequency change. + $ref: /schemas/types.yaml#/definitions/phandle + + mboxes: + maxItems: 1 + + mbox-names: + const: mbox-tx + +required: + - compatible + - '#clock-cells' + - mboxes + +additionalProperties: false From 40e5d379cc19fa7fa477414087df5e915d5e843f Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Mon, 12 Oct 2026 15:18:59 +0200 Subject: [PATCH 166/168] clk: stm32: fix clock array size for STM32MP21 STM32MP21_LAST_CLK is used as the number of entries of the onecell clk_hw array allocated in stm32_rcc_clock_init(), and as the bound of the clock IDs it can hold. It was wrongly set to CK_SCMI_KER_ETR (112), which belongs to the SCMI clock ID range, whereas the RCC clock IDs go up to CK_KER_STM (289). As a result the array is too small, and registering a clock whose ID is greater than 111 writes past the end of the allocated clk_hw array (hws[cfg_clock->id] = hw), and consumers requesting such a clock get rejected or read out of bounds. Define STM32MP21_LAST_CLK as CK_KER_STM + 1 so that the array covers all the RCC clock IDs. No device tree node uses the STM32MP21 RCC driver yet, so there is no need to backport this patch to stable kernels. Fixes: 37ae8501cdb0 ("clk: stm32: introduce clocks for STM32MP21 platform") Signed-off-by: Gabriel Fernandez Link: https://patch.msgid.link/20261012131859.215240-1-gabriel.fernandez@foss.st.com Signed-off-by: Jerome Brunet Signed-off-by: Brian Masney --- drivers/clk/stm32/clk-stm32mp21.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/stm32/clk-stm32mp21.c b/drivers/clk/stm32/clk-stm32mp21.c index bdb17419908c..961a228d8c64 100644 --- a/drivers/clk/stm32/clk-stm32mp21.c +++ b/drivers/clk/stm32/clk-stm32mp21.c @@ -17,8 +17,8 @@ #include #include -/* Max clock binding value */ -#define STM32MP21_LAST_CLK CK_SCMI_KER_ETR +/* Number of RCC clock bindings (highest RCC clock ID + 1) */ +#define STM32MP21_LAST_CLK (CK_KER_STM + 1) /* Clock security definition */ #define SECF_NONE -1 From e9e6b4dc303dff637ef725aca4f4968d7600798b Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 14 Oct 2026 18:11:53 +0200 Subject: [PATCH 167/168] clk: cdce925: Size the PLL child name buffer for any int The PLL child node name is built from "PLL%d" in a 6 byte stack buffer. The PLL index is bounded by the chip's num_plls, at most 4, but GCC cannot see that bound and, with W=1, warns that the formatted string may not fit. Make the buffer large enough to hold any int and use snprintf() with sizeof() so the size stays tied to the declaration. Fixes: 19fbbbbcd3a3 ("Add TI CDCE925 I2C controlled clock synthesizer driver") Signed-off-by: Jerome Brunet Link: https://patch.msgid.link/20261014-cdce925-truncate-child-name-v1-1-00136be00c49@baylibre.com Signed-off-by: Brian Masney --- drivers/clk/clk-cdce925.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index 4d49cc1659c0..56b69d4fe4c2 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -625,7 +625,12 @@ static int cdce925_probe(struct i2c_client *client) int i; int err; struct device_node *np_output; - char child_name[6]; + /* + * The PLL number isn't a compile time constant so GCC can't infer + * the number. Make the stack buffer large enough to hold any int + * so Wformat-truncation does not complain. + */ + char child_name[15]; struct regmap_config config = { .name = "configuration0", .reg_bits = 8, @@ -697,7 +702,7 @@ static int cdce925_probe(struct i2c_client *client) dev_err(&client->dev, "Failed register PLL %d\n", i); goto error; } - sprintf(child_name, "PLL%d", i+1); + snprintf(child_name, sizeof(child_name), "PLL%d", i + 1); np_output = of_get_child_by_name(node, child_name); if (!np_output) continue; From ce8c0f4b8306e01b058859bb43425613cfd1782b Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Fri, 4 Sep 2026 12:06:33 +0200 Subject: [PATCH 168/168] clk: imx: pll14xx: support spread spectrum clock generation Add support for spread spectrum clock (SSC) generation to the pll14xx driver. Tested on the video PLL of i.MX8MN and i.MX8MP based boards. Reviewed-by: Peng Fan Signed-off-by: Dario Binacchi Reviewed-by: Abel Vesa Acked-by: Abel Vesa Link: https://patch.msgid.link/20260904101243.412006-5-dario.binacchi@amarulasolutions.com Signed-off-by: Brian Masney --- drivers/clk/imx/clk-pll14xx.c | 103 ++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index 2f9e36f9e240..c6438144e507 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,8 @@ #define GNRL_CTL 0x0 #define DIV_CTL0 0x4 #define DIV_CTL1 0x8 +#define SSCG_CTRL 0xc + #define LOCK_STATUS BIT(31) #define LOCK_SEL_MASK BIT(29) #define CLKE_MASK BIT(11) @@ -33,6 +36,13 @@ #define KDIV_MASK GENMASK(15, 0) #define KDIV_MIN SHRT_MIN #define KDIV_MAX SHRT_MAX +#define SSCG_ENABLE BIT(31) +#define MFREQ_CTL_MASK GENMASK(19, 12) +#define MRAT_CTL_MASK GENMASK(9, 4) +#define SEL_PF_DOWN_SPREAD 0 +#define SEL_PF_UP_SPREAD 1 +#define SEL_PF_CENTER_SPREAD 2 +#define SEL_PF_MASK GENMASK(1, 0) #define LOCK_TIMEOUT_US 10000 @@ -44,6 +54,7 @@ struct clk_pll14xx { int rate_count; s16 delta_k; spinlock_t lock; + struct clk_spread_spectrum ss_conf; }; #define to_clk_pll14xx(_hw) container_of(_hw, struct clk_pll14xx, hw) @@ -366,6 +377,62 @@ static int clk_pll1416x_set_rate(struct clk_hw *hw, unsigned long drate, return 0; } +static void __clk_pll1443x_set_spread_spectrum(struct clk_hw *hw, + unsigned long parent_rate, + unsigned int pdiv, + unsigned int mdiv) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + struct clk_spread_spectrum *conf = &pll->ss_conf; + u32 sscg_ctrl, mfr, mrr, sel_pf; + + sscg_ctrl = readl_relaxed(pll->base + SSCG_CTRL); + sscg_ctrl &= ~(SSCG_ENABLE | MFREQ_CTL_MASK | MRAT_CTL_MASK | SEL_PF_MASK); + + switch (conf->method) { + case CLK_SPREAD_CENTER: + sel_pf = SEL_PF_CENTER_SPREAD; + break; + case CLK_SPREAD_UP: + sel_pf = SEL_PF_UP_SPREAD; + break; + case CLK_SPREAD_DOWN: + sel_pf = SEL_PF_DOWN_SPREAD; + break; + default: + /* No spread: disable modulation and clear any stale state */ + goto out; + } + + if (!conf->modfreq_hz || !parent_rate || !pdiv) + goto out; + + mfr = div64_u64(parent_rate, (u64)conf->modfreq_hz * pdiv * BIT(5)); + if (!mfr || mfr > FIELD_MAX(MFREQ_CTL_MASK)) { + pr_warn_ratelimited("%s: SSC disabled, modulation frequency (%u Hz) out of range\n", + clk_hw_get_name(hw), conf->modfreq_hz); + goto out; + } + + /* + * No overflow: the core limits spread_bp to 10000 and mdiv is a 10-bit + * field, so the product is at most 10000 * 1023 * 64 < 2^32. + */ + mrr = (conf->spread_bp * mdiv * BIT(6)) / (10000 * mfr); + if (!mrr || mrr > FIELD_MAX(MRAT_CTL_MASK)) { + pr_warn_ratelimited("%s: SSC disabled, spread (%u permyriad) out of range\n", + clk_hw_get_name(hw), conf->spread_bp); + goto out; + } + + sscg_ctrl |= SSCG_ENABLE | FIELD_PREP(MFREQ_CTL_MASK, mfr) | + FIELD_PREP(MRAT_CTL_MASK, mrr) | + FIELD_PREP(SEL_PF_MASK, sel_pf); + +out: + writel_relaxed(sscg_ctrl, pll->base + SSCG_CTRL); +} + static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate, unsigned long prate) { @@ -390,6 +457,9 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), pll->base + DIV_CTL1); + __clk_pll1443x_set_spread_spectrum(hw, prate, rate.pdiv, + rate.mdiv); + spin_unlock_irqrestore(&pll->lock, flags); return 0; @@ -411,6 +481,8 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate, writel_relaxed(FIELD_PREP(KDIV_MASK, rate.kdiv), pll->base + DIV_CTL1); + __clk_pll1443x_set_spread_spectrum(hw, prate, rate.pdiv, rate.mdiv); + spin_unlock_irqrestore(&pll->lock, flags); /* @@ -437,6 +509,36 @@ static int clk_pll1443x_set_rate(struct clk_hw *hw, unsigned long drate, return 0; } +static int clk_pll1443x_set_spread_spectrum(struct clk_hw *hw, + const struct clk_spread_spectrum *ss_conf) +{ + struct clk_pll14xx *pll = to_clk_pll14xx(hw); + struct clk_hw *parent = clk_hw_get_parent(hw); + unsigned long parent_rate = parent ? clk_hw_get_rate(parent) : 0; + unsigned long flags; + u32 div_ctl0; + + spin_lock_irqsave(&pll->lock, flags); + + pll->ss_conf = *ss_conf; + + /* + * Apply the configuration to the hardware right away, using the + * current PLL dividers: the clock framework does not call set_rate() + * if the requested rate is unchanged, so relying on it would leave + * the SSC settings unapplied when the PLL is already at the target + * rate (e.g. configured by the bootloader). + */ + div_ctl0 = readl_relaxed(pll->base + DIV_CTL0); + __clk_pll1443x_set_spread_spectrum(hw, parent_rate, + FIELD_GET(PDIV_MASK, div_ctl0), + FIELD_GET(MDIV_MASK, div_ctl0)); + + spin_unlock_irqrestore(&pll->lock, flags); + + return 0; +} + static int clk_pll14xx_prepare(struct clk_hw *hw) { struct clk_pll14xx *pll = to_clk_pll14xx(hw); @@ -509,6 +611,7 @@ static const struct clk_ops clk_pll1443x_ops = { .recalc_rate = clk_pll14xx_recalc_rate, .determine_rate = clk_pll1443x_determine_rate, .set_rate = clk_pll1443x_set_rate, + .set_spread_spectrum = clk_pll1443x_set_spread_spectrum, }; struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,