u-boot/drivers/firmware/scmi/pwdom.c
AKASHI Takahiro fc358b1a76 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 <takahiro.akashi@linaro.org>
2023-10-24 17:05:24 -04:00

189 lines
3.9 KiB
C

// 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;
}