mirror of
https://github.com/smaeul/u-boot.git
synced 2025-11-01 12:38:22 +00:00
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:
commit
25edd247a8
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 *),
|
||||
};
|
||||
|
||||
@ -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
|
||||
|
||||
664
drivers/firmware/scmi/base.c
Normal file
664
drivers/firmware/scmi/base.c
Normal 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",
|
||||
};
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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),
|
||||
};
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 *),
|
||||
};
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
195
test/dm/scmi.c
195
test/dm/scmi.c
@ -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];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user