Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

clk: renesas: cpg-mssr: Ignore all clocks assigned to non-Linux system

Some boards might use Linux and another OS at the same time. In such
case, currently, during booting, Linux will stop necessary module clocks
which are not used on the Linux side, but are used by another OS.

To avoid such situation, renesas-cpg-mssr tries to find
status = "reserved" devices (A), and adds 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@iot.bzh>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: Yusuke Goda <yusuke.goda.sx@renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Link: https://lore.kernel.org/r/878r4ygfap.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>

authored by

Kuninori Morimoto and committed by
Geert Uytterhoeven
6aa17547 28c5d4e4

+104 -7
+104 -7
drivers/clk/renesas/renesas-cpg-mssr.c
··· 142 142 * @reset_clear_regs: Pointer to reset clearing registers array 143 143 * @smstpcr_saved: [].mask: Mask of SMSTPCR[] bits under our control 144 144 * [].val: Saved values of SMSTPCR[] 145 + * @reserved_ids: Temporary used, reserved id list 146 + * @num_reserved_ids: Temporary used, number of reserved id list 145 147 * @clks: Array containing all Core and Module Clocks 146 148 */ 147 149 struct cpg_mssr_priv { ··· 169 167 u32 mask; 170 168 u32 val; 171 169 } smstpcr_saved[ARRAY_SIZE(mstpsr_for_gen4)]; 170 + 171 + unsigned int *reserved_ids; 172 + unsigned int num_reserved_ids; 172 173 173 174 struct clk *clks[]; 174 175 }; ··· 457 452 init.flags |= CLK_IS_CRITICAL; 458 453 break; 459 454 } 455 + 456 + /* 457 + * Ignore reserved device. 458 + * see 459 + * cpg_mssr_reserved_init() 460 + */ 461 + for (i = 0; i < priv->num_reserved_ids; i++) { 462 + if (id == priv->reserved_ids[i]) { 463 + dev_info(dev, "Ignore Linux non-assigned mod (%s)\n", mod->name); 464 + init.flags |= CLK_IGNORE_UNUSED; 465 + break; 466 + } 467 + } 460 468 461 469 clk = clk_register(NULL, &clock->hw); 462 470 if (IS_ERR(clk)) ··· 967 949 #define DEV_PM_OPS NULL 968 950 #endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */ 969 951 952 + static void __init cpg_mssr_reserved_exit(struct cpg_mssr_priv *priv) 953 + { 954 + kfree(priv->reserved_ids); 955 + } 956 + 957 + static int __init cpg_mssr_reserved_init(struct cpg_mssr_priv *priv, 958 + const struct cpg_mssr_info *info) 959 + { 960 + struct device_node *soc = of_find_node_by_path("/soc"); 961 + struct device_node *node; 962 + uint32_t args[MAX_PHANDLE_ARGS]; 963 + unsigned int *ids = NULL; 964 + unsigned int num = 0; 965 + 966 + /* 967 + * Because clk_disable_unused() will disable all unused clocks, the device which is assigned 968 + * to a non-Linux system will be disabled when Linux is booted. 969 + * 970 + * To avoid such situation, renesas-cpg-mssr assumes the device which has 971 + * status = "reserved" is assigned to a non-Linux system, and adds CLK_IGNORE_UNUSED flag 972 + * to its CPG_MOD clocks. 973 + * see also 974 + * cpg_mssr_register_mod_clk() 975 + * 976 + * scif5: serial@e6f30000 { 977 + * ... 978 + * => clocks = <&cpg CPG_MOD 202>, 979 + * <&cpg CPG_CORE R8A7795_CLK_S3D1>, 980 + * <&scif_clk>; 981 + * ... 982 + * status = "reserved"; 983 + * }; 984 + */ 985 + for_each_reserved_child_of_node(soc, node) { 986 + struct of_phandle_iterator it; 987 + int rc; 988 + 989 + of_for_each_phandle(&it, rc, node, "clocks", "#clock-cells", -1) { 990 + int idx; 991 + 992 + if (it.node != priv->np) 993 + continue; 994 + 995 + if (of_phandle_iterator_args(&it, args, MAX_PHANDLE_ARGS) != 2) 996 + continue; 997 + 998 + if (args[0] != CPG_MOD) 999 + continue; 1000 + 1001 + ids = krealloc_array(ids, (num + 1), sizeof(*ids), GFP_KERNEL); 1002 + if (!ids) { 1003 + of_node_put(it.node); 1004 + return -ENOMEM; 1005 + } 1006 + 1007 + if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) 1008 + idx = MOD_CLK_PACK_10(args[1]); /* for DEF_MOD_STB() */ 1009 + else 1010 + idx = MOD_CLK_PACK(args[1]); /* for DEF_MOD() */ 1011 + 1012 + ids[num] = info->num_total_core_clks + idx; 1013 + 1014 + num++; 1015 + } 1016 + } 1017 + 1018 + priv->num_reserved_ids = num; 1019 + priv->reserved_ids = ids; 1020 + 1021 + return 0; 1022 + } 1023 + 970 1024 static int __init cpg_mssr_common_init(struct device *dev, 971 1025 struct device_node *np, 972 1026 const struct cpg_mssr_info *info) ··· 1093 1003 for (i = 0; i < nclks; i++) 1094 1004 priv->clks[i] = ERR_PTR(-ENOENT); 1095 1005 1096 - error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv); 1006 + error = cpg_mssr_reserved_init(priv, info); 1097 1007 if (error) 1098 1008 goto out_err; 1009 + 1010 + error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv); 1011 + if (error) 1012 + goto reserve_err; 1099 1013 1100 1014 cpg_mssr_priv = priv; 1101 1015 1102 1016 return 0; 1103 1017 1018 + reserve_err: 1019 + cpg_mssr_reserved_exit(priv); 1104 1020 out_err: 1105 1021 if (priv->base) 1106 1022 iounmap(priv->base); ··· 1166 1070 cpg_mssr_del_clk_provider, 1167 1071 np); 1168 1072 if (error) 1169 - return error; 1073 + goto reserve_exit; 1170 1074 1171 1075 error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks, 1172 1076 info->num_core_pm_clks); 1173 1077 if (error) 1174 - return error; 1078 + goto reserve_exit; 1175 1079 1176 1080 /* Reset Controller not supported for Standby Control SoCs */ 1177 1081 if (priv->reg_layout == CLK_REG_LAYOUT_RZ_A) 1178 - return 0; 1082 + goto reserve_exit; 1179 1083 1180 1084 error = cpg_mssr_reset_controller_register(priv); 1181 - if (error) 1182 - return error; 1183 1085 1184 - return 0; 1086 + reserve_exit: 1087 + cpg_mssr_reserved_exit(priv); 1088 + 1089 + return error; 1185 1090 } 1186 1091 1187 1092 static struct platform_driver cpg_mssr_driver = {