On 2/28/25 11:53 AM, Alice Guo (OSS) wrote:
From: Alice Guo <alice....@nxp.com>
Clock driver based on SCMI clock management protocol in Linux checks
clock state, parent and rate control permissions. To be consistent with
the kernel driver, add this check here.
When using common clock framework (CCF), use the clock signal ID to get
the clock registered by clk_register() in scmi_clk_probe(), and then
obatin the struct clk_scmi variable with container_of().
Signed-off-by: Alice Guo <alice....@nxp.com>
Signed-off-by: Ye Li <ye...@nxp.com>
Reviewed-by: Peng Fan <peng....@nxp.com>
---
drivers/clk/clk_scmi.c | 172 ++++++++++++++++++++++++++++++++++++++++++++---
include/scmi_protocols.h | 26 ++++++-
2 files changed, 187 insertions(+), 11 deletions(-)
diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c
index 84333cdd0c..4fce92d064 100644
--- a/drivers/clk/clk_scmi.c
+++ b/drivers/clk/clk_scmi.c
@@ -12,6 +12,56 @@
#include <asm/types.h>
#include <linux/clk-provider.h>
+struct clk_scmi {
+ struct clk clk;
+ u32 ctrl_flags;
+};
+
+static int scmi_clk_get_permissions(struct udevice *dev, int clkid, u32 *perm)
+{
+ u32 version;
+ int ret;
+
+ ret = scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_CLOCK,
&version);
+ if (ret) {
+ debug("get SCMI clock management protocol version failed\n");
+ return ret;
+ }
+
+ if (version < CLOCK_PROTOCOL_VERSION_3_0) {
+ debug("SCMI clock management protocol version is less than
3.0.\n");
+ return -EINVAL;
+ }
+
+ struct scmi_clk_get_permissions_in in = {
+ .clock_id = clkid,
+ };
+ struct scmi_clk_get_permissions_out out;
Variable declarations should be at the start of this function.
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_CLOCK,
+ .message_id = SCMI_CLOCK_GET_PERMISSIONS,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)&out,
+ .out_msg_sz = sizeof(out),
+ };
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret) {
+ debug("get SCMI clock management protocol permissions
failed\n");
Either use log_debug() or dev_dbg() or something which includes __func__
and __LINE__ too.
+ return ret;
+ }
+
+ ret = scmi_to_linux_errno(out.status);
+ if (ret < 0) {
+ debug("the status code of getting permissions: %d\n", ret);
+ return ret;
+ }
+
+ *perm = out.permissions;
+ return 0;
+}
+
static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
{
struct scmi_clk_protocol_attr_out out;
@@ -32,7 +82,8 @@ 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_clk_attribute_in in = {
.clock_id = clkid,
@@ -53,6 +104,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int
clkid, char **name)
return ret;
*name = strdup(out.clock_name);
+ *attr = out.attributes;
return 0;
}
@@ -78,11 +130,49 @@ static int scmi_clk_gate(struct clk *clk, int enable)
static int scmi_clk_enable(struct clk *clk)
{
+ struct clk_scmi *clkscmi;
+ struct clk *c;
+ int ret;
+
+ if (CONFIG_IS_ENABLED(CLK_CCF)) {
if (!CONFIG_IS_ENABLED(CLK_CCF))
return scmi_clk_gate(clk, 1);
Reduce indent.
+ 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)
+ return scmi_clk_gate(clk, 1);
+
+ /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if
agent has no permission. */
+ debug("SCMI CLOCK: the clock cannot be enabled by the
agent.\n");
+ return 0;
+ }
+
return scmi_clk_gate(clk, 1);
}
static int scmi_clk_disable(struct clk *clk)
{
+ struct clk_scmi *clkscmi;
+ struct clk *c;
+ int ret;
+
+ if (CONFIG_IS_ENABLED(CLK_CCF)) {
DTTO
+ 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)
+ return scmi_clk_gate(clk, 0);
+
+ /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if
agent has no permission. */
+ debug("SCMI CLOCK: the clock cannot be disabled by the
agent.\n");
+ return 0;
+ }
+
return scmi_clk_gate(clk, 0);
}
[...]