[RFC] firmware: arm_scmi: support clock denied attributes

From: Peng Fan (OSS)
Date: Wed Oct 25 2023 - 23:37:10 EST


From: Peng Fan <peng.fan@xxxxxxx>

This is not in SPEC and is just defined by NXP. This patch is
to start the discussion to start include them in SPEC.

Signed-off-by: Peng Fan <peng.fan@xxxxxxx>
---
drivers/clk/clk-scmi.c | 39 +++++++++++++++++++++++++------
drivers/firmware/arm_scmi/clock.c | 9 +++++++
include/linux/scmi_protocol.h | 4 ++++
3 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index 8cbe24789c24..303f8a8ec8e0 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -75,15 +75,13 @@ static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct scmi_clk *clk = to_scmi_clk(hw);
+ const struct scmi_clock_info *info = clk->info;
+ u64 rate1 = 0;

- return scmi_proto_clk_ops->rate_set(clk->ph, clk->id, rate);
-}
-
-static int scmi_clk_set_parent(struct clk_hw *hw, u8 parent_index)
-{
- struct scmi_clk *clk = to_scmi_clk(hw);
+ if (info->flags & SCMI_CLOCK_SET_RATE_DENIED)
+ return -EACCES;

- return scmi_proto_clk_ops->parent_set(clk->ph, clk->id, parent_index);
+ return scmi_proto_clk_ops->rate_set(clk->ph, clk->id, rate);
}

static u8 scmi_clk_get_parent(struct clk_hw *hw)
@@ -107,6 +105,17 @@ static u8 scmi_clk_get_parent(struct clk_hw *hw)
return p_idx;
}

+static int scmi_clk_set_parent(struct clk_hw *hw, u8 parent_index)
+{
+ struct scmi_clk *clk = to_scmi_clk(hw);
+ const struct scmi_clock_info *info = clk->info;
+
+ if (info->flags & SCMI_CLOCK_SET_ENABLE_DENIED)
+ return -EACCES;
+
+ return scmi_proto_clk_ops->parent_set(clk->ph, clk->id, parent_index);
+}
+
static int scmi_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
/*
@@ -119,6 +128,10 @@ static int scmi_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *r
static int scmi_clk_enable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
+ const struct scmi_clock_info *info = clk->info;
+
+ if (info->flags & SCMI_CLOCK_SET_ENABLE_DENIED)
+ return 0;

return scmi_proto_clk_ops->enable(clk->ph, clk->id, NOT_ATOMIC);
}
@@ -126,6 +139,10 @@ static int scmi_clk_enable(struct clk_hw *hw)
static void scmi_clk_disable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
+ const struct scmi_clock_info *info = clk->info;
+
+ if (info->flags & SCMI_CLOCK_SET_ENABLE_DENIED)
+ return;

scmi_proto_clk_ops->disable(clk->ph, clk->id, NOT_ATOMIC);
}
@@ -133,6 +150,10 @@ static void scmi_clk_disable(struct clk_hw *hw)
static int scmi_clk_atomic_enable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
+ const struct scmi_clock_info *info = clk->info;
+
+ if (info->flags & SCMI_CLOCK_SET_ENABLE_DENIED)
+ return 0;

return scmi_proto_clk_ops->enable(clk->ph, clk->id, ATOMIC);
}
@@ -140,6 +161,10 @@ static int scmi_clk_atomic_enable(struct clk_hw *hw)
static void scmi_clk_atomic_disable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
+ const struct scmi_clock_info *info = clk->info;
+
+ if (info->flags & SCMI_CLOCK_SET_ENABLE_DENIED)
+ return;

scmi_proto_clk_ops->disable(clk->ph, clk->id, ATOMIC);
}
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index 42b81c181d68..1a62e3b82d34 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -46,6 +46,9 @@ struct scmi_msg_resp_clock_attributes {
#define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x) ((x) & BIT(30))
#define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29))
#define SUPPORTS_PARENT_CLOCK(x) ((x) & BIT(28))
+#define SETS_ENABLE_DENIED(x) ((x) & BIT(15))
+#define SETS_RATE_DENIED(x) ((x) & BIT(14))
+#define SETS_PARENT_DENIED(x) ((x) & BIT(13))
u8 name[SCMI_SHORT_NAME_MAX_SIZE];
__le32 clock_enable_latency;
};
@@ -327,6 +330,12 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
clk->rate_change_requested_notifications = true;
if (SUPPORTS_PARENT_CLOCK(attributes))
scmi_clock_possible_parents(ph, clk_id, clk);
+ if (SETS_PARENT_DENIED(attributes))
+ clk->flags |= SCMI_CLOCK_SET_PARENT_DENIED;
+ if (SETS_RATE_DENIED(attributes))
+ clk->flags |= SCMI_CLOCK_SET_RATE_DENIED;
+ if (SETS_ENABLE_DENIED(attributes))
+ clk->flags |= SCMI_CLOCK_SET_ENABLE_DENIED;
}

return ret;
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index f2f05fb42d28..71911dcd8117 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -41,12 +41,16 @@ struct scmi_revision_info {
char sub_vendor_id[SCMI_SHORT_NAME_MAX_SIZE];
};

+#define SCMI_CLOCK_SET_PARENT_DENIED BIT(13)
+#define SCMI_CLOCK_SET_RATE_DENIED BIT(14)
+#define SCMI_CLOCK_SET_ENABLE_DENIED BIT(15)
struct scmi_clock_info {
char name[SCMI_MAX_STR_SIZE];
unsigned int enable_latency;
bool rate_discrete;
bool rate_changed_notifications;
bool rate_change_requested_notifications;
+ unsigned int flags;
union {
struct {
int num_rates;
--
2.37.1