sandbox: add SCMI power domain protocol support for testing

SCMI power domain management protocol is supported on sandbox
for test purpose. Add fake agent interfaces and associated
power domain devices.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
AKASHI Takahiro 2023-10-16 14:39:45 +09:00 committed by Tom Rini
parent c1d2ed0c63
commit 8e545b3781
5 changed files with 302 additions and 1 deletions

View File

@ -733,6 +733,11 @@
#address-cells = <1>;
#size-cells = <0>;
pwrdom_scmi: protocol@11 {
reg = <0x11>;
#power-domain-cells = <1>;
};
clk_scmi: protocol@14 {
reg = <0x14>;
#clock-cells = <1>;
@ -1647,6 +1652,7 @@
sandbox_scmi {
compatible = "sandbox,scmi-devices";
power-domains = <&pwrdom_scmi 2>;
clocks = <&clk_scmi 2>, <&clk_scmi 0>;
resets = <&reset_scmi 3>;
regul0-supply = <&regul0_scmi>;

View File

@ -6,10 +6,22 @@
#ifndef __SANDBOX_SCMI_TEST_H
#define __SANDBOX_SCMI_TEST_H
#include <power-domain.h>
struct udevice;
struct sandbox_scmi_agent;
struct sandbox_scmi_service;
/**
* struct sandbox_scmi_pwd
* @id: Identifier of the power domain used in the SCMI protocol
* @pstate:: Power state of the domain
*/
struct sandbox_scmi_pwd {
uint id;
u32 pstate;
};
/**
* struct sandbox_scmi_clk - Simulated clock exposed by SCMI
* @id: Identifier of the clock used in the SCMI protocol
@ -45,6 +57,8 @@ struct sandbox_scmi_voltd {
/**
* struct sandbox_scmi_agent - Simulated SCMI service seen by SCMI agent
* @pwdom_version: Implemented power domain protocol version
* @pwdom_count: Simulated power domains array size
* @clk: Simulated clocks
* @clk_count: Simulated clocks array size
* @reset: Simulated reset domains
@ -53,6 +67,9 @@ struct sandbox_scmi_voltd {
* @voltd_count: Simulated voltage domains array size
*/
struct sandbox_scmi_agent {
int pwdom_version;
struct sandbox_scmi_pwd *pwdom;
size_t pwdom_count;
struct sandbox_scmi_clk *clk;
size_t clk_count;
struct sandbox_scmi_reset *reset;
@ -71,6 +88,8 @@ struct sandbox_scmi_service {
/**
* struct sandbox_scmi_devices - Reference to devices probed through SCMI
* @pwdom: Array of power domains
* @pwdom_count: Number of power domains probed
* @clk: Array the clock devices
* @clk_count: Number of clock devices probed
* @reset: Array the reset controller devices
@ -79,6 +98,8 @@ struct sandbox_scmi_service {
* @regul_count: Number of regulator devices probed
*/
struct sandbox_scmi_devices {
struct power_domain *pwdom;
size_t pwdom_count;
struct clk *clk;
size_t clk_count;
struct reset_ctl *reset;

View File

@ -240,6 +240,7 @@ CONFIG_PINCTRL_SANDBOX=y
CONFIG_PINCTRL_SINGLE=y
CONFIG_POWER_DOMAIN=y
CONFIG_SANDBOX_POWER_DOMAIN=y
CONFIG_SCMI_POWER_DOMAIN=y
CONFIG_DM_PMIC=y
CONFIG_PMIC_ACT8846=y
CONFIG_DM_PMIC_PFUZE100=y

View File

@ -43,6 +43,8 @@
#define SANDBOX_SCMI_AGENT_NAME "OSPM"
#define SANDBOX_SCMI_PLATFORM_NAME "platform"
#define SANDBOX_SCMI_PWD_PROTOCOL_VERSION SCMI_PWD_PROTOCOL_VERSION
/**
* struct sandbox_channel - Description of sandbox transport
* @channel_id: Channel identifier
@ -64,6 +66,7 @@ struct scmi_channel {
};
static u8 protocols[] = {
SCMI_PROTOCOL_ID_POWER_DOMAIN,
SCMI_PROTOCOL_ID_CLOCK,
SCMI_PROTOCOL_ID_RESET_DOMAIN,
SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
@ -71,6 +74,12 @@ static u8 protocols[] = {
#define NUM_PROTOCOLS ARRAY_SIZE(protocols)
static struct sandbox_scmi_pwd scmi_pwdom[] = {
{ .id = 0 },
{ .id = 1 },
{ .id = 2 },
};
static struct sandbox_scmi_clk scmi_clk[] = {
{ .rate = 333 },
{ .rate = 200 },
@ -458,6 +467,238 @@ static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev,
return 0;
}
/* Power Domain Management Protocol */
/**
* sandbox_scmi_pwd_protocol_version - implement SCMI_PROTOCOL_VERSION
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_PROTOCOL_VERSION command.
*
* Return: 0 on success, error code on failure
*/
static int sandbox_scmi_pwd_protocol_version(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_protocol_version_out *out = NULL;
if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
out = (struct scmi_protocol_version_out *)msg->out_msg;
out->version = SANDBOX_SCMI_PWD_PROTOCOL_VERSION;
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_pwd_protocol_attribs - implement SCMI_PWD_PROTOCOL_ATTRS
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_PWD_PROTOCOL_ATTRS command.
*
* Return: 0 on success, error code on failure
*/
static int sandbox_scmi_pwd_protocol_attribs(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_pwd_protocol_attrs_out *out;
if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
out = (struct scmi_pwd_protocol_attrs_out *)msg->out_msg;
out->attributes = ARRAY_SIZE(scmi_pwdom);
out->stats_addr_low = 0;
out->stats_addr_high = 0;
out->stats_len = 0;
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_pwd_protocol_msg_attribs - implement
SCMI_PWD_PROTOCOL_MESSAGE_ATTRS
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_PWD_PROTOCOL_MESSAGE_ATTRS command.
*
* Return: 0 on success, error code on failure
*/
static int sandbox_scmi_pwd_protocol_msg_attribs(struct udevice *dev,
struct scmi_msg *msg)
{
u32 message_id;
struct scmi_pwd_protocol_msg_attrs_out *out;
if (!msg->in_msg || msg->in_msg_sz < sizeof(message_id) ||
!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
message_id = *(u32 *)msg->in_msg;
out = (struct scmi_pwd_protocol_msg_attrs_out *)msg->out_msg;
if (message_id <= SCMI_PWD_STATE_GET ||
message_id == SCMI_PWD_NAME_GET) {
out->attributes = 0;
out->status = SCMI_SUCCESS;
} else {
out->status = SCMI_NOT_FOUND;
}
return 0;
}
/**
* sandbox_scmi_pwd_attribs - implement SCMI_PWD_ATTRS
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_PWD_ATTRS command.
*
* Return: 0 on success, error code on failure
*/
static int sandbox_scmi_pwd_attribs(struct udevice *dev, struct scmi_msg *msg)
{
u32 domain_id;
struct scmi_pwd_attrs_out *out;
if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
domain_id = *(u32 *)msg->in_msg;
out = (struct scmi_pwd_attrs_out *)msg->out_msg;
if (domain_id > ARRAY_SIZE(scmi_pwdom)) {
out->status = SCMI_NOT_FOUND;
return 0;
}
out->attributes =
SCMI_PWD_ATTR_PSTATE_SYNC | SCMI_PWD_ATTR_EXTENDED_NAME;
/* just 15-char + NULL */
snprintf(out->name, SCMI_PWD_NAME_LENGTH_MAX, "power-domain--%d",
domain_id);
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_pwd_state_set - implement SCMI_PWD_STATE_SET
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_PWD_STATE_SET command.
*
* Return: 0 on success, error code on failure
*/
static int sandbox_scmi_pwd_state_set(struct udevice *dev, struct scmi_msg *msg)
{
struct scmi_pwd_state_set_in *in;
s32 *status;
if (!msg->in_msg || msg->in_msg_sz < sizeof(in) ||
!msg->out_msg || msg->out_msg_sz < sizeof(*status))
return -EINVAL;
in = (struct scmi_pwd_state_set_in *)msg->in_msg;
status = (s32 *)msg->out_msg;
if (in->domain_id > ARRAY_SIZE(scmi_pwdom)) {
*status = SCMI_NOT_FOUND;
return 0;
}
if ((in->flags & SCMI_PWD_SET_FLAGS_ASYNC) ||
(in->pstate != SCMI_PWD_PSTATE_TYPE_LOST && in->pstate)) {
*status = SCMI_INVALID_PARAMETERS;
return 0;
}
scmi_pwdom[in->domain_id].pstate = in->pstate;
*status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_pwd_state_get - implement SCMI_PWD_STATE_GET
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_PWD_STATE_GET command.
*
* Return: 0 on success, error code on failure
*/
static int sandbox_scmi_pwd_state_get(struct udevice *dev, struct scmi_msg *msg)
{
u32 domain_id;
struct scmi_pwd_state_get_out *out;
if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
domain_id = *(u32 *)msg->in_msg;
out = (struct scmi_pwd_state_get_out *)msg->out_msg;
if (domain_id > ARRAY_SIZE(scmi_pwdom)) {
out->status = SCMI_NOT_FOUND;
return 0;
}
out->pstate = scmi_pwdom[domain_id].pstate;
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_pwd_name_get - implement SCMI_PWD_NAME_GET
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_PWD_NAME_GET command.
*
* Return: 0 on success, error code on failure
*/
static int sandbox_scmi_pwd_name_get(struct udevice *dev, struct scmi_msg *msg)
{
u32 domain_id;
struct scmi_pwd_name_get_out *out;
if (!msg->in_msg || msg->in_msg_sz < sizeof(domain_id) ||
!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
domain_id = *(u32 *)msg->in_msg;
out = (struct scmi_pwd_name_get_out *)msg->out_msg;
if (domain_id > ARRAY_SIZE(scmi_pwdom)) {
out->status = SCMI_NOT_FOUND;
return 0;
}
snprintf(out->extended_name, SCMI_PWD_EXTENDED_NAME_MAX,
"power-domain--%d-extended", domain_id);
out->status = SCMI_SUCCESS;
return 0;
}
/* Clock Protocol */
static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
@ -918,6 +1159,26 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
break;
}
break;
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
switch (msg->message_id) {
case SCMI_PROTOCOL_VERSION:
return sandbox_scmi_pwd_protocol_version(dev, msg);
case SCMI_PROTOCOL_ATTRIBUTES:
return sandbox_scmi_pwd_protocol_attribs(dev, msg);
case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
return sandbox_scmi_pwd_protocol_msg_attribs(dev, msg);
case SCMI_PWD_ATTRIBUTES:
return sandbox_scmi_pwd_attribs(dev, msg);
case SCMI_PWD_STATE_SET:
return sandbox_scmi_pwd_state_set(dev, msg);
case SCMI_PWD_STATE_GET:
return sandbox_scmi_pwd_state_get(dev, msg);
case SCMI_PWD_NAME_GET:
return sandbox_scmi_pwd_name_get(dev, msg);
default:
break;
}
break;
case SCMI_PROTOCOL_ID_CLOCK:
switch (msg->message_id) {
case SCMI_PROTOCOL_ATTRIBUTES:
@ -960,7 +1221,6 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
break;
}
break;
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
case SCMI_PROTOCOL_ID_SYSTEM:
case SCMI_PROTOCOL_ID_PERF:
case SCMI_PROTOCOL_ID_SENSOR:
@ -993,6 +1253,9 @@ static int sandbox_scmi_test_probe(struct udevice *dev)
struct sandbox_scmi_agent *agent = dev_get_priv(dev);
*agent = (struct sandbox_scmi_agent){
.pwdom_version = SANDBOX_SCMI_PWD_PROTOCOL_VERSION,
.pwdom = scmi_pwdom,
.pwdom_count = ARRAY_SIZE(scmi_pwdom),
.clk = scmi_clk,
.clk_count = ARRAY_SIZE(scmi_clk),
.reset = scmi_reset,

View File

@ -29,12 +29,14 @@
/*
* struct sandbox_scmi_device_priv - Storage for device handles used by test
* @pwdom: Power domain device
* @clk: Array of clock instances used by tests
* @reset_clt: Array of the reset controller instances used by tests
* @regulators: Array of regulator device references used by the tests
* @devices: Resources exposed by sandbox_scmi_devices_ctx()
*/
struct sandbox_scmi_device_priv {
struct power_domain pwdom;
struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT];
struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT];
struct udevice *regulators[SCMI_TEST_DEVICES_VOLTD_COUNT];
@ -77,6 +79,8 @@ static int sandbox_scmi_devices_probe(struct udevice *dev)
size_t n;
priv->devices = (struct sandbox_scmi_devices){
.pwdom = &priv->pwdom,
.pwdom_count = 1,
.clk = priv->clk,
.clk_count = SCMI_TEST_DEVICES_CLK_COUNT,
.reset = priv->reset_ctl,
@ -85,6 +89,12 @@ static int sandbox_scmi_devices_probe(struct udevice *dev)
.regul_count = SCMI_TEST_DEVICES_VOLTD_COUNT,
};
ret = power_domain_get_by_index(dev, priv->devices.pwdom, 0);
if (ret) {
dev_err(dev, "%s: Failed on power domain\n", __func__);
return ret;
}
for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
ret = clk_get_by_index(dev, n, priv->devices.clk + n);
if (ret) {