mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 22:02:02 +00:00
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:
parent
2858f6e5f0
commit
dc36561e15
2 changed files with 67 additions and 0 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue