From: AKASHI Takahiro Date: Mon, 16 Oct 2023 05:39:43 +0000 (+0900) Subject: firmware: scmi: add power domain protocol support X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=fc358b1a760228a61388ac3c17b3850ac8f914dd;p=u-boot.git firmware: scmi: add power domain protocol support In this patch, added are helper functions to directly manipulate SCMI power domain management protocol. DM compliant power domain driver will be implemented on top of those interfaces in a succeeding patch. Signed-off-by: AKASHI Takahiro --- diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile index 1a23d49817..dae4286358 100644 --- a/drivers/firmware/scmi/Makefile +++ b/drivers/firmware/scmi/Makefile @@ -4,4 +4,5 @@ obj-y += smt.o obj-$(CONFIG_SCMI_AGENT_SMCCC) += smccc_agent.o obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o obj-$(CONFIG_SCMI_AGENT_OPTEE) += optee_agent.o +obj-$(CONFIG_SCMI_POWER_DOMAIN) += pwdom.o obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o sandbox-scmi_devices.o diff --git a/drivers/firmware/scmi/pwdom.c b/drivers/firmware/scmi/pwdom.c new file mode 100644 index 0000000000..de2ba4755a --- /dev/null +++ b/drivers/firmware/scmi/pwdom.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SCMI Power domain management protocol + * + * Copyright (C) 2023 Linaro Limited + * author: AKASHI Takahiro + */ + +#include +#include +#include +#include +#include +#include + +int scmi_pwd_protocol_attrs(struct udevice *dev, int *num_pwdoms, + u64 *stats_addr, size_t *stats_len) +{ + struct scmi_pwd_protocol_attrs_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN, + .message_id = SCMI_PROTOCOL_ATTRIBUTES, + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + if (!dev || !num_pwdoms || !stats_addr || !stats_len) + return -EINVAL; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + *num_pwdoms = SCMI_PWD_PROTO_ATTRS_NUM_PWD(out.attributes); + *stats_addr = ((u64)out.stats_addr_high << 32) + out.stats_addr_low; + *stats_len = out.stats_len; + + return 0; +} + +int scmi_pwd_protocol_message_attrs(struct udevice *dev, s32 message_id, + u32 *attributes) +{ + struct scmi_pwd_protocol_msg_attrs_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN, + .message_id = SCMI_PROTOCOL_MESSAGE_ATTRIBUTES, + .in_msg = (u8 *)&message_id, + .in_msg_sz = sizeof(message_id), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + if (!dev || !attributes) + return -EINVAL; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + *attributes = out.attributes; + + return 0; +} + +int scmi_pwd_attrs(struct udevice *dev, u32 domain_id, u32 *attributes, + u8 **name) +{ + struct scmi_pwd_attrs_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN, + .message_id = SCMI_PWD_ATTRIBUTES, + .in_msg = (u8 *)&domain_id, + .in_msg_sz = sizeof(domain_id), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + if (!dev || !attributes || !name) + return -EINVAL; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + *name = strdup(out.name); + if (!*name) + return -ENOMEM; + + *attributes = out.attributes; + + return 0; +} + +int scmi_pwd_state_set(struct udevice *dev, u32 flags, u32 domain_id, + u32 pstate) +{ + struct scmi_pwd_state_set_in in; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN, + .message_id = SCMI_PWD_STATE_SET, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + in.flags = flags; + in.domain_id = domain_id; + in.pstate = pstate; + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +int scmi_pwd_state_get(struct udevice *dev, u32 domain_id, u32 *pstate) +{ + struct scmi_pwd_state_get_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN, + .message_id = SCMI_PWD_STATE_GET, + .in_msg = (u8 *)&domain_id, + .in_msg_sz = sizeof(domain_id), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + if (!dev || !pstate) + return -EINVAL; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + *pstate = out.pstate; + + return 0; +} + +int scmi_pwd_name_get(struct udevice *dev, u32 domain_id, u8 **name) +{ + struct scmi_pwd_name_get_out out; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_POWER_DOMAIN, + .message_id = SCMI_PWD_NAME_GET, + .in_msg = (u8 *)&domain_id, + .in_msg_sz = sizeof(domain_id), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + if (!dev || !name) + return -EINVAL; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + if (out.status) + return scmi_to_linux_errno(out.status); + + *name = strdup(out.extended_name); + if (!*name) + return -ENOMEM; + + return 0; +} diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h index 163647a57b..7abb2a6f36 100644 --- a/include/scmi_protocols.h +++ b/include/scmi_protocols.h @@ -544,6 +544,184 @@ int scmi_base_set_protocol_permissions(struct udevice *dev, int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id, u32 flags); +/* + * SCMI Power Domain Management Protocol + */ + +#define SCMI_PWD_PROTOCOL_VERSION 0x30000 +#define SCMI_PWD_PSTATE_TYPE_LOST BIT(30) +#define SCMI_PWD_PSTATE_ID GENMASK(27, 0) + +enum scmi_power_domain_message_id { + SCMI_PWD_ATTRIBUTES = 0x3, + SCMI_PWD_STATE_SET = 0x4, + SCMI_PWD_STATE_GET = 0x5, + SCMI_PWD_STATE_NOTIFY = 0x6, + SCMI_PWD_STATE_CHANGE_REQUESTED_NOTIFY = 0x7, + SCMI_PWD_NAME_GET = 0x8, +}; + +/** + * struct scmi_pwd_protocol_attrs_out + * @status: SCMI command status + * @attributes: Protocol attributes + * @stats_addr_low: Lower 32 bits of address of statistics memory region + * @stats_addr_high: Higher 32 bits of address of statistics memory region + * @stats_len: Length of statistics memory region + */ +struct scmi_pwd_protocol_attrs_out { + s32 status; + u32 attributes; + u32 stats_addr_low; + u32 stats_addr_high; + u32 stats_len; +}; + +#define SCMI_PWD_PROTO_ATTRS_NUM_PWD(attributes) ((attributes) & GENMASK(15, 0)) + +/** + * struct scmi_pwd_protocol_msg_attrs_out + * @status: SCMI command status + * @attributes: Message-specific attributes + */ +struct scmi_pwd_protocol_msg_attrs_out { + s32 status; + u32 attributes; +}; + +#define SCMI_PWD_NAME_LENGTH_MAX 16 + +/** + * struct scmi_pwd_attrs_out + * @status: SCMI command status + * @attributes: Power domain attributes + * @name: Name of power domain + */ +struct scmi_pwd_attrs_out { + s32 status; + u32 attributes; + u8 name[SCMI_PWD_NAME_LENGTH_MAX]; +}; + +#define SCMI_PWD_ATTR_PSTATE_CHANGE_NOTIFY BIT(31) +#define SCMI_PWD_ATTR_PSTATE_ASYNC BIT(30) +#define SCMI_PWD_ATTR_PSTATE_SYNC BIT(29) +#define SCMI_PWD_ATTR_PSTATE_CHANGE_RQ_NOTIFY BIT(28) +#define SCMI_PWD_ATTR_EXTENDED_NAME BIT(27) + +/** + * struct scmi_pwd_state_set_in + * @flags: Flags + * @domain_id: Identifier of power domain + * @pstate: Power state of the domain + */ +struct scmi_pwd_state_set_in { + u32 flags; + u32 domain_id; + u32 pstate; +}; + +#define SCMI_PWD_SET_FLAGS_ASYNC BIT(0) + +/** + * struct scmi_pwd_state_get_out + * @status: SCMI command status + * @pstate: Power state of the domain + */ +struct scmi_pwd_state_get_out { + s32 status; + u32 pstate; +}; + +#define SCMI_PWD_EXTENDED_NAME_MAX 64 +/** + * struct scmi_pwd_name_get_out + * @status: SCMI command status + * @flags: Parameter flags + * @extended_name: Extended name of power domain + */ +struct scmi_pwd_name_get_out { + s32 status; + u32 flags; + u8 extended_name[SCMI_PWD_EXTENDED_NAME_MAX]; +}; + +/** + * scmi_pwd_protocol_attrs - get protocol attributes + * @dev: SCMI protocol device + * @num_pwdoms: Number of power domains + * @stats_addr: Address of statistics memory region + * @stats_len: Length of statistics memory region + * + * Obtain the protocol attributes, the number of power domains and + * the information of statistics memory region. + * + * Return: 0 on success, error code on failure + */ +int scmi_pwd_protocol_attrs(struct udevice *dev, int *num_pwdoms, + u64 *stats_addr, size_t *stats_len); +/** + * scmi_pwd_protocol_message_attrs - get message-specific attributes + * @dev: SCMI protocol device + * @message_id: SCMI message ID + * @attributes: Message-specific attributes + * + * Obtain the message-specific attributes in @attributes. + * + * Return: 0 on success, error code on failure + */ +int scmi_pwd_protocol_message_attrs(struct udevice *dev, s32 message_id, + u32 *attributes); +/** + * scmi_pwd_attrs - get power domain attributes + * @dev: SCMI protocol device + * @domain_id: Identifier of power domain + * @attributes: Power domain attributes + * @name: Name of power domain + * + * Obtain the attributes of the given power domain, @domain_id, in @attributes + * as well as its name in @name. + * + * Return: 0 on success, error code on failure + */ +int scmi_pwd_attrs(struct udevice *dev, u32 message_id, u32 *attributes, + u8 **name); +/** + * scmi_pwd_state_set - set power state + * @dev: SCMI protocol device + * @flags: Parameter flags + * @domain_id: Identifier of power domain + * @pstate: Power state + * + * Change the power state of the given power domain, @domain_id. + * + * Return: 0 on success, error code on failure + */ +int scmi_pwd_state_set(struct udevice *dev, u32 flags, u32 domain_id, + u32 pstate); +/** + * scmi_pwd_state_get - get power state + * @dev: SCMI protocol device + * @domain_id: Identifier of power domain + * @pstate: Power state + * + * Obtain the power state of the given power domain, @domain_id. + * + * Return: 0 on success, error code on failure + */ +int scmi_pwd_state_get(struct udevice *dev, u32 domain_id, u32 *pstate); +/** + * scmi_pwd_name_get - get extended name + * @dev: SCMI protocol device + * @domain_id: Identifier of power domain + * @name: Extended name of the domain + * + * Obtain the extended name of the given power domain, @domain_id, in @name. + * + * Return: 0 on success, error code on failure + */ +int scmi_pwd_name_get(struct udevice *dev, u32 domain_id, u8 **name); + /* * SCMI Clock Protocol */