On Tue, Nov 21, 2023 at 02:05:42AM +0000, Kuninori Morimoto wrote: > Some board might use Linux and another OS in the same time. In such > case, current Linux will stop necessary module clock when booting > which is not used on Linux side, but is used on another OS side. > > To avoid such situation, renesas-cpg-mssr try to find > status = "reserved" devices (A), and add CLK_IGNORE_UNUSED flag to its > <&cgp CPG_MOD xxx> clock (B). > > Table 2.4: Values for status property > https://github.com/devicetree-org/devicetree-specification/releases/download/v0.4/devicetree-specification-v0.4.pdf > > "reserved" > Indicates that the device is operational, but should not be > used. Typically this is used for devices that are controlled > by another software component, such as platform firmware. > > ex) > scif5: serial@e6f30000 { > ... > (B) clocks = <&cpg CPG_MOD 202>, > <&cpg CPG_CORE R8A7795_CLK_S3D1>, > <&scif_clk>; > ... > (A) status = "reserved"; > }; > > Cc: Aymeric Aillet <aymeric.aillet@xxxxxxx> > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@xxxxxxxxxxx> > Tested-by: Yusuke Goda <yusuke.goda.sx@xxxxxxxxxxx> > --- > drivers/clk/renesas/renesas-cpg-mssr.c | 118 +++++++++++++++++++++++-- > 1 file changed, 109 insertions(+), 9 deletions(-) > > diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c > index cb80d1bf6c7c..26098b7f4323 100644 > --- a/drivers/clk/renesas/renesas-cpg-mssr.c > +++ b/drivers/clk/renesas/renesas-cpg-mssr.c > @@ -142,6 +142,8 @@ static const u16 srstclr_for_gen4[] = { > * @reset_clear_regs: Pointer to reset clearing registers array > * @smstpcr_saved: [].mask: Mask of SMSTPCR[] bits under our control > * [].val: Saved values of SMSTPCR[] > + * @reserved_ids: Temporary used, reserved id list > + * @num_reserved_ids: Temporary used, number of reserved id list > * @clks: Array containing all Core and Module Clocks > */ > struct cpg_mssr_priv { > @@ -168,6 +170,9 @@ struct cpg_mssr_priv { > u32 val; > } smstpcr_saved[ARRAY_SIZE(mstpsr_for_gen4)]; > > + unsigned int *reserved_ids; > + unsigned int num_reserved_ids; > + > struct clk *clks[]; > }; > > @@ -453,6 +458,19 @@ static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod, > break; > } > > + /* > + * Ignore reserved device. > + * see > + * cpg_mssr_reserved_init() > + */ > + for (i = 0; i < priv->num_reserved_ids; i++) { > + if (id == priv->reserved_ids[i]) { > + dev_info(dev, "Ignore Linux non-assigned mod (%s)\n", mod->name); > + init.flags |= CLK_IGNORE_UNUSED; > + break; > + } > + } > + > clk = clk_register(NULL, &clock->hw); > if (IS_ERR(clk)) > goto fail; > @@ -949,6 +967,75 @@ static const struct dev_pm_ops cpg_mssr_pm = { > #define DEV_PM_OPS NULL > #endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */ > > +static void __init cpg_mssr_reserved_exit(struct cpg_mssr_priv *priv) > +{ > + kfree(priv->reserved_ids); > +} > + > +static int __init cpg_mssr_reserved_init(struct cpg_mssr_priv *priv, > + const struct cpg_mssr_info *info) > +{ > + struct device_node *root = of_find_node_by_path("/soc"); 'root' is '/', so I find this slightly confusing. > + struct device_node *node = NULL; > + struct of_phandle_args clkspec; > + unsigned int *ids = NULL; > + unsigned int num = 0; > + > + /* > + * Because cpg_mssr_info has .num_hw_mod_clks which indicates number of all Module Clocks, > + * and clk_disable_unused() will disable all unused clocks, the device which is assigned to > + * non-Linux system will be disabled when Linux was booted. > + * > + * To avoid such situation, renesas-cpg-mssr assumes the device which has > + * status = "reserved" is assigned to non-Linux system, and add CLK_IGNORE_UNUSED flag > + * to its clocks if it was CPG_MOD. > + * see also > + * cpg_mssr_register_mod_clk() > + * > + * scif5: serial@e6f30000 { > + * ... > + * => clocks = <&cpg CPG_MOD 202>, > + * <&cpg CPG_CORE R8A7795_CLK_S3D1>, > + * <&scif_clk>; > + * ... > + * status = "reserved"; > + * }; > + */ > + for_each_reserved_child_of_node(root, node) { Don't you really want to find all reserved nodes in the DT rather than just child nodes of a single node? > + unsigned int i = 0; > + > + while (!of_parse_phandle_with_args(node, "clocks", "#clock-cells", i++, &clkspec)) { of_for_each_phandle() > + > + of_node_put(clkspec.np); > + > + if (clkspec.np == priv->dev->of_node && > + clkspec.args[0] == CPG_MOD) { > + > + ids = krealloc_array(ids, (num + 1), sizeof(*ids), GFP_KERNEL); > + if (!ids) > + return -ENOMEM; > + > + ids[num] = info->num_total_core_clks + > + MOD_CLK_PACK(clkspec.args[1]); > + > + num++; > + } > + } > + }