Commit 4c74701b authored by Cristian Marussi's avatar Cristian Marussi Committed by Sudeep Holla
Browse files

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: default avatarCristian Marussi <cristian.marussi@arm.com>
Signed-off-by: default avatarSudeep Holla <sudeep.holla@arm.com>
parent 7aa75496
Loading
Loading
Loading
Loading
+42 −9
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ enum scmi_voltage_protocol_cmd {

struct scmi_msg_resp_domain_attributes {
	__le32 attr;
#define SUPPORTS_ASYNC_LEVEL_SET(x)	((x) & BIT(31))
#define SUPPORTS_EXTENDED_NAMES(x)	((x) & BIT(30))
	u8 name[SCMI_SHORT_NAME_MAX_SIZE];
};
@@ -56,6 +57,11 @@ struct scmi_msg_cmd_level_set {
	__le32 voltage_level;
};

struct scmi_resp_voltage_level_set_complete {
	__le32 domain_id;
	__le32 voltage_level;
};

struct voltage_info {
	unsigned int version;
	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;

	for (dom = 0; dom < vinfo->num_domains; dom++) {
		u32 attributes;
		struct scmi_voltage_info *v;

		/* 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->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);

		/*
		 * If supported overwrite short name with the extended one;
		 * on error just carry on and use already provided short name.
		 */
		if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2 &&
		    SUPPORTS_EXTENDED_NAMES(v->attributes))
			ph->hops->extended_name_get(ph, VOLTAGE_DOMAIN_NAME_GET,
		if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2) {
			if (SUPPORTS_EXTENDED_NAMES(attributes))
				ph->hops->extended_name_get(ph,
							VOLTAGE_DOMAIN_NAME_GET,
							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);
		/* 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,
				  u32 domain_id, u32 flags, s32 volt_uV)
				  u32 domain_id,
				  enum scmi_voltage_level_mode mode,
				  s32 volt_uV)
{
	int ret;
	struct scmi_xfer *t;
	struct voltage_info *vinfo = ph->get_priv(ph);
	struct scmi_msg_cmd_level_set *cmd;
	struct scmi_voltage_info *v;

	if (domain_id >= vinfo->num_domains)
		return -EINVAL;
@@ -323,12 +337,31 @@ static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
	if (ret)
		return ret;

	v = vinfo->domains + domain_id;

	cmd = t->tx.buf;
	cmd->domain_id = cpu_to_le32(domain_id);
	cmd->flags = cpu_to_le32(flags);
	cmd->voltage_level = cpu_to_le32(volt_uV);

	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);
	return ret;
+9 −3
Original line number Diff line number Diff line
@@ -495,6 +495,11 @@ struct scmi_reset_proto_ops {
	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
 *
@@ -507,7 +512,8 @@ struct scmi_reset_proto_ops {
 *	         supported voltage level
 * @negative_volts_allowed: True if any of the entries of @levels_uv represent
 *			    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
 * @num_levels: number of total entries in @levels_uv.
 * @levels_uv: array of entries describing the available voltage levels for
@@ -517,7 +523,7 @@ struct scmi_voltage_info {
	unsigned int id;
	bool segmented;
	bool negative_volts_allowed;
	unsigned int attributes;
	bool async_level_set;
	char name[SCMI_MAX_STR_SIZE];
	unsigned int num_levels;
#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,
			  u32 *config);
	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,
			 s32 *volt_uV);
};