Merge branch '2021-11-23-scmi-and-tee-updates' into next

- A set of SCMI and TEE related updates
This commit is contained in:
Tom Rini 2021-11-23 16:24:24 -05:00
commit 1943f2a2a7
14 changed files with 399 additions and 44 deletions

View File

@ -77,6 +77,7 @@ CONFIG_FASTBOOT_MMC_USER_NAME="mmc1"
CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
CONFIG_FASTBOOT_CMD_OEM_PARTCONF=y
CONFIG_FASTBOOT_CMD_OEM_BOOTBUS=y
# CONFIG_SCMI_AGENT_MAILBOX is not set
CONFIG_GPIO_HOG=y
CONFIG_DM_HWSPINLOCK=y
CONFIG_HWSPINLOCK_STM32=y

View File

@ -78,6 +78,7 @@ CONFIG_FASTBOOT_MMC_USER_NAME="mmc1"
CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
CONFIG_FASTBOOT_CMD_OEM_PARTCONF=y
CONFIG_FASTBOOT_CMD_OEM_BOOTBUS=y
# CONFIG_SCMI_AGENT_MAILBOX is not set
CONFIG_GPIO_HOG=y
CONFIG_DM_HWSPINLOCK=y
CONFIG_HWSPINLOCK_STM32=y

View File

@ -14,7 +14,8 @@ Required properties:
The scmi node with the following properties shall be under the /firmware/ node.
- compatible : shall be "arm,scmi" or "arm,scmi-smc" for smc/hvc transports
- compatible : shall be "arm,scmi" or "arm,scmi-smc" for smc/hvc transports,
or "linaro,scmi-optee" for OP-TEE transport.
- mboxes: List of phandle and mailbox channel specifiers. It should contain
exactly one or two mailboxes, one for transmitting messages("tx")
and another optional for receiving the notifications("rx") if
@ -26,6 +27,8 @@ The scmi node with the following properties shall be under the /firmware/ node.
- #size-cells : should be '0' as 'reg' property doesn't have any size
associated with it.
- arm,smc-id : SMC id required when using smc or hvc transports
- linaro,optee-channel-id : Channel specifier required when using OP-TEE
transport.
Optional properties:
@ -33,16 +36,16 @@ Optional properties:
See Documentation/devicetree/bindings/mailbox/mailbox.txt for more details
about the generic mailbox controller and client driver bindings.
The mailbox is the only permitted method of calling the SCMI firmware.
Mailbox doorbell is used as a mechanism to alert the presence of a
messages and/or notification.
Each protocol supported shall have a sub-node with corresponding compatible
as described in the following sections. If the platform supports dedicated
communication channel for a particular protocol, the 3 properties namely:
mboxes, mbox-names and shmem shall be present in the sub-node corresponding
to that protocol.
communication channel for a particular protocol, properties shall be present
in the sub-node corresponding to that protocol. These properties are:
- mboxes, mbox-names and shmem for mailbox transport
- arm,smc-id and shmem for smc/hvc transport
- linaro,optee-channel-id and possibly shmem for OP-TEE transport
Clock/Performance bindings for the clocks/OPPs based on SCMI Message Protocol
------------------------------------------------------------

View File

@ -2,6 +2,9 @@
/*
* Copyright (C) 2019-2020 Linaro Limited
*/
#define LOG_CATEGORY UCLASS_CLK
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>

View File

@ -2,7 +2,7 @@ config SCMI_FIRMWARE
bool "Enable SCMI support"
select FIRMWARE
select OF_TRANSLATE
depends on SANDBOX || DM_MAILBOX || ARM_SMCCC
depends on SANDBOX || DM_MAILBOX || ARM_SMCCC || OPTEE
help
System Control and Management Interface (SCMI) is a communication
protocol that defines standard interfaces for power, performance
@ -14,6 +14,30 @@ config SCMI_FIRMWARE
or a companion host in the CPU system.
Communications between agent (client) and the SCMI server are
based on message exchange. Messages can be exchange over tranport
based on message exchange. Messages can be exchanged over transport
channels as a mailbox device or an Arm SMCCC service with some
piece of identified shared memory.
config SCMI_AGENT_MAILBOX
bool "Enable SCMI agent mailbox"
depends on SCMI_FIRMWARE && DM_MAILBOX
default y
help
Enable the SCMI communication channel based on mailbox
for compatible "arm,scmi".
config SCMI_AGENT_SMCCC
bool "Enable SCMI agent SMCCC"
depends on SCMI_FIRMWARE && ARM_SMCCC
default y
help
Enable the SCMI communication channel based on Arm SMCCC service for
compatible "arm,scmi-smc".
config SCMI_AGENT_OPTEE
bool "Enable SCMI agent OP-TEE"
depends on SCMI_FIRMWARE && OPTEE
default y
help
Enable the SCMI communication channel based on OP-TEE transport
for compatible "linaro,scmi-optee".

View File

@ -1,5 +1,6 @@
obj-y += scmi_agent-uclass.o
obj-y += smt.o
obj-$(CONFIG_ARM_SMCCC) += smccc_agent.o
obj-$(CONFIG_DM_MAILBOX) += mailbox_agent.o
obj-$(CONFIG_SCMI_AGENT_SMCCC) += smccc_agent.o
obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o
obj-$(CONFIG_SCMI_AGENT_OPTEE) += optee_agent.o
obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o sandbox-scmi_devices.o

View File

@ -33,7 +33,7 @@ struct scmi_mbox_channel {
static int scmi_mbox_process_msg(struct udevice *dev, struct scmi_msg *msg)
{
struct scmi_mbox_channel *chan = dev_get_priv(dev);
struct scmi_mbox_channel *chan = dev_get_plat(dev);
int ret;
ret = scmi_write_msg_to_smt(dev, &chan->smt, msg);
@ -62,9 +62,9 @@ out:
return ret;
}
int scmi_mbox_probe(struct udevice *dev)
int scmi_mbox_of_to_plat(struct udevice *dev)
{
struct scmi_mbox_channel *chan = dev_get_priv(dev);
struct scmi_mbox_channel *chan = dev_get_plat(dev);
int ret;
chan->timeout_us = TIMEOUT_US_10MS;
@ -72,17 +72,13 @@ int scmi_mbox_probe(struct udevice *dev)
ret = mbox_get_by_index(dev, 0, &chan->mbox);
if (ret) {
dev_err(dev, "Failed to find mailbox: %d\n", ret);
goto out;
return ret;
}
ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
if (ret)
dev_err(dev, "Failed to get shm resources: %d\n", ret);
out:
if (ret)
devm_kfree(dev, chan);
return ret;
}
@ -99,7 +95,7 @@ U_BOOT_DRIVER(scmi_mbox) = {
.name = "scmi-over-mailbox",
.id = UCLASS_SCMI_AGENT,
.of_match = scmi_mbox_ids,
.priv_auto = sizeof(struct scmi_mbox_channel),
.probe = scmi_mbox_probe,
.plat_auto = sizeof(struct scmi_mbox_channel),
.of_to_plat = scmi_mbox_of_to_plat,
.ops = &scmi_mbox_ops,
};

View File

@ -0,0 +1,312 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2020-2021 Linaro Limited.
*/
#define LOG_CATEGORY UCLASS_SCMI_AGENT
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <scmi_agent.h>
#include <scmi_agent-uclass.h>
#include <string.h>
#include <tee.h>
#include <asm/types.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <linux/arm-smccc.h>
#include <linux/bug.h>
#include <linux/compat.h>
#include "smt.h"
#define SCMI_SHM_SIZE 128
/**
* struct scmi_optee_channel - Description of an SCMI OP-TEE transport
* @channel_id: Channel identifier
* @smt: Shared memory buffer with synchronisation protocol
* @dyn_shm: True if using dynamically allocated shared memory
*/
struct scmi_optee_channel {
unsigned int channel_id;
struct scmi_smt smt;
bool dyn_shm;
};
/**
* struct channel_session - Aggreates SCMI service session context references
* @tee: OP-TEE device to invoke
* @tee_session: OP-TEE session identifier
* @tee_shm: Dynamically allocated OP-TEE shared memory, or NULL
* @channel_hdl: Channel handle provided by OP-TEE SCMI service
*/
struct channel_session {
struct udevice *tee;
u32 tee_session;
struct tee_shm *tee_shm;
u32 channel_hdl;
};
#define TA_SCMI_UUID { 0xa8cfe406, 0xd4f5, 0x4a2e, \
{ 0x9f, 0x8d, 0xa2, 0x5d, 0xc7, 0x54, 0xc0, 0x99 } }
enum optee_smci_pta_cmd {
/*
* PTA_SCMI_CMD_CAPABILITIES - Get channel capabilities
*
* [out] value[0].a: Capability bit mask (enum pta_scmi_caps)
* [out] value[0].b: Extended capabilities or 0
*/
PTA_SCMI_CMD_CAPABILITIES = 0,
/*
* PTA_SCMI_CMD_PROCESS_SMT_CHANNEL - Process SCMI message in SMT buffer
*
* [in] value[0].a: Channel handle
*
* Shared memory used for SCMI message/response exhange is expected
* already identified and bound to channel handle in both SCMI agent
* and SCMI server (OP-TEE) parts.
* The memory uses SMT header to carry SCMI meta-data (protocol ID and
* protocol message ID).
*/
PTA_SCMI_CMD_PROCESS_SMT_CHANNEL = 1,
/*
* PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE - Process SMT/SCMI message
*
* [in] value[0].a: Channel handle
* [in/out] memref[1]: Message/response buffer (SMT and SCMI payload)
*
* Shared memory used for SCMI message/response is a SMT buffer
* referenced by param[1]. It shall be 128 bytes large to fit response
* payload whatever message playload size.
* The memory uses SMT header to carry SCMI meta-data (protocol ID and
* protocol message ID).
*/
PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE = 2,
/*
* PTA_SCMI_CMD_GET_CHANNEL - Get channel handle
*
* SCMI shm information are 0 if agent expects to use OP-TEE regular SHM
*
* [in] value[0].a: Channel identifier
* [out] value[0].a: Returned channel handle
* [in] value[0].b: Requested capabilities mask (enum pta_scmi_caps)
*/
PTA_SCMI_CMD_GET_CHANNEL = 3,
};
/*
* OP-TEE SCMI service capabilities bit flags (32bit)
*
* PTA_SCMI_CAPS_SMT_HEADER
* When set, OP-TEE supports command using SMT header protocol (SCMI shmem) in
* shared memory buffers to carry SCMI protocol synchronisation information.
*/
#define PTA_SCMI_CAPS_NONE 0
#define PTA_SCMI_CAPS_SMT_HEADER BIT(0)
static int open_channel(struct udevice *dev, struct channel_session *sess)
{
const struct tee_optee_ta_uuid uuid = TA_SCMI_UUID;
struct scmi_optee_channel *chan = dev_get_plat(dev);
struct tee_open_session_arg sess_arg = { };
struct tee_invoke_arg cmd_arg = { };
struct tee_param param[1] = { };
int ret;
memset(sess, 0, sizeof(sess));
sess->tee = tee_find_device(NULL, NULL, NULL, NULL);
if (!sess->tee)
return -ENODEV;
sess_arg.clnt_login = TEE_LOGIN_REE_KERNEL;
tee_optee_ta_uuid_to_octets(sess_arg.uuid, &uuid);
ret = tee_open_session(sess->tee, &sess_arg, 0, NULL);
if (ret) {
dev_err(dev, "can't open session: %d\n", ret);
return ret;
}
cmd_arg.func = PTA_SCMI_CMD_GET_CHANNEL;
cmd_arg.session = sess_arg.session;
param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INOUT;
param[0].u.value.a = chan->channel_id;
param[0].u.value.b = PTA_SCMI_CAPS_SMT_HEADER;
ret = tee_invoke_func(sess->tee, &cmd_arg, ARRAY_SIZE(param), param);
if (ret || cmd_arg.ret) {
dev_err(dev, "Invoke failed: %d, 0x%x\n", ret, cmd_arg.ret);
if (!ret)
ret = -EPROTO;
tee_close_session(sess->tee, sess_arg.session);
return ret;
}
sess->tee_session = sess_arg.session;
sess->channel_hdl = param[0].u.value.a;
return 0;
}
static void close_channel(struct channel_session *sess)
{
tee_close_session(sess->tee, sess->tee_session);
}
static int invoke_cmd(struct udevice *dev, struct channel_session *sess,
struct scmi_msg *msg)
{
struct scmi_optee_channel *chan = dev_get_plat(dev);
struct tee_invoke_arg arg = { };
struct tee_param param[2] = { };
int ret;
scmi_write_msg_to_smt(dev, &chan->smt, msg);
arg.session = sess->tee_session;
param[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
param[0].u.value.a = sess->channel_hdl;
if (chan->dyn_shm) {
arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL_MESSAGE;
param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
param[1].u.memref.shm = sess->tee_shm;
param[1].u.memref.size = SCMI_SHM_SIZE;
} else {
arg.func = PTA_SCMI_CMD_PROCESS_SMT_CHANNEL;
}
ret = tee_invoke_func(sess->tee, &arg, ARRAY_SIZE(param), param);
if (ret || arg.ret) {
if (!ret)
ret = -EPROTO;
} else {
ret = scmi_read_resp_from_smt(dev, &chan->smt, msg);
}
scmi_clear_smt_channel(&chan->smt);
return ret;
}
static int prepare_shm(struct udevice *dev, struct channel_session *sess)
{
struct scmi_optee_channel *chan = dev_get_plat(dev);
int ret;
/* Static shm is already prepared by the firmware: nothing to do */
if (!chan->dyn_shm)
return 0;
chan->smt.size = SCMI_SHM_SIZE;
ret = tee_shm_alloc(sess->tee, chan->smt.size, 0, &sess->tee_shm);
if (ret) {
dev_err(dev, "Failed to allocated shmem: %d\n", ret);
return ret;
}
chan->smt.buf = sess->tee_shm->addr;
/* Initialize shm buffer for message exchanges */
scmi_clear_smt_channel(&chan->smt);
return 0;
}
static void release_shm(struct udevice *dev, struct channel_session *sess)
{
struct scmi_optee_channel *chan = dev_get_plat(dev);
if (chan->dyn_shm)
tee_shm_free(sess->tee_shm);
}
static int scmi_optee_process_msg(struct udevice *dev, struct scmi_msg *msg)
{
struct channel_session sess;
int ret;
ret = open_channel(dev, &sess);
if (ret)
return ret;
ret = prepare_shm(dev, &sess);
if (ret)
goto out;
ret = invoke_cmd(dev, &sess, msg);
release_shm(dev, &sess);
out:
close_channel(&sess);
return ret;
}
static int scmi_optee_of_to_plat(struct udevice *dev)
{
struct scmi_optee_channel *chan = dev_get_plat(dev);
int ret;
if (dev_read_u32(dev, "linaro,optee-channel-id", &chan->channel_id)) {
dev_err(dev, "Missing property linaro,optee-channel-id\n");
return -EINVAL;
}
if (dev_read_prop(dev, "shmem", NULL)) {
ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
if (ret) {
dev_err(dev, "Failed to get smt resources: %d\n", ret);
return ret;
}
chan->dyn_shm = false;
} else {
chan->dyn_shm = true;
}
return 0;
}
static int scmi_optee_probe(struct udevice *dev)
{
struct channel_session sess;
int ret;
/* Check OP-TEE service acknowledges the SCMI channel */
ret = open_channel(dev, &sess);
if (!ret)
close_channel(&sess);
return ret;
}
static const struct udevice_id scmi_optee_ids[] = {
{ .compatible = "linaro,scmi-optee" },
{ }
};
static const struct scmi_agent_ops scmi_optee_ops = {
.process_msg = scmi_optee_process_msg,
};
U_BOOT_DRIVER(scmi_optee) = {
.name = "scmi-over-optee",
.id = UCLASS_SCMI_AGENT,
.of_match = scmi_optee_ids,
.plat_auto = sizeof(struct scmi_optee_channel),
.of_to_plat = scmi_optee_of_to_plat,
.probe = scmi_optee_probe,
.flags = DM_FLAG_OS_PREPARE,
.ops = &scmi_optee_ops,
};

View File

@ -32,7 +32,7 @@ struct scmi_smccc_channel {
static int scmi_smccc_process_msg(struct udevice *dev, struct scmi_msg *msg)
{
struct scmi_smccc_channel *chan = dev_get_priv(dev);
struct scmi_smccc_channel *chan = dev_get_plat(dev);
struct arm_smccc_res res;
int ret;
@ -51,9 +51,9 @@ static int scmi_smccc_process_msg(struct udevice *dev, struct scmi_msg *msg)
return ret;
}
static int scmi_smccc_probe(struct udevice *dev)
static int scmi_smccc_of_to_plat(struct udevice *dev)
{
struct scmi_smccc_channel *chan = dev_get_priv(dev);
struct scmi_smccc_channel *chan = dev_get_plat(dev);
u32 func_id;
int ret;
@ -65,12 +65,10 @@ static int scmi_smccc_probe(struct udevice *dev)
chan->func_id = func_id;
ret = scmi_dt_get_smt_buffer(dev, &chan->smt);
if (ret) {
if (ret)
dev_err(dev, "Failed to get smt resources: %d\n", ret);
return ret;
}
return 0;
return ret;
}
static const struct udevice_id scmi_smccc_ids[] = {
@ -86,7 +84,7 @@ U_BOOT_DRIVER(scmi_smccc) = {
.name = "scmi-over-smccc",
.id = UCLASS_SCMI_AGENT,
.of_match = scmi_smccc_ids,
.priv_auto = sizeof(struct scmi_smccc_channel),
.probe = scmi_smccc_probe,
.plat_auto = sizeof(struct scmi_smccc_channel),
.of_to_plat = scmi_smccc_of_to_plat,
.ops = &scmi_smccc_ops,
};

View File

@ -2,6 +2,9 @@
/*
* Copyright (C) 2020-2021 Linaro Limited
*/
#define LOG_CATEGORY UCLASS_REGULATOR
#include <common.h>
#include <dm.h>
#include <errno.h>

View File

@ -2,6 +2,9 @@
/*
* Copyright (C) 2019-2020 Linaro Limited
*/
#define LOG_CATEGORY UCLASS_RESET
#include <common.h>
#include <dm.h>
#include <errno.h>

View File

@ -86,16 +86,6 @@
#define OPTEE_MSG_ATTR_CACHE_MASK GENMASK(2, 0)
#define OPTEE_MSG_ATTR_CACHE_PREDEFINED 0
/*
* Same values as TEE_LOGIN_* from TEE Internal API
*/
#define OPTEE_MSG_LOGIN_PUBLIC 0x00000000
#define OPTEE_MSG_LOGIN_USER 0x00000001
#define OPTEE_MSG_LOGIN_GROUP 0x00000002
#define OPTEE_MSG_LOGIN_APPLICATION 0x00000004
#define OPTEE_MSG_LOGIN_APPLICATION_USER 0x00000005
#define OPTEE_MSG_LOGIN_APPLICATION_GROUP 0x00000006
/*
* Page size used in non-contiguous buffer entries
*/
@ -279,7 +269,7 @@ struct optee_msg_arg {
* parameters to pass the following information:
* param[0].u.value.a-b uuid of Trusted Application
* param[1].u.value.a-b uuid of Client
* param[1].u.value.c Login class of client OPTEE_MSG_LOGIN_*
* param[1].u.value.c Login class of client TEE_LOGIN_*
*
* OPTEE_MSG_CMD_INVOKE_COMMAND invokes a command a previously opened
* session to a Trusted Application. struct optee_msg_arg::func is Trusted

View File

@ -45,9 +45,9 @@ struct scmi_msg {
}
/**
* scmi_send_and_process_msg() - send and process a SCMI message
* devm_scmi_process_msg() - Send and process an SCMI message
*
* Send a message to a SCMI server through a target SCMI agent device.
* Send a message to an SCMI server through a target SCMI agent device.
* Caller sets scmi_msg::out_msg_sz to the output message buffer size.
* On return, scmi_msg::out_msg_sz stores the response payload size.
*

View File

@ -31,6 +31,25 @@
#define TEE_PARAM_ATTR_MASK (TEE_PARAM_ATTR_TYPE_MASK | \
TEE_PARAM_ATTR_META)
/*
* Global Platform login identifiers for tee_open_session_arg::clnt_login
*/
#define TEE_LOGIN_PUBLIC 0x00000000
#define TEE_LOGIN_USER 0x00000001
#define TEE_LOGIN_GROUP 0x00000002
#define TEE_LOGIN_APPLICATION 0x00000004
#define TEE_LOGIN_APPLICATION_USER 0x00000005
#define TEE_LOGIN_APPLICATION_GROUP 0x00000006
/*
* Reserve use of GP implementation specific login method range
* (0x80000000 - 0xBFFFFFFF). This range is rather being used
* for REE kernel clients or TEE implementation.
*/
#define TEE_LOGIN_REE_KERNEL_MIN 0x80000000
#define TEE_LOGIN_REE_KERNEL_MAX 0xBFFFFFFF
/* Private login method for REE kernel/privileged clients */
#define TEE_LOGIN_REE_KERNEL 0x80000000
/*
* Some Global Platform error codes which has a meaning if the
* TEE_GEN_CAP_GP bit is returned by the driver in
@ -45,6 +64,7 @@
#define TEE_ERROR_NOT_SUPPORTED 0xffff000a
#define TEE_ERROR_COMMUNICATION 0xffff000e
#define TEE_ERROR_SECURITY 0xffff000f
#define TEE_ERROR_SHORT_BUFFER 0xffff0010
#define TEE_ERROR_OUT_OF_MEMORY 0xffff000c
#define TEE_ERROR_OVERFLOW 0xffff300f
#define TEE_ERROR_TARGET_DEAD 0xffff3024
@ -135,8 +155,8 @@ struct tee_param {
/**
* struct tee_open_session_arg - extra arguments for tee_open_session()
* @uuid: [in] UUID of the Trusted Application
* @clnt_uuid: [in] Normally zeroes
* @clnt_login: [in] Normally 0
* @clnt_uuid: [in] UUID of client, zeroes for PUBLIC/REE_KERNEL
* @clnt_login: [in] Class of client TEE_LOGIN_*
* @session: [out] Session id
* @ret: [out] return value
* @ret_origin: [out] origin of the return value