firmware: arm_scmi: Implement clock get permissions

ARM SCMI v3.2 introduces clock get permission command. To implement the
same let us stash the values of those permissions in the scmi_clock_info.
They indicate if the operation is forbidden or not.

If the CLOCK_GET_PERMISSIONS command is not supported, the default
permissions are set to allow the operations, otherwise they will be set
according to the response of CLOCK_GET_PERMISSIONS from the SCMI
platform firmware.

Reviewed-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
Link: https://lore.kernel.org/r/20240121110901.1414856-1-peng.fan@oss.nxp.com
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
This commit is contained in:
Peng Fan 2024-01-21 19:09:00 +08:00 committed by Sudeep Holla
parent 2858f6e5f0
commit dc36561e15
2 changed files with 67 additions and 0 deletions

View file

@ -28,8 +28,13 @@ enum scmi_clock_protocol_cmd {
CLOCK_POSSIBLE_PARENTS_GET = 0xC,
CLOCK_PARENT_SET = 0xD,
CLOCK_PARENT_GET = 0xE,
CLOCK_GET_PERMISSIONS = 0xF,
};
#define CLOCK_STATE_CONTROL_ALLOWED BIT(31)
#define CLOCK_PARENT_CONTROL_ALLOWED BIT(30)
#define CLOCK_RATE_CONTROL_ALLOWED BIT(29)
enum clk_state {
CLK_STATE_DISABLE,
CLK_STATE_ENABLE,
@ -49,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_GET_PERMISSIONS(x) ((x) & BIT(1))
u8 name[SCMI_SHORT_NAME_MAX_SIZE];
__le32 clock_enable_latency;
};
@ -293,6 +299,35 @@ static int scmi_clock_possible_parents(const struct scmi_protocol_handle *ph, u3
return ret;
}
static int
scmi_clock_get_permissions(const struct scmi_protocol_handle *ph, u32 clk_id,
struct scmi_clock_info *clk)
{
struct scmi_xfer *t;
u32 perm;
int ret;
ret = ph->xops->xfer_get_init(ph, CLOCK_GET_PERMISSIONS,
sizeof(clk_id), sizeof(perm), &t);
if (ret)
return ret;
put_unaligned_le32(clk_id, t->tx.buf);
ret = ph->xops->do_xfer(ph, t);
if (!ret) {
perm = get_unaligned_le32(t->rx.buf);
clk->state_ctrl_forbidden = !(perm & CLOCK_STATE_CONTROL_ALLOWED);
clk->rate_ctrl_forbidden = !(perm & CLOCK_RATE_CONTROL_ALLOWED);
clk->parent_ctrl_forbidden = !(perm & CLOCK_PARENT_CONTROL_ALLOWED);
}
ph->xops->xfer_put(ph, t);
return ret;
}
static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
u32 clk_id, struct scmi_clock_info *clk,
u32 version)
@ -339,6 +374,8 @@ 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 (SUPPORTS_GET_PERMISSIONS(attributes))
scmi_clock_get_permissions(ph, clk_id, clk);
}
return ret;
@ -511,6 +548,14 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,
struct scmi_xfer *t;
struct scmi_clock_set_rate *cfg;
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->rate_ctrl_forbidden)
return -EACCES;
ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_SET, sizeof(*cfg), 0, &t);
if (ret)
@ -596,6 +641,9 @@ scmi_clock_set_parent(const struct scmi_protocol_handle *ph, u32 clk_id,
if (parent_id >= clk->num_parents)
return -EINVAL;
if (clk->parent_ctrl_forbidden)
return -EACCES;
ret = ph->xops->xfer_get_init(ph, CLOCK_PARENT_SET,
sizeof(*cfg), 0, &t);
if (ret)
@ -679,6 +727,14 @@ static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id,
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->state_ctrl_forbidden)
return -EACCES;
return ci->clock_config_set(ph, clk_id, CLK_STATE_ENABLE,
NULL_OEM_TYPE, 0, atomic);
@ -688,6 +744,14 @@ static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id,
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->state_ctrl_forbidden)
return -EACCES;
return ci->clock_config_set(ph, clk_id, CLK_STATE_DISABLE,
NULL_OEM_TYPE, 0, atomic);

View file

@ -47,6 +47,9 @@ struct scmi_clock_info {
bool rate_discrete;
bool rate_changed_notifications;
bool rate_change_requested_notifications;
bool state_ctrl_forbidden;
bool rate_ctrl_forbidden;
bool parent_ctrl_forbidden;
union {
struct {
int num_rates;