aboutsummaryrefslogtreecommitdiff
path: root/drivers/firmware/scmi/pwdom.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware/scmi/pwdom.c')
-rw-r--r--drivers/firmware/scmi/pwdom.c188
1 files changed, 188 insertions, 0 deletions
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 <takahiro.akashi@linaro.org>
+ */
+
+#include <dm.h>
+#include <malloc.h>
+#include <scmi_agent.h>
+#include <scmi_protocols.h>
+#include <string.h>
+#include <asm/types.h>
+
+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;
+}