Merge branch '2023-10-13-firmware-scmi-updates'

- Fix a memset call in the optee_agent code.

Then to quote the author for the rest of the changes:
This patch series allows users to access SCMI base protocol provided by
SCMI server (platform). See SCMI specification document v3.2 beta[1]
for more details about SCMI base protocol.

What is currently not implemented is
- SCMI_BASE_NOTIFY_ERRORS command and notification callback mechanism

This feature won't be very useful in the current U-Boot environment.

[1] https://developer.arm.com/documentation/den0056/e/?lang=en
This commit is contained in:
Tom Rini 2023-10-14 10:47:52 -04:00
commit 25edd247a8
17 changed files with 2263 additions and 205 deletions

View File

@ -732,13 +732,10 @@
#address-cells = <1>;
#size-cells = <0>;
protocol@10 {
reg = <0x10>;
};
clk_scmi: protocol@14 {
reg = <0x14>;
#clock-cells = <1>;
linaro,sandbox-channel-id = <0x14>;
};
reset_scmi: protocol@16 {

View File

@ -88,11 +88,21 @@ struct sandbox_scmi_devices {
};
#ifdef CONFIG_SCMI_FIRMWARE
/**
* sandbox_scmi_channel_id - Get the channel id
* @dev: Reference to the SCMI protocol device
*
* Return: Channel id
*/
unsigned int sandbox_scmi_channel_id(struct udevice *dev);
/**
* sandbox_scmi_service_ctx - Get the simulated SCMI services context
* sandbox_scmi_agent_ctx - Get the simulated SCMI agent context
* @dev: Reference to the test agent
* @return: Reference to backend simulated resources state
*/
struct sandbox_scmi_service *sandbox_scmi_service_ctx(void);
struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev);
/**
* sandbox_scmi_devices_ctx - Get references to devices accessed through SCMI
@ -101,7 +111,12 @@ struct sandbox_scmi_service *sandbox_scmi_service_ctx(void);
*/
struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev);
#else
static inline struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
inline unsigned int sandbox_scmi_channel_id(struct udevice *dev);
{
return 0;
}
static struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev)
{
return NULL;
}

View File

@ -13,17 +13,8 @@
#include <asm/types.h>
#include <linux/clk-provider.h>
/**
* struct scmi_clk_priv - Private data for SCMI clocks
* @channel: Reference to the SCMI channel to use
*/
struct scmi_clk_priv {
struct scmi_channel *channel;
};
static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
{
struct scmi_clk_priv *priv = dev_get_priv(dev);
struct scmi_clk_protocol_attr_out out;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_CLOCK,
@ -33,7 +24,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
};
int ret;
ret = devm_scmi_process_msg(dev, priv->channel, &msg);
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
@ -44,7 +35,6 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks)
static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
{
struct scmi_clk_priv *priv = dev_get_priv(dev);
struct scmi_clk_attribute_in in = {
.clock_id = clkid,
};
@ -59,7 +49,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
};
int ret;
ret = devm_scmi_process_msg(dev, priv->channel, &msg);
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
@ -70,7 +60,6 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name)
static int scmi_clk_gate(struct clk *clk, int enable)
{
struct scmi_clk_priv *priv = dev_get_priv(clk->dev);
struct scmi_clk_state_in in = {
.clock_id = clk->id,
.attributes = enable,
@ -81,7 +70,7 @@ static int scmi_clk_gate(struct clk *clk, int enable)
in, out);
int ret;
ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
ret = devm_scmi_process_msg(clk->dev, &msg);
if (ret)
return ret;
@ -100,7 +89,6 @@ static int scmi_clk_disable(struct clk *clk)
static ulong scmi_clk_get_rate(struct clk *clk)
{
struct scmi_clk_priv *priv = dev_get_priv(clk->dev);
struct scmi_clk_rate_get_in in = {
.clock_id = clk->id,
};
@ -110,7 +98,7 @@ static ulong scmi_clk_get_rate(struct clk *clk)
in, out);
int ret;
ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
ret = devm_scmi_process_msg(clk->dev, &msg);
if (ret < 0)
return ret;
@ -123,7 +111,6 @@ static ulong scmi_clk_get_rate(struct clk *clk)
static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
{
struct scmi_clk_priv *priv = dev_get_priv(clk->dev);
struct scmi_clk_rate_set_in in = {
.clock_id = clk->id,
.flags = SCMI_CLK_RATE_ROUND_CLOSEST,
@ -136,7 +123,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
in, out);
int ret;
ret = devm_scmi_process_msg(clk->dev, priv->channel, &msg);
ret = devm_scmi_process_msg(clk->dev, &msg);
if (ret < 0)
return ret;
@ -149,12 +136,11 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate)
static int scmi_clk_probe(struct udevice *dev)
{
struct scmi_clk_priv *priv = dev_get_priv(dev);
struct clk *clk;
size_t num_clocks, i;
int ret;
ret = devm_scmi_of_get_channel(dev, &priv->channel);
ret = devm_scmi_of_get_channel(dev);
if (ret)
return ret;
@ -205,5 +191,4 @@ U_BOOT_DRIVER(scmi_clock) = {
.id = UCLASS_CLK,
.ops = &scmi_clk_ops,
.probe = scmi_clk_probe,
.priv_auto = sizeof(struct scmi_clk_priv *),
};

View File

@ -1,4 +1,5 @@
obj-y += scmi_agent-uclass.o
obj-y += base.o
obj-y += smt.o
obj-$(CONFIG_SCMI_AGENT_SMCCC) += smccc_agent.o
obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o

View File

@ -0,0 +1,664 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* SCMI Base protocol as U-Boot device
*
* Copyright (C) 2023 Linaro Limited
* author: AKASHI Takahiro <takahiro.akashi@linaro.org>
*/
#include <common.h>
#include <dm.h>
#include <scmi_agent.h>
#include <scmi_protocols.h>
#include <stdlib.h>
#include <string.h>
#include <asm/types.h>
#include <dm/device_compat.h>
#include <linux/kernel.h>
/**
* scmi_generic_protocol_version - get protocol version
* @dev: SCMI device
* @id: SCMI protocol ID
* @version: Pointer to SCMI protocol version
*
* Obtain the protocol version number in @version.
*
* Return: 0 on success, error code on failure
*/
int scmi_generic_protocol_version(struct udevice *dev,
enum scmi_std_protocol id, u32 *version)
{
struct scmi_protocol_version_out out;
struct scmi_msg msg = {
.protocol_id = id,
.message_id = SCMI_PROTOCOL_VERSION,
.out_msg = (u8 *)&out,
.out_msg_sz = sizeof(out),
};
int ret;
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
if (out.status)
return scmi_to_linux_errno(out.status);
*version = out.version;
return 0;
}
/**
* scmi_base_protocol_version_int - get Base protocol version
* @dev: SCMI device
* @version: Pointer to SCMI protocol version
*
* Obtain the protocol version number in @version for Base protocol.
*
* Return: 0 on success, error code on failure
*/
static int scmi_base_protocol_version_int(struct udevice *dev, u32 *version)
{
return scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_BASE,
version);
}
/**
* scmi_protocol_attrs_int - get protocol attributes
* @dev: SCMI device
* @num_agents: Number of SCMI agents
* @num_protocols: Number of SCMI protocols
*
* Obtain the protocol attributes, the number of agents and the number
* of protocols, in @num_agents and @num_protocols respectively, that
* the device provides.
*
* Return: 0 on success, error code on failure
*/
static int scmi_protocol_attrs_int(struct udevice *dev, u32 *num_agents,
u32 *num_protocols)
{
struct scmi_protocol_attrs_out out;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.message_id = SCMI_PROTOCOL_ATTRIBUTES,
.out_msg = (u8 *)&out,
.out_msg_sz = sizeof(out),
};
int ret;
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
if (out.status)
return scmi_to_linux_errno(out.status);
*num_agents = SCMI_PROTOCOL_ATTRS_NUM_AGENTS(out.attributes);
*num_protocols = SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(out.attributes);
return 0;
}
/**
* scmi_protocol_message_attrs_int - get message-specific attributes
* @dev: SCMI device
* @message_id: SCMI message ID
* @attributes: Message-specific attributes
*
* Obtain the message-specific attributes in @attributes.
* This command succeeds if the message is implemented and available.
*
* Return: 0 on success, error code on failure
*/
static int scmi_protocol_message_attrs_int(struct udevice *dev, u32 message_id,
u32 *attributes)
{
struct scmi_protocol_msg_attrs_out out;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.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;
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;
}
/**
* scmi_base_discover_vendor_int - get vendor name
* @dev: SCMI device
* @vendor: Pointer to vendor name
*
* Obtain the vendor's name in @vendor.
* It is a caller's responsibility to free @vendor.
*
* Return: 0 on success, error code on failure
*/
static int scmi_base_discover_vendor_int(struct udevice *dev, u8 **vendor)
{
struct scmi_base_discover_vendor_out out;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.message_id = SCMI_BASE_DISCOVER_VENDOR,
.out_msg = (u8 *)&out,
.out_msg_sz = sizeof(out),
};
int ret;
if (!vendor)
return -EINVAL;
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
if (out.status)
return scmi_to_linux_errno(out.status);
*vendor = strdup(out.vendor_identifier);
if (!*vendor)
return -ENOMEM;
return 0;
}
/**
* scmi_base_discover_sub_vendor_int - get sub-vendor name
* @dev: SCMI device
* @sub_vendor: Pointer to sub-vendor name
*
* Obtain the sub-vendor's name in @sub_vendor.
* It is a caller's responsibility to free @sub_vendor.
*
* Return: 0 on success, error code on failure
*/
static int scmi_base_discover_sub_vendor_int(struct udevice *dev,
u8 **sub_vendor)
{
struct scmi_base_discover_vendor_out out;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.message_id = SCMI_BASE_DISCOVER_SUB_VENDOR,
.out_msg = (u8 *)&out,
.out_msg_sz = sizeof(out),
};
int ret;
if (!sub_vendor)
return -EINVAL;
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
if (out.status)
return scmi_to_linux_errno(out.status);
*sub_vendor = strdup(out.vendor_identifier);
if (!*sub_vendor)
return -ENOMEM;
return 0;
}
/**
* scmi_base_discover_impl_version_int - get implementation version
* @dev: SCMI device
* @impl_version: Pointer to implementation version
*
* Obtain the implementation version number in @impl_version.
*
* Return: 0 on success, error code on failure
*/
static int scmi_base_discover_impl_version_int(struct udevice *dev,
u32 *impl_version)
{
struct scmi_base_discover_impl_version_out out;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.message_id = SCMI_BASE_DISCOVER_IMPL_VERSION,
.out_msg = (u8 *)&out,
.out_msg_sz = sizeof(out),
};
int ret;
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
if (out.status)
return scmi_to_linux_errno(out.status);
*impl_version = out.impl_version;
return 0;
}
/**
* scmi_base_discover_list_protocols_int - get list of protocols
* @dev: SCMI device
* @protocols: Pointer to array of SCMI protocols
*
* Obtain the list of protocols provided in @protocols.
* The number of elements in @protocols always match to the number of
* protocols returned by smci_protocol_attrs() when this function succeeds.
* It is a caller's responsibility to free @protocols.
*
* Return: the number of protocols in @protocols on success, error code on
* failure
*/
static int scmi_base_discover_list_protocols_int(struct udevice *dev,
u8 **protocols)
{
struct scmi_base_discover_list_protocols_out out;
int cur;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.message_id = SCMI_BASE_DISCOVER_LIST_PROTOCOLS,
.in_msg = (u8 *)&cur,
.in_msg_sz = sizeof(cur),
.out_msg = (u8 *)&out,
.out_msg_sz = sizeof(out),
};
u32 num_agents, num_protocols;
u8 *buf;
int i, ret;
ret = scmi_base_protocol_attrs(dev, &num_agents, &num_protocols);
if (ret)
return ret;
buf = calloc(sizeof(u8), num_protocols);
if (!buf)
return -ENOMEM;
cur = 0;
do {
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
goto err;
if (out.status) {
ret = scmi_to_linux_errno(out.status);
goto err;
}
for (i = 0; i < out.num_protocols; i++, cur++)
buf[cur] = out.protocols[i / 4] >> ((i % 4) * 8);
} while (cur < num_protocols);
*protocols = buf;
return num_protocols;
err:
free(buf);
return ret;
}
/**
* scmi_base_discover_agent_int - identify agent
* @dev: SCMI device
* @agent_id: SCMI agent ID
* @ret_agent_id: Pointer to SCMI agent ID
* @name: Pointer to SCMI agent name
*
* Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
* this function returns the caller's agent id in @ret_agent_id.
* It is a caller's responsibility to free @name.
*
* Return: 0 on success, error code on failure
*/
static int scmi_base_discover_agent_int(struct udevice *dev, u32 agent_id,
u32 *ret_agent_id, u8 **name)
{
struct scmi_base_discover_agent_out out;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.message_id = SCMI_BASE_DISCOVER_AGENT,
.in_msg = (u8 *)&agent_id,
.in_msg_sz = sizeof(agent_id),
.out_msg = (u8 *)&out,
.out_msg_sz = sizeof(out),
};
int ret;
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
if (out.status)
return scmi_to_linux_errno(out.status);
if (ret_agent_id)
*ret_agent_id = out.agent_id;
if (name) {
*name = strdup(out.name);
if (!*name)
return -ENOMEM;
}
return 0;
}
/**
* scmi_base_set_device_permissions_int - configure access permission to device
* @dev: SCMI device
* @agent_id: SCMI agent ID
* @device_id: ID of device to access
* @flags: A set of flags
*
* Ask for allowing or denying access permission to the device, @device_id.
* The meaning of @flags is defined in SCMI specification.
*
* Return: 0 on success, error code on failure
*/
static int scmi_base_set_device_permissions_int(struct udevice *dev, u32 agent_id,
u32 device_id, u32 flags)
{
struct scmi_base_set_device_permissions_in in = {
.agent_id = agent_id,
.device_id = device_id,
.flags = flags,
};
s32 status;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.message_id = SCMI_BASE_SET_DEVICE_PERMISSIONS,
.in_msg = (u8 *)&in,
.in_msg_sz = sizeof(in),
.out_msg = (u8 *)&status,
.out_msg_sz = sizeof(status),
};
int ret;
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
if (status)
return scmi_to_linux_errno(status);
return 0;
}
/**
* scmi_base_set_protocol_permissions_int - configure access permission to
* protocol on device
* @dev: SCMI device
* @agent_id: SCMI agent ID
* @device_id: ID of device to access
* @command_id: SCMI command ID
* @flags: A set of flags
*
* Ask for allowing or denying access permission to the protocol, @command_id,
* on the device, @device_id.
* The meaning of @flags is defined in SCMI specification.
*
* Return: 0 on success, error code on failure
*/
static int scmi_base_set_protocol_permissions_int(struct udevice *dev,
u32 agent_id, u32 device_id,
u32 command_id, u32 flags)
{
struct scmi_base_set_protocol_permissions_in in = {
.agent_id = agent_id,
.device_id = device_id,
.command_id = command_id,
.flags = flags,
};
s32 status;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.message_id = SCMI_BASE_SET_PROTOCOL_PERMISSIONS,
.in_msg = (u8 *)&in,
.in_msg_sz = sizeof(in),
.out_msg = (u8 *)&status,
.out_msg_sz = sizeof(status),
};
int ret;
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
if (status)
return scmi_to_linux_errno(status);
return 0;
}
/**
* scmi_base_reset_agent_configuration_int - reset resource settings
* @dev: SCMI device
* @agent_id: SCMI agent ID
* @flags: A set of flags
*
* Reset all the resource settings against @agent_id.
* The meaning of @flags is defined in SCMI specification.
*
* Return: 0 on success, error code on failure
*/
static int scmi_base_reset_agent_configuration_int(struct udevice *dev,
u32 agent_id, u32 flags)
{
struct scmi_base_reset_agent_configuration_in in = {
.agent_id = agent_id,
.flags = flags,
};
s32 status;
struct scmi_msg msg = {
.protocol_id = SCMI_PROTOCOL_ID_BASE,
.message_id = SCMI_BASE_RESET_AGENT_CONFIGURATION,
.in_msg = (u8 *)&in,
.in_msg_sz = sizeof(in),
.out_msg = (u8 *)&status,
.out_msg_sz = sizeof(status),
};
int ret;
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
if (status)
return scmi_to_linux_errno(status);
return 0;
}
/**
* scmi_base_probe - probe base protocol device
* @dev: SCMI device
*
* Probe the device for SCMI base protocol and initialize the private data.
*
* Return: 0 on success, error code on failure
*/
static int scmi_base_probe(struct udevice *dev)
{
u32 version;
int ret;
ret = devm_scmi_of_get_channel(dev);
if (ret) {
dev_err(dev, "get_channel failed\n");
return ret;
}
ret = scmi_base_protocol_version_int(dev, &version);
if (ret) {
dev_err(dev, "getting protocol version failed\n");
return ret;
}
if (version < SCMI_BASE_PROTOCOL_VERSION)
return -EINVAL;
return ret;
}
static struct scmi_base_ops scmi_base_ops = {
/* Commands */
.protocol_version = scmi_base_protocol_version_int,
.protocol_attrs = scmi_protocol_attrs_int,
.protocol_message_attrs = scmi_protocol_message_attrs_int,
.base_discover_vendor = scmi_base_discover_vendor_int,
.base_discover_sub_vendor = scmi_base_discover_sub_vendor_int,
.base_discover_impl_version = scmi_base_discover_impl_version_int,
.base_discover_list_protocols = scmi_base_discover_list_protocols_int,
.base_discover_agent = scmi_base_discover_agent_int,
.base_notify_errors = NULL,
.base_set_device_permissions = scmi_base_set_device_permissions_int,
.base_set_protocol_permissions = scmi_base_set_protocol_permissions_int,
.base_reset_agent_configuration =
scmi_base_reset_agent_configuration_int,
};
int scmi_base_protocol_version(struct udevice *dev, u32 *version)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->protocol_version)
return (*ops->protocol_version)(dev, version);
return -EOPNOTSUPP;
}
int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
u32 *num_protocols)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->protocol_attrs)
return (*ops->protocol_attrs)(dev, num_agents, num_protocols);
return -EOPNOTSUPP;
}
int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
u32 *attributes)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->protocol_message_attrs)
return (*ops->protocol_message_attrs)(dev, message_id,
attributes);
return -EOPNOTSUPP;
}
int scmi_base_discover_vendor(struct udevice *dev, u8 **vendor)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->base_discover_vendor)
return (*ops->base_discover_vendor)(dev, vendor);
return -EOPNOTSUPP;
}
int scmi_base_discover_sub_vendor(struct udevice *dev, u8 **sub_vendor)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->base_discover_sub_vendor)
return (*ops->base_discover_sub_vendor)(dev, sub_vendor);
return -EOPNOTSUPP;
}
int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->base_discover_impl_version)
return (*ops->base_discover_impl_version)(dev, impl_version);
return -EOPNOTSUPP;
}
int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->base_discover_list_protocols)
return (*ops->base_discover_list_protocols)(dev, protocols);
return -EOPNOTSUPP;
}
int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
u32 *ret_agent_id, u8 **name)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->base_discover_agent)
return (*ops->base_discover_agent)(dev, agent_id, ret_agent_id,
name);
return -EOPNOTSUPP;
}
int scmi_base_notify_errors(struct udevice *dev, u32 enable)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->base_notify_errors)
return (*ops->base_notify_errors)(dev, enable);
return -EOPNOTSUPP;
}
int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
u32 device_id, u32 flags)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->base_set_device_permissions)
return (*ops->base_set_device_permissions)(dev, agent_id,
device_id, flags);
return -EOPNOTSUPP;
}
int scmi_base_set_protocol_permissions(struct udevice *dev,
u32 agent_id, u32 device_id,
u32 command_id, u32 flags)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->base_set_protocol_permissions)
return (*ops->base_set_protocol_permissions)(dev, agent_id,
device_id,
command_id,
flags);
return -EOPNOTSUPP;
}
int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
u32 flags)
{
const struct scmi_base_ops *ops = device_get_ops(dev);
if (ops->base_reset_agent_configuration)
return (*ops->base_reset_agent_configuration)(dev, agent_id,
flags);
return -EOPNOTSUPP;
}
U_BOOT_DRIVER(scmi_base_drv) = {
.id = UCLASS_SCMI_BASE,
.name = "scmi_base_drv",
.ops = &scmi_base_ops,
.probe = scmi_base_probe,
};
UCLASS_DRIVER(scmi_base) = {
.id = UCLASS_SCMI_BASE,
.name = "scmi_base",
};

View File

@ -94,13 +94,14 @@ static int setup_channel(struct udevice *dev, struct scmi_mbox_channel *chan)
}
static int scmi_mbox_get_channel(struct udevice *dev,
struct udevice *protocol,
struct scmi_channel **channel)
{
struct scmi_mbox_channel *base_chan = dev_get_plat(dev);
struct scmi_mbox_channel *chan;
int ret;
if (!dev_read_prop(dev, "shmem", NULL)) {
if (!dev_read_prop(protocol, "shmem", NULL)) {
/* Uses agent base channel */
*channel = container_of(base_chan, struct scmi_channel, ref);
@ -112,7 +113,7 @@ static int scmi_mbox_get_channel(struct udevice *dev,
return -ENOMEM;
/* Setup a dedicated channel for the protocol */
ret = setup_channel(dev, chan);
ret = setup_channel(protocol, chan);
if (ret) {
free(chan);
return ret;

View File

@ -149,7 +149,7 @@ static int open_channel(struct udevice *dev, struct scmi_optee_channel *chan,
struct tee_param param[1] = { };
int ret;
memset(sess, 0, sizeof(sess));
memset(sess, 0, sizeof(*sess));
sess->tee = tee_find_device(NULL, NULL, NULL, NULL);
if (!sess->tee)
@ -324,6 +324,7 @@ static int setup_channel(struct udevice *dev, struct scmi_optee_channel *chan)
}
static int scmi_optee_get_channel(struct udevice *dev,
struct udevice *protocol,
struct scmi_channel **channel)
{
struct scmi_optee_channel *base_chan = dev_get_plat(dev);
@ -331,7 +332,7 @@ static int scmi_optee_get_channel(struct udevice *dev,
u32 channel_id;
int ret;
if (dev_read_u32(dev, "linaro,optee-channel-id", &channel_id)) {
if (dev_read_u32(protocol, "linaro,optee-channel-id", &channel_id)) {
/* Uses agent base channel */
*channel = container_of(base_chan, struct scmi_channel, ref);
@ -343,7 +344,7 @@ static int scmi_optee_get_channel(struct udevice *dev,
if (!chan)
return -ENOMEM;
ret = setup_channel(dev, chan);
ret = setup_channel(protocol, chan);
if (ret) {
free(chan);
return ret;

View File

@ -14,11 +14,14 @@
#include <asm/io.h>
#include <asm/scmi_test.h>
#include <dm/device_compat.h>
#include <linux/bitfield.h>
#include <linux/kernel.h>
/*
* The sandbox SCMI agent driver simulates to some extend a SCMI message
* processing. It simulates few of the SCMI services for some of the
* SCMI protocols embedded in U-Boot. Currently:
* - SCMI base protocol
* - SCMI clock protocol emulates an agent exposing 2 clocks
* - SCMI reset protocol emulates an agent exposing a reset controller
* - SCMI voltage domain protocol emulates an agent exposing 2 regulators
@ -33,6 +36,41 @@
* various uclass devices, as clocks and reset controllers.
*/
#define SANDBOX_SCMI_BASE_PROTOCOL_VERSION SCMI_BASE_PROTOCOL_VERSION
#define SANDBOX_SCMI_VENDOR "U-Boot"
#define SANDBOX_SCMI_SUB_VENDOR "Sandbox"
#define SANDBOX_SCMI_IMPL_VERSION 0x1
#define SANDBOX_SCMI_AGENT_NAME "OSPM"
#define SANDBOX_SCMI_PLATFORM_NAME "platform"
/**
* struct sandbox_channel - Description of sandbox transport
* @channel_id: Channel identifier
*
* Dummy channel. This will be used to test if a protocol-specific
* channel is properly used.
* Id 0 means a channel for the sandbox agent.
*/
struct sandbox_channel {
unsigned int channel_id;
};
/**
* struct scmi_channel - Channel instance referenced in SCMI drivers
* @ref: Reference to local channel instance
**/
struct scmi_channel {
struct sandbox_channel ref;
};
static u8 protocols[] = {
SCMI_PROTOCOL_ID_CLOCK,
SCMI_PROTOCOL_ID_RESET_DOMAIN,
SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
};
#define NUM_PROTOCOLS ARRAY_SIZE(protocols)
static struct sandbox_scmi_clk scmi_clk[] = {
{ .rate = 333 },
{ .rate = 200 },
@ -48,11 +86,9 @@ static struct sandbox_scmi_voltd scmi_voltd[] = {
{ .id = 1, .voltage_uv = 1800000 },
};
static struct sandbox_scmi_service sandbox_scmi_service_state;
struct sandbox_scmi_service *sandbox_scmi_service_ctx(void)
struct sandbox_scmi_agent *sandbox_scmi_agent_ctx(struct udevice *dev)
{
return &sandbox_scmi_service_state;
return dev_get_priv(dev);
}
static void debug_print_agent_state(struct udevice *dev, char *str)
@ -114,6 +150,316 @@ static struct sandbox_scmi_voltd *get_scmi_voltd_state(uint domain_id)
* Sandbox SCMI agent ops
*/
/* Base Protocol */
/**
* sandbox_scmi_base_protocol_version - implement SCMI_BASE_PROTOCOL_VERSION
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_PROTOCOL_VERSION command.
*/
static int sandbox_scmi_base_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_BASE_PROTOCOL_VERSION;
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_base_protocol_attrs - implement SCMI_BASE_PROTOCOL_ATTRIBUTES
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_PROTOCOL_ATTRIBUTES command.
*/
static int sandbox_scmi_base_protocol_attrs(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_protocol_attrs_out *out = NULL;
if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
out = (struct scmi_protocol_attrs_out *)msg->out_msg;
out->attributes = FIELD_PREP(0xff00, 2) | NUM_PROTOCOLS;
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_base_message_attrs - implement
* SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_PROTOCOL_MESSAGE_ATTRIBUTES command.
*/
static int sandbox_scmi_base_message_attrs(struct udevice *dev,
struct scmi_msg *msg)
{
u32 message_id;
struct scmi_protocol_msg_attrs_out *out = NULL;
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_protocol_msg_attrs_out *)msg->out_msg;
if (message_id >= SCMI_PROTOCOL_VERSION &&
message_id <= SCMI_BASE_RESET_AGENT_CONFIGURATION &&
message_id != SCMI_BASE_NOTIFY_ERRORS) {
out->attributes = 0;
out->status = SCMI_SUCCESS;
} else {
out->status = SCMI_NOT_FOUND;
}
return 0;
}
/**
* sandbox_scmi_base_discover_vendor - implement SCMI_BASE_DISCOVER_VENDOR
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_DISCOVER_VENDOR command
*/
static int sandbox_scmi_base_discover_vendor(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_base_discover_vendor_out *out = NULL;
if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
strcpy(out->vendor_identifier, SANDBOX_SCMI_VENDOR);
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_base_discover_sub_vendor - implement
* SCMI_BASE_DISCOVER_SUB_VENDOR
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_DISCOVER_SUB_VENDOR command
*/
static int sandbox_scmi_base_discover_sub_vendor(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_base_discover_vendor_out *out = NULL;
if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
out = (struct scmi_base_discover_vendor_out *)msg->out_msg;
strcpy(out->vendor_identifier, SANDBOX_SCMI_SUB_VENDOR);
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_base_discover_impl_version - implement
* SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_DISCOVER_IMPLEMENTATION_VERSION command
*/
static int sandbox_scmi_base_discover_impl_version(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_base_discover_impl_version_out *out = NULL;
if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
out = (struct scmi_base_discover_impl_version_out *)msg->out_msg;
out->impl_version = SANDBOX_SCMI_IMPL_VERSION;
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_base_discover_list_protocols - implement
* SCMI_BASE_DISCOVER_LIST_PROTOCOLS
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
*/
static int sandbox_scmi_base_discover_list_protocols(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_base_discover_list_protocols_out *out = NULL;
if (!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
out = (struct scmi_base_discover_list_protocols_out *)msg->out_msg;
memcpy(out->protocols, protocols, sizeof(protocols));
out->num_protocols = NUM_PROTOCOLS;
out->status = SCMI_SUCCESS;
return 0;
}
/**
* sandbox_scmi_base_discover_agent - implement SCMI_BASE_DISCOVER_AGENT
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_DISCOVER_AGENT command
*/
static int sandbox_scmi_base_discover_agent(struct udevice *dev,
struct scmi_msg *msg)
{
u32 agent_id;
struct scmi_base_discover_agent_out *out = NULL;
if (!msg->in_msg || msg->in_msg_sz < sizeof(agent_id) ||
!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
agent_id = *(u32 *)msg->in_msg;
out = (struct scmi_base_discover_agent_out *)msg->out_msg;
out->status = SCMI_SUCCESS;
if (agent_id == 0xffffffff || agent_id == 1) {
out->agent_id = 1;
strcpy(out->name, SANDBOX_SCMI_AGENT_NAME);
} else if (!agent_id) {
out->agent_id = agent_id;
strcpy(out->name, SANDBOX_SCMI_PLATFORM_NAME);
} else {
out->status = SCMI_NOT_FOUND;
}
return 0;
}
/**
* sandbox_scmi_base_set_device_permissions - implement
* SCMI_BASE_SET_DEVICE_PERMISSIONS
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_SET_DEVICE_PERMISSIONS command
*/
static int sandbox_scmi_base_set_device_permissions(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_base_set_device_permissions_in *in = NULL;
u32 *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_base_set_device_permissions_in *)msg->in_msg;
status = (u32 *)msg->out_msg;
if (in->agent_id != 1 || in->device_id != 0)
*status = SCMI_NOT_FOUND;
else if (in->flags & ~SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
*status = SCMI_INVALID_PARAMETERS;
else if (in->flags & SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS)
*status = SCMI_SUCCESS;
else
/* unset not allowed */
*status = SCMI_DENIED;
return 0;
}
/**
* sandbox_scmi_base_set_protocol_permissions - implement
* SCMI_BASE_SET_PROTOCOL_PERMISSIONS
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
*/
static int sandbox_scmi_base_set_protocol_permissions(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_base_set_protocol_permissions_in *in = NULL;
u32 *status;
int i;
if (!msg->in_msg || msg->in_msg_sz < sizeof(*in) ||
!msg->out_msg || msg->out_msg_sz < sizeof(*status))
return -EINVAL;
in = (struct scmi_base_set_protocol_permissions_in *)msg->in_msg;
status = (u32 *)msg->out_msg;
for (i = 0; i < ARRAY_SIZE(protocols); i++)
if (protocols[i] == in->command_id)
break;
if (in->agent_id != 1 || in->device_id != 0 ||
i == ARRAY_SIZE(protocols))
*status = SCMI_NOT_FOUND;
else if (in->flags & ~SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
*status = SCMI_INVALID_PARAMETERS;
else if (in->flags & SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS)
*status = SCMI_SUCCESS;
else
/* unset not allowed */
*status = SCMI_DENIED;
return 0;
}
/**
* sandbox_scmi_base_reset_agent_configuration - implement
* SCMI_BASE_RESET_AGENT_CONFIGURATION
* @dev: SCMI device
* @msg: SCMI message
*
* Implement SCMI_BASE_RESET_AGENT_CONFIGURATION command
*/
static int sandbox_scmi_base_reset_agent_configuration(struct udevice *dev,
struct scmi_msg *msg)
{
struct scmi_base_reset_agent_configuration_in *in = NULL;
u32 *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_base_reset_agent_configuration_in *)msg->in_msg;
status = (u32 *)msg->out_msg;
if (in->agent_id != 1)
*status = SCMI_NOT_FOUND;
else if (in->flags & ~SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS)
*status = SCMI_INVALID_PARAMETERS;
else
*status = SCMI_DENIED;
return 0;
}
/* Clock Protocol */
static int sandbox_scmi_clock_protocol_attribs(struct udevice *dev,
struct scmi_msg *msg)
{
@ -470,11 +816,108 @@ static int sandbox_scmi_voltd_level_get(struct udevice *dev,
return 0;
}
/**
* sandbox_scmi_of_get_channel - assigne a channel
* @dev: SCMI agent device
* @protocol: SCMI protocol device
* @channel: Pointer to channel info
*
* Assign a channel for the protocol, @protocol, in @channel,
* based on a device tree's property.
*
* Return: 0 on success, error code on failure
*/
static int sandbox_scmi_of_get_channel(struct udevice *dev,
struct udevice *protocol,
struct scmi_channel **channel)
{
struct sandbox_channel *agent_chan = dev_get_plat(dev);
struct sandbox_channel *chan;
u32 channel_id;
if (dev_read_u32(protocol, "linaro,sandbox-channel-id", &channel_id)) {
/* Uses agent channel */
*channel = container_of(agent_chan, struct scmi_channel, ref);
return 0;
}
/* Setup a dedicated channel */
chan = calloc(1, sizeof(*chan));
if (!chan)
return -ENOMEM;
chan->channel_id = channel_id;
*channel = container_of(chan, struct scmi_channel, ref);
return 0;
}
/**
* sandbox_scmi_of_to_plat - assigne a channel to agent
* @dev: SCMI agent device
*
* Assign a channel for the agent, @protocol.
*
* Return: always 0
*/
static int sandbox_scmi_of_to_plat(struct udevice *dev)
{
struct sandbox_channel *chan = dev_get_plat(dev);
/* The channel for agent is always 0 */
chan->channel_id = 0;
return 0;
}
unsigned int sandbox_scmi_channel_id(struct udevice *dev)
{
struct scmi_agent_proto_priv *priv;
struct sandbox_channel *chan;
priv = dev_get_parent_priv(dev);
chan = (struct sandbox_channel *)&priv->channel->ref;
return chan->channel_id;
}
static int sandbox_scmi_test_process_msg(struct udevice *dev,
struct scmi_channel *channel,
struct scmi_msg *msg)
{
switch (msg->protocol_id) {
case SCMI_PROTOCOL_ID_BASE:
switch (msg->message_id) {
case SCMI_PROTOCOL_VERSION:
return sandbox_scmi_base_protocol_version(dev, msg);
case SCMI_PROTOCOL_ATTRIBUTES:
return sandbox_scmi_base_protocol_attrs(dev, msg);
case SCMI_PROTOCOL_MESSAGE_ATTRIBUTES:
return sandbox_scmi_base_message_attrs(dev, msg);
case SCMI_BASE_DISCOVER_VENDOR:
return sandbox_scmi_base_discover_vendor(dev, msg);
case SCMI_BASE_DISCOVER_SUB_VENDOR:
return sandbox_scmi_base_discover_sub_vendor(dev, msg);
case SCMI_BASE_DISCOVER_IMPL_VERSION:
return sandbox_scmi_base_discover_impl_version(dev, msg);
case SCMI_BASE_DISCOVER_LIST_PROTOCOLS:
return sandbox_scmi_base_discover_list_protocols(dev, msg);
case SCMI_BASE_DISCOVER_AGENT:
return sandbox_scmi_base_discover_agent(dev, msg);
case SCMI_BASE_NOTIFY_ERRORS:
break;
case SCMI_BASE_SET_DEVICE_PERMISSIONS:
return sandbox_scmi_base_set_device_permissions(dev, msg);
case SCMI_BASE_SET_PROTOCOL_PERMISSIONS:
return sandbox_scmi_base_set_protocol_permissions(dev, msg);
case SCMI_BASE_RESET_AGENT_CONFIGURATION:
return sandbox_scmi_base_reset_agent_configuration(dev, msg);
default:
break;
}
break;
case SCMI_PROTOCOL_ID_CLOCK:
switch (msg->message_id) {
case SCMI_PROTOCOL_ATTRIBUTES:
@ -517,7 +960,6 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
break;
}
break;
case SCMI_PROTOCOL_ID_BASE:
case SCMI_PROTOCOL_ID_POWER_DOMAIN:
case SCMI_PROTOCOL_ID_SYSTEM:
case SCMI_PROTOCOL_ID_PERF:
@ -541,16 +983,8 @@ static int sandbox_scmi_test_process_msg(struct udevice *dev,
static int sandbox_scmi_test_remove(struct udevice *dev)
{
struct sandbox_scmi_agent *agent = dev_get_priv(dev);
if (agent != sandbox_scmi_service_ctx()->agent)
return -EINVAL;
debug_print_agent_state(dev, "removed");
/* We only need to dereference the agent in the context */
sandbox_scmi_service_ctx()->agent = NULL;
return 0;
}
@ -558,9 +992,6 @@ static int sandbox_scmi_test_probe(struct udevice *dev)
{
struct sandbox_scmi_agent *agent = dev_get_priv(dev);
if (sandbox_scmi_service_ctx()->agent)
return -EINVAL;
*agent = (struct sandbox_scmi_agent){
.clk = scmi_clk,
.clk_count = ARRAY_SIZE(scmi_clk),
@ -572,9 +1003,6 @@ static int sandbox_scmi_test_probe(struct udevice *dev)
debug_print_agent_state(dev, "probed");
/* Save reference for tests purpose */
sandbox_scmi_service_ctx()->agent = agent;
return 0;
};
@ -584,6 +1012,7 @@ static const struct udevice_id sandbox_scmi_test_ids[] = {
};
struct scmi_agent_ops sandbox_scmi_test_ops = {
.of_get_channel = sandbox_scmi_of_get_channel,
.process_msg = sandbox_scmi_test_process_msg,
};
@ -592,6 +1021,8 @@ U_BOOT_DRIVER(sandbox_scmi_agent) = {
.id = UCLASS_SCMI_AGENT,
.of_match = sandbox_scmi_test_ids,
.priv_auto = sizeof(struct sandbox_scmi_agent),
.plat_auto = sizeof(struct sandbox_channel),
.of_to_plat = sandbox_scmi_of_to_plat,
.probe = sandbox_scmi_test_probe,
.remove = sandbox_scmi_test_remove,
.ops = &sandbox_scmi_test_ops,

View File

@ -8,6 +8,7 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
#include <dm/device_compat.h>
@ -37,6 +38,118 @@ static const struct error_code scmi_linux_errmap[] = {
{ .scmi = SCMI_PROTOCOL_ERROR, .errno = -EPROTO, },
};
/**
* scmi_protocol_is_supported - check availability of protocol
* @dev: SCMI agent device
* @proto_id: Identifier of protocol
*
* check if the protocol, @proto_id, is provided by the SCMI agent,
* @dev.
*
* Return: 0 on success, error code otherwise
*/
static bool scmi_protocol_is_supported(struct udevice *dev,
enum scmi_std_protocol proto_id)
{
struct scmi_agent_priv *priv;
int i;
if (proto_id == SCMI_PROTOCOL_ID_BASE)
return true;
priv = dev_get_uclass_plat(dev);
if (!priv) {
dev_err(dev, "No priv data found\n");
return false;
}
for (i = 0; i < priv->num_protocols; i++)
if (priv->protocols[i] == proto_id)
return true;
return false;
}
struct udevice *scmi_get_protocol(struct udevice *dev,
enum scmi_std_protocol id)
{
struct scmi_agent_priv *priv;
struct udevice *proto;
priv = dev_get_uclass_plat(dev);
if (!priv) {
dev_err(dev, "No priv data found\n");
return NULL;
}
switch (id) {
case SCMI_PROTOCOL_ID_BASE:
proto = priv->base_dev;
break;
case SCMI_PROTOCOL_ID_CLOCK:
proto = priv->clock_dev;
break;
case SCMI_PROTOCOL_ID_RESET_DOMAIN:
proto = priv->resetdom_dev;
break;
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
proto = priv->voltagedom_dev;
break;
default:
dev_err(dev, "Protocol not supported\n");
proto = NULL;
break;
}
if (proto && device_probe(proto))
dev_err(dev, "Probe failed\n");
return proto;
}
/**
* scmi_add_protocol - add protocol to agent
* @dev: SCMI agent device
* @proto_id: SCMI protocol ID
* @proto: SCMI protocol device
*
* Associate the protocol instance, @proto, to the agent, @dev,
* for later use.
*
* Return: 0 on success, error code on failure
*/
static int scmi_add_protocol(struct udevice *dev,
enum scmi_std_protocol proto_id,
struct udevice *proto)
{
struct scmi_agent_priv *priv;
priv = dev_get_uclass_plat(dev);
if (!priv) {
dev_err(dev, "No priv data found\n");
return -ENODEV;
}
switch (proto_id) {
case SCMI_PROTOCOL_ID_BASE:
priv->base_dev = proto;
break;
case SCMI_PROTOCOL_ID_CLOCK:
priv->clock_dev = proto;
break;
case SCMI_PROTOCOL_ID_RESET_DOMAIN:
priv->resetdom_dev = proto;
break;
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
priv->voltagedom_dev = proto;
break;
default:
dev_err(dev, "Protocol not supported\n");
return -EPROTO;
}
return 0;
}
int scmi_to_linux_errno(s32 scmi_code)
{
int n;
@ -51,8 +164,191 @@ int scmi_to_linux_errno(s32 scmi_code)
return -EPROTO;
}
static struct udevice *find_scmi_protocol_device(struct udevice *dev)
{
struct udevice *parent = NULL, *protocol;
for (protocol = dev; protocol; protocol = parent) {
parent = dev_get_parent(protocol);
if (!parent ||
device_get_uclass_id(parent) == UCLASS_SCMI_AGENT)
break;
}
if (!parent) {
dev_err(dev, "Invalid SCMI device, agent not found\n");
return NULL;
}
return protocol;
}
static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
{
return (const struct scmi_agent_ops *)dev->driver->ops;
}
/**
* scmi_of_get_channel() - Get SCMI channel handle
*
* @dev: SCMI agent device
* @channel: Output reference to the SCMI channel upon success
*
* On return, @channel will be set.
* Return 0 on success and a negative errno on failure
*/
static int scmi_of_get_channel(struct udevice *dev, struct udevice *protocol,
struct scmi_channel **channel)
{
const struct scmi_agent_ops *ops;
ops = transport_dev_ops(dev);
if (ops->of_get_channel)
return ops->of_get_channel(dev, protocol, channel);
else
return -EPROTONOSUPPORT;
}
int devm_scmi_of_get_channel(struct udevice *dev)
{
struct udevice *protocol;
struct scmi_agent_proto_priv *priv;
int ret;
protocol = find_scmi_protocol_device(dev);
if (!protocol)
return -ENODEV;
priv = dev_get_parent_priv(protocol);
ret = scmi_of_get_channel(protocol->parent, protocol, &priv->channel);
if (ret == -EPROTONOSUPPORT) {
/* Drivers without a get_channel operator don't need a channel ref */
priv->channel = NULL;
return 0;
}
return ret;
}
/**
* scmi_process_msg() - Send and process an SCMI message
*
* Send a message to an SCMI server.
* Caller sets scmi_msg::out_msg_sz to the output message buffer size.
*
* @dev: SCMI agent device
* @channel: Communication channel for the device
* @msg: Message structure reference
*
* On return, scmi_msg::out_msg_sz stores the response payload size.
* Return: 0 on success and a negative errno on failure
*/
static int scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg)
{
const struct scmi_agent_ops *ops;
ops = transport_dev_ops(dev);
if (ops->process_msg)
return ops->process_msg(dev, channel, msg);
else
return -EPROTONOSUPPORT;
}
int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg)
{
struct udevice *protocol;
struct scmi_agent_proto_priv *priv;
protocol = find_scmi_protocol_device(dev);
if (!protocol)
return -ENODEV;
priv = dev_get_parent_priv(protocol);
return scmi_process_msg(protocol->parent, priv->channel, msg);
}
/**
* scmi_fill_base_info - get base information about SCMI server
* @agent: SCMI agent device
* @dev: SCMI protocol device
*
* By using Base protocol commands, collect the base information
* about SCMI server.
*
* Return: 0 on success, error code on failure
*/
static int scmi_fill_base_info(struct udevice *agent, struct udevice *dev)
{
struct scmi_agent_priv *priv = dev_get_uclass_plat(agent);
int ret;
ret = scmi_base_protocol_version(dev, &priv->version);
if (ret) {
dev_err(dev, "protocol_version() failed (%d)\n", ret);
return ret;
}
/* check for required version */
if (priv->version < SCMI_BASE_PROTOCOL_VERSION) {
dev_err(dev, "base protocol version (%d) lower than expected\n",
priv->version);
return -EPROTO;
}
ret = scmi_base_protocol_attrs(dev, &priv->num_agents,
&priv->num_protocols);
if (ret) {
dev_err(dev, "protocol_attrs() failed (%d)\n", ret);
return ret;
}
ret = scmi_base_discover_vendor(dev, &priv->vendor);
if (ret) {
dev_err(dev, "base_discover_vendor() failed (%d)\n", ret);
return ret;
}
ret = scmi_base_discover_sub_vendor(dev, &priv->sub_vendor);
if (ret) {
if (ret != -EOPNOTSUPP) {
dev_err(dev, "base_discover_sub_vendor() failed (%d)\n",
ret);
return ret;
}
priv->sub_vendor = "NA";
}
ret = scmi_base_discover_impl_version(dev, &priv->impl_version);
if (ret) {
dev_err(dev, "base_discover_impl_version() failed (%d)\n",
ret);
return ret;
}
ret = scmi_base_discover_agent(dev, 0xffffffff,
&priv->agent_id, &priv->agent_name);
if (ret) {
if (ret != -EOPNOTSUPP) {
dev_err(dev,
"base_discover_agent() failed for myself (%d)\n",
ret);
return ret;
}
priv->agent_id = 0xffffffff;
priv->agent_name = "NA";
}
ret = scmi_base_discover_list_protocols(dev, &priv->protocols);
if (ret != priv->num_protocols) {
dev_err(dev, "base_discover_list_protocols() failed (%d)\n",
ret);
return -EPROTO;
}
return 0;
}
/*
* SCMI agent devices binds devices of various uclasses depeding on
* SCMI agent devices binds devices of various uclasses depending on
* the FDT description. scmi_bind_protocol() is a generic bind sequence
* called by the uclass at bind stage, that is uclass post_bind.
*/
@ -61,9 +357,43 @@ static int scmi_bind_protocols(struct udevice *dev)
int ret = 0;
ofnode node;
const char *name;
struct driver *drv;
struct udevice *agent, *proto;
if (!uclass_get_device(UCLASS_SCMI_AGENT, 1, &agent)) {
/* This is a second SCMI agent */
dev_err(dev, "Cannot have more than one SCMI agent\n");
return -EEXIST;
}
/* initialize the device from device tree */
drv = DM_DRIVER_GET(scmi_base_drv);
name = "scmi-base.0";
ret = device_bind(dev, drv, name, NULL, ofnode_null(), &proto);
if (ret) {
dev_err(dev, "failed to bind base protocol\n");
return ret;
}
ret = scmi_add_protocol(dev, SCMI_PROTOCOL_ID_BASE, proto);
if (ret) {
dev_err(dev, "failed to add protocol: %s, ret: %d\n",
proto->name, ret);
return ret;
}
ret = device_probe(proto);
if (ret) {
dev_err(dev, "failed to probe base protocol\n");
return ret;
}
ret = scmi_fill_base_info(dev, proto);
if (ret) {
dev_err(dev, "failed to get base information\n");
return ret;
}
dev_for_each_subnode(node, dev) {
struct driver *drv = NULL;
u32 protocol_id;
if (!ofnode_is_enabled(node))
@ -72,18 +402,22 @@ static int scmi_bind_protocols(struct udevice *dev)
if (ofnode_read_u32(node, "reg", &protocol_id))
continue;
drv = NULL;
name = ofnode_get_name(node);
switch (protocol_id) {
case SCMI_PROTOCOL_ID_CLOCK:
if (CONFIG_IS_ENABLED(CLK_SCMI))
if (CONFIG_IS_ENABLED(CLK_SCMI) &&
scmi_protocol_is_supported(dev, protocol_id))
drv = DM_DRIVER_GET(scmi_clock);
break;
case SCMI_PROTOCOL_ID_RESET_DOMAIN:
if (IS_ENABLED(CONFIG_RESET_SCMI))
if (IS_ENABLED(CONFIG_RESET_SCMI) &&
scmi_protocol_is_supported(dev, protocol_id))
drv = DM_DRIVER_GET(scmi_reset_domain);
break;
case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN:
if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI)) {
if (IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) &&
scmi_protocol_is_supported(dev, protocol_id)) {
node = ofnode_find_subnode(node, "regulators");
if (!ofnode_valid(node)) {
dev_err(dev, "no regulators node\n");
@ -102,70 +436,26 @@ static int scmi_bind_protocols(struct udevice *dev)
continue;
}
ret = device_bind(dev, drv, name, NULL, node, NULL);
if (ret)
ret = device_bind(dev, drv, name, NULL, node, &proto);
if (ret) {
dev_err(dev, "failed to bind %s protocol\n", drv->name);
break;
}
ret = scmi_add_protocol(dev, protocol_id, proto);
if (ret) {
dev_err(dev, "failed to add protocol: %s, ret: %d\n",
proto->name, ret);
break;
}
}
return ret;
}
static struct udevice *find_scmi_transport_device(struct udevice *dev)
{
struct udevice *parent = dev;
do {
parent = dev_get_parent(parent);
} while (parent && device_get_uclass_id(parent) != UCLASS_SCMI_AGENT);
if (!parent)
dev_err(dev, "Invalid SCMI device, agent not found\n");
return parent;
}
static const struct scmi_agent_ops *transport_dev_ops(struct udevice *dev)
{
return (const struct scmi_agent_ops *)dev->driver->ops;
}
int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
{
struct udevice *parent;
parent = find_scmi_transport_device(dev);
if (!parent)
return -ENODEV;
if (transport_dev_ops(parent)->of_get_channel)
return transport_dev_ops(parent)->of_get_channel(parent, channel);
/* Drivers without a get_channel operator don't need a channel ref */
*channel = NULL;
return 0;
}
int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg)
{
const struct scmi_agent_ops *ops;
struct udevice *parent;
parent = find_scmi_transport_device(dev);
if (!parent)
return -ENODEV;
ops = transport_dev_ops(parent);
if (ops->process_msg)
return ops->process_msg(parent, channel, msg);
return -EPROTONOSUPPORT;
}
UCLASS_DRIVER(scmi_agent) = {
.id = UCLASS_SCMI_AGENT,
.name = "scmi_agent",
.post_bind = scmi_bind_protocols,
.per_device_plat_auto = sizeof(struct scmi_agent_priv),
.per_child_auto = sizeof(struct scmi_agent_proto_priv),
};

View File

@ -81,6 +81,7 @@ static int setup_channel(struct udevice *dev, struct scmi_smccc_channel *chan)
}
static int scmi_smccc_get_channel(struct udevice *dev,
struct udevice *protocol,
struct scmi_channel **channel)
{
struct scmi_smccc_channel *base_chan = dev_get_plat(dev);
@ -88,7 +89,7 @@ static int scmi_smccc_get_channel(struct udevice *dev,
u32 func_id;
int ret;
if (dev_read_u32(dev, "arm,smc-id", &func_id)) {
if (dev_read_u32(protocol, "arm,smc-id", &func_id)) {
/* Uses agent base channel */
*channel = container_of(base_chan, struct scmi_channel, ref);
@ -100,7 +101,7 @@ static int scmi_smccc_get_channel(struct udevice *dev,
if (!chan)
return -ENOMEM;
ret = setup_channel(dev, chan);
ret = setup_channel(protocol, chan);
if (ret) {
free(chan);
return ret;

View File

@ -25,18 +25,9 @@ struct scmi_regulator_platdata {
u32 domain_id;
};
/**
* struct scmi_regulator_priv - Private data for SCMI voltage regulator
* @channel: Reference to the SCMI channel to use
*/
struct scmi_regulator_priv {
struct scmi_channel *channel;
};
static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
{
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_voltd_config_set_in in = {
.domain_id = pdata->domain_id,
.config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
@ -47,7 +38,7 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
in, out);
int ret;
ret = devm_scmi_process_msg(dev, priv->channel, &msg);
ret = devm_scmi_process_msg(dev, &msg);
if (ret)
return ret;
@ -57,7 +48,6 @@ static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
static int scmi_voltd_get_enable(struct udevice *dev)
{
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_voltd_config_get_in in = {
.domain_id = pdata->domain_id,
};
@ -67,7 +57,7 @@ static int scmi_voltd_get_enable(struct udevice *dev)
in, out);
int ret;
ret = devm_scmi_process_msg(dev, priv->channel, &msg);
ret = devm_scmi_process_msg(dev, &msg);
if (ret < 0)
return ret;
@ -80,7 +70,6 @@ static int scmi_voltd_get_enable(struct udevice *dev)
static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
{
struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
struct scmi_voltd_level_set_in in = {
.domain_id = pdata->domain_id,
@ -92,7 +81,7 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
in, out);
int ret;
ret = devm_scmi_process_msg(dev, priv->channel, &msg);
ret = devm_scmi_process_msg(dev, &msg);
if (ret < 0)
return ret;
@ -101,7 +90,6 @@ static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
static int scmi_voltd_get_voltage_level(struct udevice *dev)
{
struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
struct scmi_voltd_level_get_in in = {
.domain_id = pdata->domain_id,
@ -112,7 +100,7 @@ static int scmi_voltd_get_voltage_level(struct udevice *dev)
in, out);
int ret;
ret = devm_scmi_process_msg(dev, priv->channel, &msg);
ret = devm_scmi_process_msg(dev, &msg);
if (ret < 0)
return ret;
@ -140,7 +128,6 @@ static int scmi_regulator_of_to_plat(struct udevice *dev)
static int scmi_regulator_probe(struct udevice *dev)
{
struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
struct scmi_regulator_priv *priv = dev_get_priv(dev);
struct scmi_voltd_attr_in in = { 0 };
struct scmi_voltd_attr_out out = { 0 };
struct scmi_msg scmi_msg = {
@ -153,14 +140,14 @@ static int scmi_regulator_probe(struct udevice *dev)
};
int ret;
ret = devm_scmi_of_get_channel(dev->parent, &priv->channel);
ret = devm_scmi_of_get_channel(dev);
if (ret)
return ret;
/* Check voltage domain is known from SCMI server */
in.domain_id = pdata->domain_id;
ret = devm_scmi_process_msg(dev, priv->channel, &scmi_msg);
ret = devm_scmi_process_msg(dev, &scmi_msg);
if (ret) {
dev_err(dev, "Failed to query voltage domain %u: %d\n",
pdata->domain_id, ret);
@ -184,7 +171,6 @@ U_BOOT_DRIVER(scmi_regulator) = {
.probe = scmi_regulator_probe,
.of_to_plat = scmi_regulator_of_to_plat,
.plat_auto = sizeof(struct scmi_regulator_platdata),
.priv_auto = sizeof(struct scmi_regulator_priv *),
};
static int scmi_regulator_bind(struct udevice *dev)

View File

@ -13,17 +13,8 @@
#include <scmi_protocols.h>
#include <asm/types.h>
/**
* struct scmi_reset_priv - Private data for SCMI reset controller
* @channel: Reference to the SCMI channel to use
*/
struct scmi_reset_priv {
struct scmi_channel *channel;
};
static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert)
{
struct scmi_reset_priv *priv = dev_get_priv(rst->dev);
struct scmi_rd_reset_in in = {
.domain_id = rst->id,
.flags = assert_not_deassert ? SCMI_RD_RESET_FLAG_ASSERT : 0,
@ -35,7 +26,7 @@ static int scmi_reset_set_level(struct reset_ctl *rst, bool assert_not_deassert)
in, out);
int ret;
ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
ret = devm_scmi_process_msg(rst->dev, &msg);
if (ret)
return ret;
@ -54,7 +45,6 @@ static int scmi_reset_deassert(struct reset_ctl *rst)
static int scmi_reset_request(struct reset_ctl *rst)
{
struct scmi_reset_priv *priv = dev_get_priv(rst->dev);
struct scmi_rd_attr_in in = {
.domain_id = rst->id,
};
@ -68,7 +58,7 @@ static int scmi_reset_request(struct reset_ctl *rst)
* We don't really care about the attribute, just check
* the reset domain exists.
*/
ret = devm_scmi_process_msg(rst->dev, priv->channel, &msg);
ret = devm_scmi_process_msg(rst->dev, &msg);
if (ret)
return ret;
@ -83,9 +73,7 @@ static const struct reset_ops scmi_reset_domain_ops = {
static int scmi_reset_probe(struct udevice *dev)
{
struct scmi_reset_priv *priv = dev_get_priv(dev);
return devm_scmi_of_get_channel(dev, &priv->channel);
return devm_scmi_of_get_channel(dev);
}
U_BOOT_DRIVER(scmi_reset_domain) = {
@ -93,5 +81,4 @@ U_BOOT_DRIVER(scmi_reset_domain) = {
.id = UCLASS_RESET,
.ops = &scmi_reset_domain_ops,
.probe = scmi_reset_probe,
.priv_auto = sizeof(struct scmi_reset_priv *),
};

View File

@ -123,6 +123,7 @@ enum uclass_id {
UCLASS_RNG, /* Random Number Generator */
UCLASS_RTC, /* Real time clock device */
UCLASS_SCMI_AGENT, /* Interface with an SCMI server */
UCLASS_SCMI_BASE, /* Interface for SCMI Base protocol */
UCLASS_SCSI, /* SCSI device */
UCLASS_SERIAL, /* Serial UART */
UCLASS_SIMPLE_BUS, /* Bus with child devices */

View File

@ -5,10 +5,89 @@
#ifndef _SCMI_AGENT_UCLASS_H
#define _SCMI_AGENT_UCLASS_H
struct udevice;
#include <scmi_protocols.h>
#include <dm/device.h>
struct scmi_msg;
struct scmi_channel;
/**
* struct scmi_agent_priv - private data maintained by agent instance
* @version: Version
* @num_agents: Number of agents
* @num_protocols: Number of protocols
* @impl_version: Implementation version
* @protocols: Array of protocol IDs
* @vendor: Vendor name
* @sub_vendor: Sub-vendor name
* @agent_name: Agent name
* @agent_id: Identifier of agent
* @base_dev: SCMI base protocol device
* @clock_dev: SCMI clock protocol device
* @resetdom_dev: SCMI reset domain protocol device
* @voltagedom_dev: SCMI voltage domain protocol device
*/
struct scmi_agent_priv {
u32 version;
u32 num_agents;
u32 num_protocols;
u32 impl_version;
u8 *protocols;
u8 *vendor;
u8 *sub_vendor;
u8 *agent_name;
u32 agent_id;
struct udevice *base_dev;
struct udevice *clock_dev;
struct udevice *resetdom_dev;
struct udevice *voltagedom_dev;
};
static inline u32 scmi_version(struct udevice *dev)
{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->version;
}
static inline u32 scmi_num_agents(struct udevice *dev)
{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_agents;
}
static inline u32 scmi_num_protocols(struct udevice *dev)
{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->num_protocols;
}
static inline u32 scmi_impl_version(struct udevice *dev)
{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->impl_version;
}
static inline u8 *scmi_protocols(struct udevice *dev)
{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->protocols;
}
static inline u8 *scmi_vendor(struct udevice *dev)
{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->vendor;
}
static inline u8 *scmi_sub_vendor(struct udevice *dev)
{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->sub_vendor;
}
static inline u8 *scmi_agent_name(struct udevice *dev)
{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_name;
}
static inline u32 scmi_agent_id(struct udevice *dev)
{
return ((struct scmi_agent_priv *)dev_get_uclass_plat(dev))->agent_id;
}
/**
* struct scmi_transport_ops - The functions that a SCMI transport layer must implement.
*/
@ -16,16 +95,18 @@ struct scmi_agent_ops {
/*
* of_get_channel - Get SCMI channel from SCMI agent device tree node
*
* @dev: SCMI protocol device using the transport
* @dev: SCMI agent device using the transport
* @protocol: SCMI protocol device using the transport
* @channel: Output reference to SCMI channel upon success
* Return 0 upon success and a negative errno on failure
*/
int (*of_get_channel)(struct udevice *dev, struct scmi_channel **channel);
int (*of_get_channel)(struct udevice *dev, struct udevice *protocol,
struct scmi_channel **channel);
/*
* process_msg - Request transport to get the SCMI message processed
*
* @dev: SCMI protocol device using the transport
* @dev: SCMI agent device using the transport
* @msg: SCMI message to be transmitted
*/
int (*process_msg)(struct udevice *dev, struct scmi_channel *channel,

View File

@ -10,11 +10,20 @@
#ifndef SCMI_AGENT_H
#define SCMI_AGENT_H
#include <scmi_protocols.h>
#include <asm/types.h>
struct udevice;
struct scmi_channel;
/**
* struct scmi_agent_proto_priv - Private data in device for SCMI agent
* @channel: Reference to the SCMI channel to use
*/
struct scmi_agent_proto_priv {
struct scmi_channel *channel;
};
/*
* struct scmi_msg - Context of a SCMI message sent and the response received
*
@ -49,10 +58,9 @@ struct scmi_msg {
* devm_scmi_of_get_channel() - Get SCMI channel handle from SCMI agent DT node
*
* @dev: Device requesting a channel
* @channel: Output reference to the SCMI channel upon success
* @return 0 on success and a negative errno on failure
*/
int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel);
int devm_scmi_of_get_channel(struct udevice *dev);
/**
* devm_scmi_process_msg() - Send and process an SCMI message
@ -62,12 +70,23 @@ int devm_scmi_of_get_channel(struct udevice *dev, struct scmi_channel **channel)
* On return, scmi_msg::out_msg_sz stores the response payload size.
*
* @dev: SCMI device
* @channel: Communication channel for the device
* @msg: Message structure reference
* Return: 0 on success and a negative errno on failure
*/
int devm_scmi_process_msg(struct udevice *dev, struct scmi_channel *channel,
struct scmi_msg *msg);
int devm_scmi_process_msg(struct udevice *dev, struct scmi_msg *msg);
/**
* scmi_get_protocol() - get protocol instance
*
* @dev: SCMI agent device
* @id: SCMI protocol ID
*
* Obtain the device instance for given protocol ID, @id.
*
* Return: Pointer to the device if found, null otherwise
*/
struct udevice *scmi_get_protocol(struct udevice *dev,
enum scmi_std_protocol id);
/**
* scmi_to_linux_errno() - Convert an SCMI error code into a Linux errno code

View File

@ -49,6 +49,501 @@ enum scmi_discovery_id {
SCMI_PROTOCOL_MESSAGE_ATTRIBUTES = 0x2,
};
/*
* SCMI Base Protocol
*/
#define SCMI_BASE_PROTOCOL_VERSION 0x20000
enum scmi_base_message_id {
SCMI_BASE_DISCOVER_VENDOR = 0x3,
SCMI_BASE_DISCOVER_SUB_VENDOR = 0x4,
SCMI_BASE_DISCOVER_IMPL_VERSION = 0x5,
SCMI_BASE_DISCOVER_LIST_PROTOCOLS = 0x6,
SCMI_BASE_DISCOVER_AGENT = 0x7,
SCMI_BASE_NOTIFY_ERRORS = 0x8,
SCMI_BASE_SET_DEVICE_PERMISSIONS = 0x9,
SCMI_BASE_SET_PROTOCOL_PERMISSIONS = 0xa,
SCMI_BASE_RESET_AGENT_CONFIGURATION = 0xb,
};
#define SCMI_BASE_NAME_LENGTH_MAX 16
/**
* struct scmi_protocol_version_out - Response for SCMI_PROTOCOL_VERSION
* command
* @status: SCMI command status
* @version: Protocol version
*/
struct scmi_protocol_version_out {
s32 status;
u32 version;
};
/**
* struct scmi_protocol_attrs_out - Response for SCMI_PROTOCOL_ATTRIBUTES
* command
* @status: SCMI command status
* @attributes: Protocol attributes or implementation details
*/
struct scmi_protocol_attrs_out {
s32 status;
u32 attributes;
};
#define SCMI_PROTOCOL_ATTRS_NUM_AGENTS(attributes) \
(((attributes) & GENMASK(15, 8)) >> 8)
#define SCMI_PROTOCOL_ATTRS_NUM_PROTOCOLS(attributes) \
((attributes) & GENMASK(7, 0))
/**
* struct scmi_protocol_msg_attrs_out - Response for
* SCMI_PROTOCOL_MESSAGE_ATTRIBUTES command
* @status: SCMI command status
* @attributes: Message-specific attributes
*/
struct scmi_protocol_msg_attrs_out {
s32 status;
u32 attributes;
};
/**
* struct scmi_base_discover_vendor_out - Response for
* SCMI_BASE_DISCOVER_VENDOR or
* SCMI_BASE_DISCOVER_SUB_VENDOR command
* @status: SCMI command status
* @vendor_identifier: Name of vendor or sub-vendor in string
*/
struct scmi_base_discover_vendor_out {
s32 status;
u8 vendor_identifier[SCMI_BASE_NAME_LENGTH_MAX];
};
/**
* struct scmi_base_discover_impl_version_out - Response for
* SCMI_BASE_DISCOVER_IMPL_VERSION command
* @status: SCMI command status
* @impl_version: Vendor-specific implementation version
*/
struct scmi_base_discover_impl_version_out {
s32 status;
u32 impl_version;
};
/**
* struct scmi_base_discover_list_protocols_out - Response for
* SCMI_BASE_DISCOVER_LIST_PROTOCOLS command
* @status: SCMI command status
* @num_protocols: Number of SCMI protocols in @protocol
* @protocols: Array of packed SCMI protocol ID's
*/
struct scmi_base_discover_list_protocols_out {
s32 status;
u32 num_protocols;
u32 protocols[3];
};
/**
* struct scmi_base_discover_agent_out - Response for
* SCMI_BASE_DISCOVER_AGENT command
* @status: SCMI command status
* @agent_id: SCMI agent ID
* @name: Name of agent in string
*/
struct scmi_base_discover_agent_out {
s32 status;
u32 agent_id;
u8 name[SCMI_BASE_NAME_LENGTH_MAX];
};
#define SCMI_BASE_NOTIFY_ERRORS_ENABLE BIT(0)
/**
* struct scmi_base_set_device_permissions_in - Parameters for
* SCMI_BASE_SET_DEVICE_PERMISSIONS command
* @agent_id: SCMI agent ID
* @device_id: device ID
* @flags: A set of flags
*/
struct scmi_base_set_device_permissions_in {
u32 agent_id;
u32 device_id;
u32 flags;
};
#define SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS BIT(0)
/**
* struct scmi_base_set_protocol_permissions_in - Parameters for
* SCMI_BASE_SET_PROTOCOL_PERMISSIONS command
* @agent_id: SCMI agent ID
* @device_id: device ID
* @command_id: command ID
* @flags: A set of flags
*/
struct scmi_base_set_protocol_permissions_in {
u32 agent_id;
u32 device_id;
u32 command_id;
u32 flags;
};
#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_COMMAND GENMASK(7, 0)
#define SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS BIT(0)
/**
* struct scmi_base_reset_agent_configuration_in - Parameters for
* SCMI_BASE_RESET_AGENT_CONFIGURATION command
* @agent_id: SCMI agent ID
* @flags: A set of flags
*/
struct scmi_base_reset_agent_configuration_in {
u32 agent_id;
u32 flags;
};
#define SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS BIT(0)
/**
* struct scmi_base_ops - SCMI base protocol interfaces
*/
struct scmi_base_ops {
/**
* protocol_version - get Base protocol version
* @dev: SCMI protocol device
* @version: Pointer to SCMI protocol version
*
* Obtain the protocol version number in @version for Base protocol.
*
* Return: 0 on success, error code on failure
*/
int (*protocol_version)(struct udevice *dev, u32 *version);
/**
* protocol_attrs - get protocol attributes
* @dev: SCMI protocol device
* @num_agents: Number of SCMI agents
* @num_protocols: Number of SCMI protocols
*
* Obtain the protocol attributes, the number of agents and the number
* of protocols, in @num_agents and @num_protocols respectively, that
* the device provides.
*
* Return: 0 on success, error code on failure
*/
int (*protocol_attrs)(struct udevice *dev, u32 *num_agents,
u32 *num_protocols);
/**
* 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.
* This command succeeds if the message is implemented and available.
*
* Return: 0 on success, error code on failure
*/
int (*protocol_message_attrs)(struct udevice *dev, u32 message_id,
u32 *attributes);
/**
* base_discover_vendor - get vendor name
* @dev: SCMI protocol device
* @vendor: Pointer to vendor name
*
* Obtain the vendor's name in @vendor.
* It is a caller's responsibility to free @vendor.
*
* Return: 0 on success, error code on failure
*/
int (*base_discover_vendor)(struct udevice *dev, u8 **vendor);
/**
* base_discover_sub_vendor - get sub-vendor name
* @dev: SCMI protocol device
* @sub_vendor: Pointer to sub-vendor name
*
* Obtain the sub-vendor's name in @sub_vendor.
* It is a caller's responsibility to free @sub_vendor.
*
* Return: 0 on success, error code on failure
*/
int (*base_discover_sub_vendor)(struct udevice *dev, u8 **sub_vendor);
/**
* base_discover_impl_version - get implementation version
* @dev: SCMI protocol device
* @impl_version: Pointer to implementation version
*
* Obtain the implementation version number in @impl_version.
*
* Return: 0 on success, error code on failure
*/
int (*base_discover_impl_version)(struct udevice *dev,
u32 *impl_version);
/**
* base_discover_list_protocols - get list of protocols
* @dev: SCMI protocol device
* @protocols: Pointer to array of SCMI protocols
*
* Obtain the list of protocols provided in @protocols.
* The number of elements in @protocols always match to the number of
* protocols returned by smci_protocol_attrs() when this function
* succeeds.
* It is a caller's responsibility to free @protocols.
*
* Return: the number of protocols in @protocols on success,
* error code on failure
*/
int (*base_discover_list_protocols)(struct udevice *dev,
u8 **protocols);
/**
* base_discover_agent - identify agent
* @dev: SCMI protocol device
* @agent_id: SCMI agent ID
* @ret_agent_id: Pointer to SCMI agent ID
* @name: Pointer to SCMI agent name
*
* Obtain the agent's name in @name. If @agent_id is equal to
* 0xffffffff, * this function returns the caller's agent id in
* @ret_agent_id.
* It is a caller's responsibility to free @name.
*
* Return: 0 on success, error code on failure
*/
int (*base_discover_agent)(struct udevice *dev, u32 agent_id,
u32 *ret_agent_id, u8 **name);
/**
* base_notify_errors - configure error notification
* @dev: SCMI protocol device
* @enable: Operation
*
* Enable or disable error notification from SCMI firmware.
*
* Return: 0 on success, error code on failure
*/
int (*base_notify_errors)(struct udevice *dev, u32 enable);
/**
* base_set_device_permissions - configure access permission to device
* @dev: SCMI protocol device
* @agent_id: SCMI agent ID
* @device_id: ID of device to access
* @flags: A set of flags
*
* Ask for allowing or denying access permission to the device,
* @device_id. The meaning of @flags is defined in SCMI specification.
*
* Return: 0 on success, error code on failure
*/
int (*base_set_device_permissions)(struct udevice *dev, u32 agent_id,
u32 device_id, u32 flags);
/**
* base_set_protocol_permissions - configure access permission to
* protocol on device
* @dev: SCMI protocol device
* @agent_id: SCMI agent ID
* @device_id: ID of device to access
* @command_id: command ID
* @flags: A set of flags
*
* Ask for allowing or denying access permission to the protocol,
* @command_id, on the device, @device_id.
* The meaning of @flags is defined in SCMI specification.
*
* Return: 0 on success, error code on failure
*/
int (*base_set_protocol_permissions)(struct udevice *dev, u32 agent_id,
u32 device_id, u32 command_id,
u32 flags);
/**
* base_reset_agent_configuration - reset resource settings
* @dev: SCMI protocol device
* @agent_id: SCMI agent ID
* @flags: A set of flags
*
* Reset all the resource settings against @agent_id.
* The meaning of @flags is defined in SCMI specification.
*
* Return: 0 on success, error code on failure
*/
int (*base_reset_agent_configuration)(struct udevice *dev, u32 agent_id,
u32 flags);
};
/**
* scmi_generic_protocol_version - get protocol version
* @dev: SCMI protocol device
* @id: SCMI protocol ID
* @version: Pointer to SCMI protocol version
*
* Obtain the protocol version number in @version.
*
* Return: 0 on success, error code on failure
*/
int scmi_generic_protocol_version(struct udevice *dev,
enum scmi_std_protocol id, u32 *version);
/**
* scmi_base_protocol_version - get Base protocol version
* @dev: SCMI protocol device
* @version: Pointer to SCMI protocol version
*
* Obtain the protocol version number in @version for Base protocol.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_protocol_version(struct udevice *dev, u32 *version);
/**
* scmi_protocol_attrs - get protocol attributes
* @dev: SCMI protocol device
* @num_agents: Number of SCMI agents
* @num_protocols: Number of SCMI protocols
*
* Obtain the protocol attributes, the number of agents and the number
* of protocols, in @num_agents and @num_protocols respectively, that
* the device provides.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_protocol_attrs(struct udevice *dev, u32 *num_agents,
u32 *num_protocols);
/**
* scmi_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.
* This command succeeds if the message is implemented and available.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_protocol_message_attrs(struct udevice *dev, u32 message_id,
u32 *attributes);
/**
* scmi_base_discover_vendor - get vendor name
* @dev: SCMI protocol device
* @vendor: Pointer to vendor name
*
* Obtain the vendor's name in @vendor.
* It is a caller's responsibility to free @vendor.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_discover_vendor(struct udevice *dev, u8 **vendor);
/**
* scmi_base_discover_sub_vendor - get sub-vendor name
* @dev: SCMI protocol device
* @sub_vendor: Pointer to sub-vendor name
*
* Obtain the sub-vendor's name in @sub_vendor.
* It is a caller's responsibility to free @sub_vendor.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_discover_sub_vendor(struct udevice *dev, u8 **sub_vendor);
/**
* scmi_base_discover_impl_version - get implementation version
* @dev: SCMI protocol device
* @impl_version: Pointer to implementation version
*
* Obtain the implementation version number in @impl_version.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_discover_impl_version(struct udevice *dev, u32 *impl_version);
/**
* scmi_base_discover_list_protocols - get list of protocols
* @dev: SCMI protocol device
* @protocols: Pointer to array of SCMI protocols
*
* Obtain the list of protocols provided in @protocols.
* The number of elements in @protocols always match to the number of
* protocols returned by smci_protocol_attrs() when this function succeeds.
* It is a caller's responsibility to free @protocols.
*
* Return: the number of protocols in @protocols on success, error code on
* failure
*/
int scmi_base_discover_list_protocols(struct udevice *dev, u8 **protocols);
/**
* scmi_base_discover_agent - identify agent
* @dev: SCMI protocol device
* @agent_id: SCMI agent ID
* @ret_agent_id: Pointer to SCMI agent ID
* @name: Pointer to SCMI agent name
*
* Obtain the agent's name in @name. If @agent_id is equal to 0xffffffff,
* this function returns the caller's agent id in @ret_agent_id.
* It is a caller's responsibility to free @name.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_discover_agent(struct udevice *dev, u32 agent_id,
u32 *ret_agent_id, u8 **name);
/**
* scmi_base_notify_errors - configure error notification
* @dev: SCMI protocol device
* @enable: Operation
*
* Enable or disable error notification from SCMI firmware.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_notify_errors(struct udevice *dev, u32 enable);
/**
* scmi_base_set_device_permissions - configure access permission to device
* @dev: SCMI protocol device
* @agent_id: SCMI agent ID
* @device_id: ID of device to access
* @flags: A set of flags
*
* Ask for allowing or denying access permission to the device, @device_id.
* The meaning of @flags is defined in SCMI specification.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_set_device_permissions(struct udevice *dev, u32 agent_id,
u32 device_id, u32 flags);
/**
* scmi_base_set_protocol_permissions - configure access permission to
* protocol on device
* @dev: SCMI protocol device
* @agent_id: SCMI agent ID
* @device_id: ID of device to access
* @command_id: SCMI command ID
* @flags: A set of flags
*
* Ask for allowing or denying access permission to the protocol, @command_id,
* on the device, @device_id.
* The meaning of @flags is defined in SCMI specification.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_set_protocol_permissions(struct udevice *dev,
u32 agent_id, u32 device_id,
u32 command_id, u32 flags);
/**
* scmi_base_reset_agent_configuration - reset resource settings
* @dev: SCMI protocol device
* @agent_id: SCMI agent ID
* @flags: A set of flags
*
* Reset all the resource settings against @agent_id.
* The meaning of @flags is defined in SCMI specification.
*
* Return: 0 on success, error code on failure
*/
int scmi_base_reset_agent_configuration(struct udevice *dev, u32 agent_id,
u32 flags);
/*
* SCMI Clock Protocol
*/

View File

@ -16,6 +16,9 @@
#include <clk.h>
#include <dm.h>
#include <reset.h>
#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <scmi_protocols.h>
#include <asm/scmi_test.h>
#include <dm/device-internal.h>
#include <dm/test.h>
@ -23,22 +26,11 @@
#include <power/regulator.h>
#include <test/ut.h>
static int ut_assert_scmi_state_preprobe(struct unit_test_state *uts)
{
struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx();
ut_assertnonnull(scmi_ctx);
ut_assertnull(scmi_ctx->agent);
return 0;
}
static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts,
struct sandbox_scmi_agent *agent,
struct udevice *dev)
{
struct sandbox_scmi_devices *scmi_devices;
struct sandbox_scmi_service *scmi_ctx;
struct sandbox_scmi_agent *agent;
/* Device references to check context against test sequence */
scmi_devices = sandbox_scmi_devices_ctx(dev);
@ -48,10 +40,6 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts,
ut_asserteq(2, scmi_devices->regul_count);
/* State of the simulated SCMI server exposed */
scmi_ctx = sandbox_scmi_service_ctx();
ut_assertnonnull(scmi_ctx);
agent = scmi_ctx->agent;
ut_assertnonnull(agent);
ut_asserteq(3, agent->clk_count);
ut_assertnonnull(agent->clk);
ut_asserteq(1, agent->reset_count);
@ -63,27 +51,32 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts,
}
static int load_sandbox_scmi_test_devices(struct unit_test_state *uts,
struct sandbox_scmi_agent **ctx,
struct udevice **dev)
{
int ret;
struct udevice *agent_dev;
ret = ut_assert_scmi_state_preprobe(uts);
if (ret)
return ret;
ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi",
&agent_dev));
ut_assertnonnull(agent_dev);
*ctx = sandbox_scmi_agent_ctx(agent_dev);
ut_assertnonnull(*ctx);
/* probe */
ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_scmi",
dev));
ut_assertnonnull(*dev);
return ut_assert_scmi_state_postprobe(uts, *dev);
return ut_assert_scmi_state_postprobe(uts, *ctx, *dev);
}
static int release_sandbox_scmi_test_devices(struct unit_test_state *uts,
struct udevice *dev)
{
/* un-probe */
ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
/* Not sure test devices are fully removed, agent may not be visible */
return 0;
}
@ -93,10 +86,11 @@ static int release_sandbox_scmi_test_devices(struct unit_test_state *uts,
*/
static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts)
{
struct sandbox_scmi_agent *ctx;
struct udevice *dev = NULL;
int ret;
ret = load_sandbox_scmi_test_devices(uts, &dev);
ret = load_sandbox_scmi_test_devices(uts, &ctx, &dev);
if (!ret)
ret = release_sandbox_scmi_test_devices(uts, dev);
@ -104,25 +98,136 @@ static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts)
}
DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT);
static int dm_test_scmi_base(struct unit_test_state *uts)
{
struct udevice *agent_dev, *base;
struct scmi_agent_priv *priv;
u32 version, num_agents, num_protocols, impl_version;
u32 attributes, agent_id;
u8 *vendor, *agent_name, *protocols;
int ret;
/* preparation */
ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi",
&agent_dev));
ut_assertnonnull(agent_dev);
ut_assertnonnull(priv = dev_get_uclass_plat(agent_dev));
ut_assertnonnull(base = scmi_get_protocol(agent_dev,
SCMI_PROTOCOL_ID_BASE));
/* version */
ret = scmi_base_protocol_version(base, &version);
ut_assertok(ret);
ut_asserteq(priv->version, version);
/* protocol attributes */
ret = scmi_base_protocol_attrs(base, &num_agents, &num_protocols);
ut_assertok(ret);
ut_asserteq(priv->num_agents, num_agents);
ut_asserteq(priv->num_protocols, num_protocols);
/* discover vendor */
ret = scmi_base_discover_vendor(base, &vendor);
ut_assertok(ret);
ut_asserteq_str(priv->vendor, vendor);
free(vendor);
/* message attributes */
ret = scmi_base_protocol_message_attrs(base,
SCMI_BASE_DISCOVER_SUB_VENDOR,
&attributes);
ut_assertok(ret);
ut_assertok(attributes);
/* discover sub vendor */
ret = scmi_base_discover_sub_vendor(base, &vendor);
ut_assertok(ret);
ut_asserteq_str(priv->sub_vendor, vendor);
free(vendor);
/* impl version */
ret = scmi_base_discover_impl_version(base, &impl_version);
ut_assertok(ret);
ut_asserteq(priv->impl_version, impl_version);
/* discover agent (my self) */
ret = scmi_base_discover_agent(base, 0xffffffff, &agent_id,
&agent_name);
ut_assertok(ret);
ut_asserteq(priv->agent_id, agent_id);
ut_asserteq_str(priv->agent_name, agent_name);
free(agent_name);
/* discover protocols */
ret = scmi_base_discover_list_protocols(base, &protocols);
ut_asserteq(num_protocols, ret);
ut_asserteq_mem(priv->protocols, protocols, sizeof(u8) * num_protocols);
free(protocols);
/*
* NOTE: Sandbox SCMI driver handles device-0 only. It supports setting
* access and protocol permissions, but doesn't allow unsetting them nor
* resetting the configurations.
*/
/* set device permissions */
ret = scmi_base_set_device_permissions(base, agent_id, 0,
SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS);
ut_assertok(ret); /* SCMI_SUCCESS */
ret = scmi_base_set_device_permissions(base, agent_id, 1,
SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS);
ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */
ret = scmi_base_set_device_permissions(base, agent_id, 0, 0);
ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
/* set protocol permissions */
ret = scmi_base_set_protocol_permissions(base, agent_id, 0,
SCMI_PROTOCOL_ID_CLOCK,
SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS);
ut_assertok(ret); /* SCMI_SUCCESS */
ret = scmi_base_set_protocol_permissions(base, agent_id, 1,
SCMI_PROTOCOL_ID_CLOCK,
SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS);
ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */
ret = scmi_base_set_protocol_permissions(base, agent_id, 0,
SCMI_PROTOCOL_ID_CLOCK, 0);
ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
/* reset agent configuration */
ret = scmi_base_reset_agent_configuration(base, agent_id, 0);
ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
ret = scmi_base_reset_agent_configuration(base, agent_id,
SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS);
ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
ret = scmi_base_reset_agent_configuration(base, agent_id, 0);
ut_asserteq(-EACCES, ret); /* SCMI_DENIED */
return 0;
}
DM_TEST(dm_test_scmi_base, UT_TESTF_SCAN_FDT);
static int dm_test_scmi_clocks(struct unit_test_state *uts)
{
struct sandbox_scmi_devices *scmi_devices;
struct sandbox_scmi_service *scmi_ctx;
struct sandbox_scmi_agent *agent;
struct udevice *dev;
struct sandbox_scmi_devices *scmi_devices;
struct udevice *agent_dev, *clock_dev, *dev;
int ret_dev;
int ret;
ret = load_sandbox_scmi_test_devices(uts, &dev);
ret = load_sandbox_scmi_test_devices(uts, &agent, &dev);
if (ret)
return ret;
scmi_devices = sandbox_scmi_devices_ctx(dev);
ut_assertnonnull(scmi_devices);
scmi_ctx = sandbox_scmi_service_ctx();
ut_assertnonnull(scmi_ctx);
agent = scmi_ctx->agent;
ut_assertnonnull(agent);
/* Sandbox SCMI clock protocol has its own channel */
ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi",
&agent_dev));
ut_assertnonnull(agent_dev);
clock_dev = scmi_get_protocol(agent_dev, SCMI_PROTOCOL_ID_CLOCK);
ut_assertnonnull(clock_dev);
ut_asserteq(0x14, sandbox_scmi_channel_id(clock_dev));
/* Test SCMI clocks rate manipulation */
ut_asserteq(333, agent->clk[0].rate);
@ -169,22 +274,25 @@ DM_TEST(dm_test_scmi_clocks, UT_TESTF_SCAN_FDT);
static int dm_test_scmi_resets(struct unit_test_state *uts)
{
struct sandbox_scmi_devices *scmi_devices;
struct sandbox_scmi_service *scmi_ctx;
struct sandbox_scmi_agent *agent;
struct udevice *dev = NULL;
struct sandbox_scmi_devices *scmi_devices;
struct udevice *agent_dev, *reset_dev, *dev = NULL;
int ret;
ret = load_sandbox_scmi_test_devices(uts, &dev);
ret = load_sandbox_scmi_test_devices(uts, &agent, &dev);
if (ret)
return ret;
scmi_devices = sandbox_scmi_devices_ctx(dev);
ut_assertnonnull(scmi_devices);
scmi_ctx = sandbox_scmi_service_ctx();
ut_assertnonnull(scmi_ctx);
agent = scmi_ctx->agent;
ut_assertnonnull(agent);
/* Sandbox SCMI reset protocol doesn't have its own channel */
ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi",
&agent_dev));
ut_assertnonnull(agent_dev);
reset_dev = scmi_get_protocol(agent_dev, SCMI_PROTOCOL_ID_RESET_DOMAIN);
ut_assertnonnull(reset_dev);
ut_asserteq(0x0, sandbox_scmi_channel_id(reset_dev));
/* Test SCMI resect controller manipulation */
ut_assert(!agent->reset[0].asserted);
@ -201,21 +309,16 @@ DM_TEST(dm_test_scmi_resets, UT_TESTF_SCAN_FDT);
static int dm_test_scmi_voltage_domains(struct unit_test_state *uts)
{
struct sandbox_scmi_devices *scmi_devices;
struct sandbox_scmi_service *scmi_ctx;
struct sandbox_scmi_agent *agent;
struct sandbox_scmi_devices *scmi_devices;
struct dm_regulator_uclass_plat *uc_pdata;
struct udevice *dev;
struct udevice *regul0_dev;
ut_assertok(load_sandbox_scmi_test_devices(uts, &dev));
ut_assertok(load_sandbox_scmi_test_devices(uts, &agent, &dev));
scmi_devices = sandbox_scmi_devices_ctx(dev);
ut_assertnonnull(scmi_devices);
scmi_ctx = sandbox_scmi_service_ctx();
ut_assertnonnull(scmi_ctx);
agent = scmi_ctx->agent;
ut_assertnonnull(agent);
/* Set/Get an SCMI voltage domain level */
regul0_dev = scmi_devices->regul[0];