]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
firmware: arm_scmi: Add clock check for extended config support
authorCristian Marussi <cristian.marussi@arm.com>
Wed, 14 Feb 2024 18:30:02 +0000 (18:30 +0000)
committerSudeep Holla <sudeep.holla@arm.com>
Thu, 22 Feb 2024 08:17:10 +0000 (08:17 +0000)
SCMI v3.2 added support to set/get clock custom OEM types; such support is
conditionally present, though, depending on an extended config attribute
bit possibly advertised by the platform server on a per-domain base.

Add a check to verify if OEM types are supported before allowing any kind
of OEM-specific get/set operation. Also add a check around all the new
v3.2 clock features.

Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Link: https://lore.kernel.org/r/20240214183006.3403207-4-cristian.marussi@arm.com
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
drivers/firmware/arm_scmi/clock.c
include/linux/scmi_protocol.h

index 85eda5db40bab4e05f55b6cbc9dffd9df0589572..add350bf2a7f2d3aa1fc2baa5030d9db380f8910 100644 (file)
@@ -54,6 +54,7 @@ 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 SUPPORTS_EXTENDED_CONFIG(x)            ((x) & BIT(27))
 #define SUPPORTS_GET_PERMISSIONS(x)            ((x) & BIT(1))
        u8 name[SCMI_SHORT_NAME_MAX_SIZE];
        __le32 clock_enable_latency;
@@ -388,10 +389,14 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
                if (cinfo->notify_rate_change_requested_cmd &&
                    SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes))
                        clk->rate_change_requested_notifications = true;
-               if (SUPPORTS_PARENT_CLOCK(attributes))
-                       scmi_clock_possible_parents(ph, clk_id, clk);
-               if (SUPPORTS_GET_PERMISSIONS(attributes))
-                       scmi_clock_get_permissions(ph, clk_id, clk);
+               if (PROTOCOL_REV_MAJOR(version) >= 0x3) {
+                       if (SUPPORTS_PARENT_CLOCK(attributes))
+                               scmi_clock_possible_parents(ph, clk_id, clk);
+                       if (SUPPORTS_GET_PERMISSIONS(attributes))
+                               scmi_clock_get_permissions(ph, clk_id, clk);
+                       if (SUPPORTS_EXTENDED_CONFIG(attributes))
+                               clk->extended_config = true;
+               }
        }
 
        return ret;
@@ -700,7 +705,7 @@ scmi_clock_get_parent(const struct scmi_protocol_handle *ph, u32 clk_id,
        return ret;
 }
 
-/* For SCMI clock v2.1 and onwards */
+/* For SCMI clock v3.0 and onwards */
 static int
 scmi_clock_config_set_v2(const struct scmi_protocol_handle *ph, u32 clk_id,
                         enum clk_state state, u8 oem_type, u32 oem_val,
@@ -773,7 +778,7 @@ static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id,
                                    NULL_OEM_TYPE, 0, atomic);
 }
 
-/* For SCMI clock v2.1 and onwards */
+/* For SCMI clock v3.0 and onwards */
 static int
 scmi_clock_config_get_v2(const struct scmi_protocol_handle *ph, u32 clk_id,
                         u8 oem_type, u32 *attributes, bool *enabled,
@@ -860,6 +865,14 @@ static int scmi_clock_config_oem_set(const struct scmi_protocol_handle *ph,
                                     bool atomic)
 {
        struct clock_info *ci = ph->get_priv(ph);
+       struct scmi_clock_info *clk;
+
+       clk = scmi_clock_domain_lookup(ci, clk_id);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       if (!clk->extended_config)
+               return -EOPNOTSUPP;
 
        return ci->clock_config_set(ph, clk_id, CLK_STATE_UNCHANGED,
                                    oem_type, oem_val, atomic);
@@ -870,6 +883,14 @@ static int scmi_clock_config_oem_get(const struct scmi_protocol_handle *ph,
                                     u32 *attributes, bool atomic)
 {
        struct clock_info *ci = ph->get_priv(ph);
+       struct scmi_clock_info *clk;
+
+       clk = scmi_clock_domain_lookup(ci, clk_id);
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       if (!clk->extended_config)
+               return -EOPNOTSUPP;
 
        return ci->clock_config_get(ph, clk_id, oem_type, attributes,
                                    NULL, oem_val, atomic);
index 9b9351e07a110da37b5c7b0c3f2c296b4a03c581..46a61173c91ca83b8edadc97cd94a7e1661b17bb 100644 (file)
@@ -50,6 +50,7 @@ struct scmi_clock_info {
        bool state_ctrl_forbidden;
        bool rate_ctrl_forbidden;
        bool parent_ctrl_forbidden;
+       bool extended_config;
        union {
                struct {
                        int num_rates;