From 431f6cce118d22c98a65d20e9b512ecc31fc1c8e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 28 Oct 2025 14:58:57 +0100 Subject: [PATCH 1/8] firmware: scmi: Fix up code comments Fix multiple instances of copy-paste errors. Fill in missing headers for CLOCK_GET_PERMISSIONS message and response. Signed-off-by: Marek Vasut Reviewed-by: Alice Guo Signed-off-by: Peng Fan --- include/scmi_protocols.h | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h index bb74a57f79a..bcd8e671149 100644 --- a/include/scmi_protocols.h +++ b/include/scmi_protocols.h @@ -399,7 +399,7 @@ int scmi_generic_protocol_version(struct udevice *dev, int scmi_base_protocol_version(struct udevice *dev, u32 *version); /** - * scmi_protocol_attrs - get protocol attributes + * scmi_base_protocol_attrs - get protocol attributes * @dev: SCMI protocol device * @num_agents: Number of SCMI agents * @num_protocols: Number of SCMI protocols @@ -414,7 +414,7 @@ int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents, u32 *num_protocols); /** - * scmi_protocol_message_attrs - get message-specific attributes + * scmi_base_protocol_message_attrs - get message-specific attributes * @dev: SCMI protocol device * @message_id: SCMI message ID * @attributes: Message-specific attributes @@ -754,7 +754,7 @@ enum scmi_clock_message_id { #define SCMI_CLOCK_NAME_LENGTH_MAX 16 /** - * struct scmi_clk_get_nb_out - Response for SCMI_PROTOCOL_ATTRIBUTES command + * struct scmi_clk_protocol_attr_out - Response for SCMI_PROTOCOL_ATTRIBUTES command * @status: SCMI command status * @attributes: Attributes of the clock protocol, mainly number of clocks exposed */ @@ -772,7 +772,7 @@ struct scmi_clk_attribute_in { }; /** - * struct scmi_clk_get_nb_out - Response payload for SCMI_CLOCK_ATTRIBUTES command + * struct scmi_clk_attribute_out - Response payload for SCMI_CLOCK_ATTRIBUTES command * @status: SCMI command status * @attributes: clock attributes * @clock_name: name of the clock @@ -785,7 +785,7 @@ struct scmi_clk_attribute_out { }; /** - * struct scmi_clk_get_nb_out_v2 - Response payload for SCMI_CLOCK_ATTRIBUTES command + * struct scmi_clk_attribute_out_v2 - Response payload for SCMI_CLOCK_ATTRIBUTES command * Clock management Protocol 2.0 * @status: SCMI command status * @attributes: clock attributes @@ -818,7 +818,7 @@ struct scmi_clk_state_out { }; /** - * struct scmi_clk_state_in - Message payload for CLOCK_RATE_GET command + * struct scmi_clk_rate_get_in - Message payload for CLOCK_RATE_GET command * @clock_id: SCMI clock ID * @attributes: Attributes of the targets clock state */ @@ -839,7 +839,7 @@ struct scmi_clk_rate_get_out { }; /** - * struct scmi_clk_state_in - Message payload for CLOCK_RATE_SET command + * struct scmi_clk_rate_set_in - Message payload for CLOCK_RATE_SET command * @flags: Flags for the clock rate set request * @clock_id: SCMI clock ID * @rate_lsb: 32bit LSB of the clock rate in Hertz @@ -861,7 +861,7 @@ struct scmi_clk_rate_set_out { }; /** - * struct scmi_clk_parent_state_in - Message payload for CLOCK_PARENT_SET command + * struct scmi_clk_parent_set_in - Message payload for CLOCK_PARENT_SET command * @clock_id: SCMI clock ID * @parent_clk: SCMI clock ID */ @@ -879,6 +879,7 @@ struct scmi_clk_parent_set_out { }; /** + * struct scmi_clk_get_permissions_in - Message payload for CLOCK_GET_PERMISSIONS command * @clock_id: Identifier for the clock device. */ struct scmi_clk_get_permissions_in { @@ -886,6 +887,7 @@ struct scmi_clk_get_permissions_in { }; /** + * struct scmi_clk_get_permissions_out - Response payload for CLOCK_GET_PERMISSIONS command * @status: Negative 32-bit integers are used to return error status codes. * @permissions: Bit[31] Clock state control, Bit[30] Clock parent control, * Bit[29] Clock rate control, Bits[28:0] Reserved, must be zero. @@ -1082,7 +1084,7 @@ struct scmi_pin_config { }; /** - * struct scmi_pad_config_set_in - Message payload for PAD_CONFIG_SET command + * struct scmi_pinctrl_config_set_in - Message payload for PAD_CONFIG_SET command * @identifier: Identifier for the pin or group. * @function_id: Identifier for the function selected to be enabled * for the selected pin or group. This field is set to From a5a0134570c88cd49a6fc97256764cb7fbb93dff Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 25 Oct 2025 23:35:09 +0200 Subject: [PATCH 2/8] firmware: scmi: Drop mmu_set_region_dcache_behaviour() misuse MMU region cache behavior configuration for SCMI/SMT mailboxes is platform specific. Even on ARM systems, the mailbox memory may not even be located in any cacheable MMU region and may instead reside in some SRAM. Remove this non-generic cache behavior configuration code from generic code path. It is unlikely that any platform is affected by this change if it did configure its MMU regions correctly on start up. Platforms which might be affected are i.MX94/95 and STM32MP. Fixes: 240720e9052f ("firmware: scmi: mailbox/smt agent device") Fixes: 2a3f161c8b16 ("scmi: correctly configure MMU for SCMI buffer") Fixes: b2ae10970d40 ("firmware: scmi: use PAGE_SIZE alignment for ARM64") Signed-off-by: Marek Vasut Tested-by: Alice Guo Tested-by: Patrice Chotard Signed-off-by: Peng Fan --- drivers/firmware/scmi/smt.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c index 237871559f0..cd1c0801f72 100644 --- a/drivers/firmware/scmi/smt.c +++ b/drivers/firmware/scmi/smt.c @@ -61,20 +61,6 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt) if (device_is_compatible(dev, "arm,scmi") && ofnode_has_property(dev_ofnode(dev), "mboxes")) scmi_smt_enable_intr(smt, true); -#ifdef CONFIG_ARM - if (dcache_status()) { - u32 align_size; - - if (IS_ENABLED(CONFIG_ARM64)) - align_size = PAGE_SIZE; - else - align_size = MMU_SECTION_SIZE; - - mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, align_size), - ALIGN(smt->size, align_size), DCACHE_OFF); - } -#endif - return 0; } From 0619cb32030b1d78379f3181d3e1103bb86124fb Mon Sep 17 00:00:00 2001 From: Vinh Nguyen Date: Wed, 5 Nov 2025 04:42:26 +0100 Subject: [PATCH 3/8] firmware: scmi: Add clock v3.2 CONFIG_SET support SCMI v3.2 introduces a new clock CONFIG_SET message format that can optionally carry also OEM specific configuration values beside the usual clock enable/disable requests. Add support to use such new format when talking to a v3.2 compliant SCMI platform. Support existing enable/disable operations across different clock protocol versions: this patch still does not add protocol operations to support the new OEM specific optional configuration capabilities. No functional change for the SCMI drivers users of the related enable and disable clock operations. [Marek: Remodel after Linux e49e314a2cf7 ("firmware: arm_scmi: Add clock v3.2 CONFIG_SET support") Support both old < 2.1 and new >= 2.1 protocol versions. Update commit message based on Linux one] Signed-off-by: Vinh Nguyen Signed-off-by: Marek Vasut Reviewed-by: Alice Guo Signed-off-by: Peng Fan --- arch/arm/mach-imx/imx9/scmi/clock_scmi.c | 2 +- drivers/clk/clk_scmi.c | 23 +++++++++++++++++----- drivers/firmware/scmi/sandbox-scmi_agent.c | 4 ++-- include/scmi_protocols.h | 17 ++++++++++++++-- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-imx/imx9/scmi/clock_scmi.c b/arch/arm/mach-imx/imx9/scmi/clock_scmi.c index b6be20ec674..9030dbf600d 100644 --- a/arch/arm/mach-imx/imx9/scmi/clock_scmi.c +++ b/arch/arm/mach-imx/imx9/scmi/clock_scmi.c @@ -10,7 +10,7 @@ int imx_clk_scmi_enable(u32 clock_id, bool enable) { - struct scmi_clk_state_in in = { + struct scmi_clk_state_in_v1 in = { .clock_id = clock_id, .attributes = !!enable, }; diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index a7d89f32cd7..54378b4e1ec 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -134,17 +135,28 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, static int scmi_clk_gate(struct clk *clk, int enable) { - struct scmi_clk_state_in in = { + struct scmi_clock_priv *priv = dev_get_parent_priv(clk->dev); + struct scmi_clk_state_in_v1 in_v1 = { + .clock_id = clk_get_id(clk), + .attributes = enable, + }; + /* Valid only from SCMI clock v2.1 */ + struct scmi_clk_state_in_v2 in_v2 = { .clock_id = clk_get_id(clk), .attributes = enable, }; struct scmi_clk_state_out out; - struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, - SCMI_CLOCK_CONFIG_SET, - in, out); + struct scmi_msg msg_v1 = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_CONFIG_SET, + in_v1, out); + struct scmi_msg msg_v2 = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_CONFIG_SET, + in_v2, out); int ret; - ret = devm_scmi_process_msg(clk->dev, &msg); + ret = devm_scmi_process_msg(clk->dev, + (priv->version < CLOCK_PROTOCOL_VERSION_2_1) ? + &msg_v1 : &msg_v2); if (ret) return ret; @@ -319,6 +331,7 @@ static int scmi_clk_probe(struct udevice *dev) } dev_clk_dm(dev, i, &clk_scmi->clk); + dev_set_parent_priv(clk_scmi->clk.dev, priv); if (CLK_HAS_RESTRICTIONS(attributes)) { u32 perm; diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 74a87832dcb..5b242a039c2 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -828,7 +828,7 @@ static int sandbox_scmi_clock_rate_get(struct udevice *dev, static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) { - struct scmi_clk_state_in *in = NULL; + struct scmi_clk_state_in_v1 *in = NULL; struct scmi_clk_state_out *out = NULL; struct sandbox_scmi_clk *clk_state = NULL; @@ -836,7 +836,7 @@ static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) !msg->out_msg || msg->out_msg_sz < sizeof(*out)) return -EINVAL; - in = (struct scmi_clk_state_in *)msg->in_msg; + in = (struct scmi_clk_state_in_v1 *)msg->in_msg; out = (struct scmi_clk_state_out *)msg->out_msg; clk_state = get_scmi_clk_state(in->clock_id); diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h index bcd8e671149..ecab021b472 100644 --- a/include/scmi_protocols.h +++ b/include/scmi_protocols.h @@ -733,6 +733,7 @@ int scmi_pwd_name_get(struct udevice *dev, u32 domain_id, u8 **name); /* * SCMI Clock Protocol */ +#define CLOCK_PROTOCOL_VERSION_2_1 0x20001 #define CLOCK_PROTOCOL_VERSION_3_0 0x30000 enum scmi_clock_message_id { @@ -800,15 +801,27 @@ struct scmi_clk_attribute_out_v2 { }; /** - * struct scmi_clk_state_in - Message payload for CLOCK_CONFIG_SET command + * struct scmi_clk_state_in_v1 - Message payload for CLOCK_CONFIG_SET command for protocol < 2.1 * @clock_id: SCMI clock ID * @attributes: Attributes of the targets clock state */ -struct scmi_clk_state_in { +struct scmi_clk_state_in_v1 { u32 clock_id; u32 attributes; }; +/** + * struct scmi_clk_state_in_v2 - Message payload for CLOCK_CONFIG_SET command for protocol >= 2.1 + * @clock_id: SCMI clock ID + * @attributes: Attributes of the targets clock state + * @extended_config_val: Extended and OEM specific configuration + */ +struct scmi_clk_state_in_v2 { + u32 clock_id; + u32 attributes; + u32 extended_config_val; +}; + /** * struct scmi_clk_state_out - Response payload for CLOCK_CONFIG_SET command * @status: SCMI command status From 66cb830291b78389eb995960ee5e1460aedd7447 Mon Sep 17 00:00:00 2001 From: Kamlesh Gurudasani Date: Tue, 4 Nov 2025 16:49:30 +0530 Subject: [PATCH 4/8] clk: scmi: fix set_parent support when CCF is not being used When not using Common clock framework(CCF), calls to scmi_clk_set_parent returns -ENOTSUPP, which should not be the case. Fix that. Fixes: 15fdfef6642c ("clk: scmi: check the clock state/parent/rate control permissions) Signed-off-by: Kamlesh Gurudasani Reviewed-by: Dhruva Gole Signed-off-by: Peng Fan --- drivers/clk/clk_scmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index 54378b4e1ec..37e349b9c78 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -377,7 +377,7 @@ static int scmi_clk_set_parent(struct clk *clk, struct clk *parent) int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) - return -ENOTSUPP; + return __scmi_clk_set_parent(clk, parent); ret = clk_get_by_id(clk->id, &c); if (ret) From ef52f697f281a88f5fa63608d50838b197cc4e9d Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 9 Nov 2025 02:35:06 +0100 Subject: [PATCH 5/8] clk: scmi: Bulk allocate all sub-driver instance data Allocate all sub-driver instance data at once. The amount of data that have to be allocated is known up front, so is the size of the data, so there is no need to call malloc() in a loop, mallocate all data at once. The upside is, less heap fragmentation and fewer malloc() calls overall, and a faster boot time. The downside is, if some of the clock fail to register, then the clock driver cannot free parts of the bulk allocated sub-driver instance data. Such a failure can only occur if clk_register() were to fail, and if that happens, the system has more significant problems. Worse, if a core clock driver fails to probe, the system has even bigger problem. Reviewed-by: Peng Fan Signed-off-by: Marek Vasut Signed-off-by: Peng Fan --- drivers/clk/clk_scmi.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index 37e349b9c78..548bbfe14de 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -283,7 +283,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) static int scmi_clk_probe(struct udevice *dev) { - struct clk_scmi *clk_scmi; + struct clk_scmi *clk_scmi_bulk, *clk_scmi; struct scmi_clock_priv *priv = dev_get_priv(dev); size_t num_clocks, i; int ret; @@ -312,20 +312,23 @@ static int scmi_clk_probe(struct udevice *dev) return ret; } + clk_scmi_bulk = kzalloc(num_clocks * sizeof(*clk_scmi), GFP_KERNEL); + if (!clk_scmi_bulk) + return -ENOMEM; + for (i = 0; i < num_clocks; i++) { char *clock_name; u32 attributes; if (!scmi_clk_get_attibute(dev, i, &clock_name, &attributes)) { - clk_scmi = kzalloc(sizeof(*clk_scmi), GFP_KERNEL); - if (!clk_scmi || !clock_name) + clk_scmi = clk_scmi_bulk + i; + if (!clock_name) ret = -ENOMEM; else ret = clk_register(&clk_scmi->clk, dev->driver->name, clock_name, dev->name); if (ret) { - free(clk_scmi); free(clock_name); return ret; } From 21bfe6a2911725aab6e8067408b0a265b2f35c96 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 9 Nov 2025 02:35:07 +0100 Subject: [PATCH 6/8] clk: scmi: Factor out clock control flags resolution Pull clock control flags resolution into dedicated function and call it from each site that does access clock control flags. No functional change. This is a preparatory patch for deferred issue of SCMI_CLOCK_ATTRIBUTES. Reviewed-by: Peng Fan Signed-off-by: Marek Vasut Signed-off-by: Peng Fan --- drivers/clk/clk_scmi.c | 51 +++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index 548bbfe14de..1a6a6ae464c 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -163,22 +163,36 @@ static int scmi_clk_gate(struct clk *clk, int enable) return scmi_to_linux_errno(out.status); } -static int scmi_clk_enable(struct clk *clk) +static int scmi_clk_get_ctrl_flags(struct clk *clk, u32 *ctrl_flags) { struct clk_scmi *clkscmi; struct clk *c; int ret; - if (!CONFIG_IS_ENABLED(CLK_CCF)) - return scmi_clk_gate(clk, 1); - ret = clk_get_by_id(clk->id, &c); if (ret) return ret; clkscmi = container_of(c, struct clk_scmi, clk); - if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL) + *ctrl_flags = clkscmi->ctrl_flags; + + return 0; +} + +static int scmi_clk_enable(struct clk *clk) +{ + u32 ctrl_flags; + int ret; + + if (!CONFIG_IS_ENABLED(CLK_CCF)) + return scmi_clk_gate(clk, 1); + + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); + if (ret) + return ret; + + if (ctrl_flags & SUPPORT_CLK_STAT_CONTROL) return scmi_clk_gate(clk, 1); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ @@ -188,20 +202,17 @@ static int scmi_clk_enable(struct clk *clk) static int scmi_clk_disable(struct clk *clk) { - struct clk_scmi *clkscmi; - struct clk *c; + u32 ctrl_flags; int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) return scmi_clk_gate(clk, 0); - ret = clk_get_by_id(clk->id, &c); + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); if (ret) return ret; - clkscmi = container_of(c, struct clk_scmi, clk); - - if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL) + if (ctrl_flags & SUPPORT_CLK_STAT_CONTROL) return scmi_clk_gate(clk, 0); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ @@ -259,20 +270,17 @@ static ulong __scmi_clk_set_rate(struct clk *clk, ulong rate) static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) { - struct clk_scmi *clkscmi; - struct clk *c; + u32 ctrl_flags; int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) return __scmi_clk_set_rate(clk, rate); - ret = clk_get_by_id(clk->id, &c); + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); if (ret) return ret; - clkscmi = container_of(c, struct clk_scmi, clk); - - if (clkscmi->ctrl_flags & SUPPORT_CLK_RATE_CONTROL) + if (ctrl_flags & SUPPORT_CLK_RATE_CONTROL) return __scmi_clk_set_rate(clk, rate); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ @@ -375,20 +383,17 @@ static int __scmi_clk_set_parent(struct clk *clk, struct clk *parent) static int scmi_clk_set_parent(struct clk *clk, struct clk *parent) { - struct clk_scmi *clkscmi; - struct clk *c; + u32 ctrl_flags; int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) return __scmi_clk_set_parent(clk, parent); - ret = clk_get_by_id(clk->id, &c); + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); if (ret) return ret; - clkscmi = container_of(c, struct clk_scmi, clk); - - if (clkscmi->ctrl_flags & SUPPORT_CLK_PARENT_CONTROL) + if (ctrl_flags & SUPPORT_CLK_PARENT_CONTROL) return __scmi_clk_set_parent(clk, parent); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ From fdb1bffe2827e6107288c57e1f2e86956fd1a2bc Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 9 Nov 2025 02:35:08 +0100 Subject: [PATCH 7/8] clk: scmi: Postpone clock name resolution The clock names are retrived via SCMI_CLOCK_ATTRIBUTES, called for each clock ID. This may take a lot of time to complete and is not strictly necessary. Register each clock as "scmi-%zu" instead, and let the first call of SCMI_CLOCK_ATTRIBUTES fill in the actual clock name. This has a side effect, which can be considered both an upside and also a downside. Unused clock are never renamed and retain their placeholder "scmi-%zu" name, which avoids empty clock names for nameless SCMI clock, and avoids the name resolution and improves boot time. But for those SCMI clock which do have name, that name is not listed until the clock are used. This is a preparatory patch for deferred issue of SCMI_CLOCK_ATTRIBUTES. Reviewed-by: Peng Fan Signed-off-by: Marek Vasut Signed-off-by: Peng Fan --- drivers/clk/clk_scmi.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index 1a6a6ae464c..9bb41eddbba 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -17,6 +17,7 @@ struct clk_scmi { struct clk clk; + char name[SCMI_CLOCK_NAME_LENGTH_MAX]; u32 ctrl_flags; }; @@ -325,25 +326,21 @@ static int scmi_clk_probe(struct udevice *dev) return -ENOMEM; for (i = 0; i < num_clocks; i++) { - char *clock_name; + clk_scmi = clk_scmi_bulk + i; + char *clock_name = clk_scmi->name; u32 attributes; + snprintf(clock_name, SCMI_CLOCK_NAME_LENGTH_MAX, "scmi-%zu", i); + + ret = clk_register(&clk_scmi->clk, dev->driver->name, + clock_name, dev->name); + if (ret) + return ret; + + dev_clk_dm(dev, i, &clk_scmi->clk); + dev_set_parent_priv(clk_scmi->clk.dev, priv); + if (!scmi_clk_get_attibute(dev, i, &clock_name, &attributes)) { - clk_scmi = clk_scmi_bulk + i; - if (!clock_name) - ret = -ENOMEM; - else - ret = clk_register(&clk_scmi->clk, dev->driver->name, - clock_name, dev->name); - - if (ret) { - free(clock_name); - return ret; - } - - dev_clk_dm(dev, i, &clk_scmi->clk); - dev_set_parent_priv(clk_scmi->clk.dev, priv); - if (CLK_HAS_RESTRICTIONS(attributes)) { u32 perm; From 3547e315c188cdbb24312543d67d132b113eb01e Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sun, 9 Nov 2025 02:35:09 +0100 Subject: [PATCH 8/8] clk: scmi: Defer issue of SCMI_CLOCK_ATTRIBUTES Instead of resolving clock control flags using SCMI_CLOCK_ATTRIBUTES during probe for each and every clock, resolve the clock control flags using SCMI_CLOCK_ATTRIBUTES when the clock control flags are first used. Because most clock are never used by U-Boot, this allows reducing the amount of SCMI_CLOCK_ATTRIBUTES considerably, and this improve probe time of the scmi clock driver and U-Boot start up time. On Renesas X5H, with 1700+ SCMI clock, the boot time improved by 1.7s . Reviewed-by: Peng Fan Signed-off-by: Marek Vasut Signed-off-by: Peng Fan --- drivers/clk/clk_scmi.c | 52 +++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index 9bb41eddbba..683ac822a01 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -19,6 +19,7 @@ struct clk_scmi { struct clk clk; char name[SCMI_CLOCK_NAME_LENGTH_MAX]; u32 ctrl_flags; + bool attrs_resolved; }; struct scmi_clock_priv { @@ -86,7 +87,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) return 0; } -static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, +static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char *name, u32 *attr) { struct scmi_clock_priv *priv = dev_get_priv(dev); @@ -110,7 +111,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, if (ret) return ret; - *name = strdup(out.clock_name); + strncpy(name, out.clock_name, SCMI_CLOCK_NAME_LENGTH_MAX); *attr = out.attributes; } else { struct scmi_clk_attribute_out out; @@ -127,7 +128,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, if (ret) return ret; - *name = strdup(out.clock_name); + strncpy(name, out.clock_name, SCMI_CLOCK_NAME_LENGTH_MAX); *attr = out.attributes; } @@ -167,6 +168,8 @@ static int scmi_clk_gate(struct clk *clk, int enable) static int scmi_clk_get_ctrl_flags(struct clk *clk, u32 *ctrl_flags) { struct clk_scmi *clkscmi; + struct udevice *dev; + u32 attributes; struct clk *c; int ret; @@ -174,8 +177,35 @@ static int scmi_clk_get_ctrl_flags(struct clk *clk, u32 *ctrl_flags) if (ret) return ret; + dev = c->dev->parent; + clkscmi = container_of(c, struct clk_scmi, clk); + if (!clkscmi->attrs_resolved) { + char name[SCMI_CLOCK_NAME_LENGTH_MAX]; + ret = scmi_clk_get_attibute(dev, clk->id & CLK_ID_MSK, + name, &attributes); + if (ret) + return ret; + + strncpy(clkscmi->name, name, SCMI_CLOCK_NAME_LENGTH_MAX); + if (CLK_HAS_RESTRICTIONS(attributes)) { + u32 perm; + + ret = scmi_clk_get_permissions(dev, clk->id & CLK_ID_MSK, &perm); + if (ret < 0) + clkscmi->ctrl_flags = 0; + else + clkscmi->ctrl_flags = perm; + } else { + clkscmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL | + SUPPORT_CLK_PARENT_CONTROL | + SUPPORT_CLK_RATE_CONTROL; + } + + clkscmi->attrs_resolved = true; + } + *ctrl_flags = clkscmi->ctrl_flags; return 0; @@ -328,7 +358,6 @@ static int scmi_clk_probe(struct udevice *dev) for (i = 0; i < num_clocks; i++) { clk_scmi = clk_scmi_bulk + i; char *clock_name = clk_scmi->name; - u32 attributes; snprintf(clock_name, SCMI_CLOCK_NAME_LENGTH_MAX, "scmi-%zu", i); @@ -339,21 +368,6 @@ static int scmi_clk_probe(struct udevice *dev) dev_clk_dm(dev, i, &clk_scmi->clk); dev_set_parent_priv(clk_scmi->clk.dev, priv); - - if (!scmi_clk_get_attibute(dev, i, &clock_name, &attributes)) { - if (CLK_HAS_RESTRICTIONS(attributes)) { - u32 perm; - - ret = scmi_clk_get_permissions(dev, i, &perm); - if (ret < 0) - clk_scmi->ctrl_flags = 0; - else - clk_scmi->ctrl_flags = perm; - } else { - clk_scmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL | SUPPORT_CLK_PARENT_CONTROL | - SUPPORT_CLK_RATE_CONTROL; - } - } } return 0;