firmware: arm_scmi: Add SCMI v3.1 VOLTAGE_LEVEL_SET_COMPLETE
Add SCMI v3.1 voltage protocol support for asynchronous VOLTAGE_LEVEL_SET command. Note that, if a voltage domain is advertised to support the asynchronous version of VOLTAGE_LEVEL_SET, the command will be issued asynchronously unless explicitly requested to use the synchronous version by setting the mode to SCMI_VOLTAGE_LEVEL_SET_SYNC when calling voltage_ops->level_set. The SCMI regulator driver level_set invocation has been left unchanged so that it will transparently use the asynchronous version if available. Link: https://lore.kernel.org/r/20220330150551.2573938-21-cristian.marussi@arm.com Signed-off-by: Cristian Marussi <cristian.marussi@arm.com> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
This commit is contained in:
Родитель
7aa75496ea
Коммит
4c74701b1e
|
@ -28,6 +28,7 @@ enum scmi_voltage_protocol_cmd {
|
||||||
|
|
||||||
struct scmi_msg_resp_domain_attributes {
|
struct scmi_msg_resp_domain_attributes {
|
||||||
__le32 attr;
|
__le32 attr;
|
||||||
|
#define SUPPORTS_ASYNC_LEVEL_SET(x) ((x) & BIT(31))
|
||||||
#define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(30))
|
#define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(30))
|
||||||
u8 name[SCMI_SHORT_NAME_MAX_SIZE];
|
u8 name[SCMI_SHORT_NAME_MAX_SIZE];
|
||||||
};
|
};
|
||||||
|
@ -56,6 +57,11 @@ struct scmi_msg_cmd_level_set {
|
||||||
__le32 voltage_level;
|
__le32 voltage_level;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct scmi_resp_voltage_level_set_complete {
|
||||||
|
__le32 domain_id;
|
||||||
|
__le32 voltage_level;
|
||||||
|
};
|
||||||
|
|
||||||
struct voltage_info {
|
struct voltage_info {
|
||||||
unsigned int version;
|
unsigned int version;
|
||||||
unsigned int num_domains;
|
unsigned int num_domains;
|
||||||
|
@ -214,6 +220,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
|
||||||
resp_dom = td->rx.buf;
|
resp_dom = td->rx.buf;
|
||||||
|
|
||||||
for (dom = 0; dom < vinfo->num_domains; dom++) {
|
for (dom = 0; dom < vinfo->num_domains; dom++) {
|
||||||
|
u32 attributes;
|
||||||
struct scmi_voltage_info *v;
|
struct scmi_voltage_info *v;
|
||||||
|
|
||||||
/* Retrieve domain attributes at first ... */
|
/* Retrieve domain attributes at first ... */
|
||||||
|
@ -225,18 +232,22 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
|
||||||
|
|
||||||
v = vinfo->domains + dom;
|
v = vinfo->domains + dom;
|
||||||
v->id = dom;
|
v->id = dom;
|
||||||
v->attributes = le32_to_cpu(resp_dom->attr);
|
attributes = le32_to_cpu(resp_dom->attr);
|
||||||
strlcpy(v->name, resp_dom->name, SCMI_MAX_STR_SIZE);
|
strlcpy(v->name, resp_dom->name, SCMI_MAX_STR_SIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If supported overwrite short name with the extended one;
|
* If supported overwrite short name with the extended one;
|
||||||
* on error just carry on and use already provided short name.
|
* on error just carry on and use already provided short name.
|
||||||
*/
|
*/
|
||||||
if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2 &&
|
if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2) {
|
||||||
SUPPORTS_EXTENDED_NAMES(v->attributes))
|
if (SUPPORTS_EXTENDED_NAMES(attributes))
|
||||||
ph->hops->extended_name_get(ph, VOLTAGE_DOMAIN_NAME_GET,
|
ph->hops->extended_name_get(ph,
|
||||||
v->id, v->name,
|
VOLTAGE_DOMAIN_NAME_GET,
|
||||||
SCMI_MAX_STR_SIZE);
|
v->id, v->name,
|
||||||
|
SCMI_MAX_STR_SIZE);
|
||||||
|
if (SUPPORTS_ASYNC_LEVEL_SET(attributes))
|
||||||
|
v->async_level_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
ret = scmi_voltage_levels_get(ph, v);
|
ret = scmi_voltage_levels_get(ph, v);
|
||||||
/* Skip invalid voltage descriptors */
|
/* Skip invalid voltage descriptors */
|
||||||
|
@ -308,12 +319,15 @@ static int scmi_voltage_config_get(const struct scmi_protocol_handle *ph,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
|
static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
|
||||||
u32 domain_id, u32 flags, s32 volt_uV)
|
u32 domain_id,
|
||||||
|
enum scmi_voltage_level_mode mode,
|
||||||
|
s32 volt_uV)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct scmi_xfer *t;
|
struct scmi_xfer *t;
|
||||||
struct voltage_info *vinfo = ph->get_priv(ph);
|
struct voltage_info *vinfo = ph->get_priv(ph);
|
||||||
struct scmi_msg_cmd_level_set *cmd;
|
struct scmi_msg_cmd_level_set *cmd;
|
||||||
|
struct scmi_voltage_info *v;
|
||||||
|
|
||||||
if (domain_id >= vinfo->num_domains)
|
if (domain_id >= vinfo->num_domains)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -323,12 +337,31 @@ static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
v = vinfo->domains + domain_id;
|
||||||
|
|
||||||
cmd = t->tx.buf;
|
cmd = t->tx.buf;
|
||||||
cmd->domain_id = cpu_to_le32(domain_id);
|
cmd->domain_id = cpu_to_le32(domain_id);
|
||||||
cmd->flags = cpu_to_le32(flags);
|
|
||||||
cmd->voltage_level = cpu_to_le32(volt_uV);
|
cmd->voltage_level = cpu_to_le32(volt_uV);
|
||||||
|
|
||||||
ret = ph->xops->do_xfer(ph, t);
|
if (!v->async_level_set || mode != SCMI_VOLTAGE_LEVEL_SET_AUTO) {
|
||||||
|
cmd->flags = cpu_to_le32(0x0);
|
||||||
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
|
} else {
|
||||||
|
cmd->flags = cpu_to_le32(0x1);
|
||||||
|
ret = ph->xops->do_xfer_with_response(ph, t);
|
||||||
|
if (!ret) {
|
||||||
|
struct scmi_resp_voltage_level_set_complete *resp;
|
||||||
|
|
||||||
|
resp = t->rx.buf;
|
||||||
|
if (le32_to_cpu(resp->domain_id) == domain_id)
|
||||||
|
dev_dbg(ph->dev,
|
||||||
|
"Voltage domain %d set async to %d\n",
|
||||||
|
v->id,
|
||||||
|
le32_to_cpu(resp->voltage_level));
|
||||||
|
else
|
||||||
|
ret = -EPROTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ph->xops->xfer_put(ph, t);
|
ph->xops->xfer_put(ph, t);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -495,6 +495,11 @@ struct scmi_reset_proto_ops {
|
||||||
int (*deassert)(const struct scmi_protocol_handle *ph, u32 domain);
|
int (*deassert)(const struct scmi_protocol_handle *ph, u32 domain);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum scmi_voltage_level_mode {
|
||||||
|
SCMI_VOLTAGE_LEVEL_SET_AUTO,
|
||||||
|
SCMI_VOLTAGE_LEVEL_SET_SYNC,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct scmi_voltage_info - describe one available SCMI Voltage Domain
|
* struct scmi_voltage_info - describe one available SCMI Voltage Domain
|
||||||
*
|
*
|
||||||
|
@ -507,7 +512,8 @@ struct scmi_reset_proto_ops {
|
||||||
* supported voltage level
|
* supported voltage level
|
||||||
* @negative_volts_allowed: True if any of the entries of @levels_uv represent
|
* @negative_volts_allowed: True if any of the entries of @levels_uv represent
|
||||||
* a negative voltage.
|
* a negative voltage.
|
||||||
* @attributes: represents Voltage Domain advertised attributes
|
* @async_level_set: True when the voltage domain supports asynchronous level
|
||||||
|
* set commands.
|
||||||
* @name: name assigned to the Voltage Domain by platform
|
* @name: name assigned to the Voltage Domain by platform
|
||||||
* @num_levels: number of total entries in @levels_uv.
|
* @num_levels: number of total entries in @levels_uv.
|
||||||
* @levels_uv: array of entries describing the available voltage levels for
|
* @levels_uv: array of entries describing the available voltage levels for
|
||||||
|
@ -517,7 +523,7 @@ struct scmi_voltage_info {
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
bool segmented;
|
bool segmented;
|
||||||
bool negative_volts_allowed;
|
bool negative_volts_allowed;
|
||||||
unsigned int attributes;
|
bool async_level_set;
|
||||||
char name[SCMI_MAX_STR_SIZE];
|
char name[SCMI_MAX_STR_SIZE];
|
||||||
unsigned int num_levels;
|
unsigned int num_levels;
|
||||||
#define SCMI_VOLTAGE_SEGMENT_LOW 0
|
#define SCMI_VOLTAGE_SEGMENT_LOW 0
|
||||||
|
@ -548,7 +554,7 @@ struct scmi_voltage_proto_ops {
|
||||||
int (*config_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
|
int (*config_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
|
||||||
u32 *config);
|
u32 *config);
|
||||||
int (*level_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
|
int (*level_set)(const struct scmi_protocol_handle *ph, u32 domain_id,
|
||||||
u32 flags, s32 volt_uV);
|
enum scmi_voltage_level_mode mode, s32 volt_uV);
|
||||||
int (*level_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
|
int (*level_get)(const struct scmi_protocol_handle *ph, u32 domain_id,
|
||||||
s32 *volt_uV);
|
s32 *volt_uV);
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче