From 5ec7c113ac941e1e4ec138c581c0ba00974a4ad5 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Apr 2020 09:22:12 +0200 Subject: [PATCH 01/15] [PATCH V5 1/2] dt-bindings: arm: arm,scmi: add smc/hvc transport SCMI could use SMC/HVC as tranports. Since there is no standardized id, we need to use vendor specific id. So add into devicetree binding doc. Also add arm,scmi-smc compatible string for smc/hvc transport Reviewed-by: Rob Herring Signed-off-by: Peng Fan --- Documentation/devicetree/bindings/arm/arm,scmi.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/arm,scmi.txt b/Documentation/devicetree/bindings/arm/arm,scmi.txt index dc102c4e4a78b8..1f293ea24cd857 100644 --- a/Documentation/devicetree/bindings/arm/arm,scmi.txt +++ b/Documentation/devicetree/bindings/arm/arm,scmi.txt @@ -14,7 +14,7 @@ Required properties: The scmi node with the following properties shall be under the /firmware/ node. -- compatible : shall be "arm,scmi" +- compatible : shall be "arm,scmi" or "arm,scmi-smc" for smc/hvc transports - 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 @@ -25,6 +25,7 @@ The scmi node with the following properties shall be under the /firmware/ node. protocol identifier for a given sub-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 Optional properties: From cf92e75e6c7fdbd7d93088d68da1a40ae3cd0ce8 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Apr 2020 09:23:35 +0200 Subject: [PATCH 02/15] [PATCH V5 2/2] firmware: arm_scmi: add smc/hvc transport Take arm,smc-id as the 1st arg, leave the other args as zero for now. There is no Rx, only Tx because of smc/hvc not support Rx. Signed-off-by: Peng Fan --- drivers/firmware/arm_scmi/Makefile | 2 +- drivers/firmware/arm_scmi/common.h | 1 + drivers/firmware/arm_scmi/driver.c | 1 + drivers/firmware/arm_scmi/smc.c | 152 +++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/smc.c diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 6694d0d908d635..6b1b0d6c6d0e65 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -2,6 +2,6 @@ obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o scmi-bus-y = bus.o scmi-driver-y = driver.o -scmi-transport-y = mailbox.o shmem.o +scmi-transport-y = mailbox.o shmem.o smc.o scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 5ac06469b01cb3..94fc2b2df94021 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -210,6 +210,7 @@ struct scmi_desc { }; extern const struct scmi_desc scmi_mailbox_desc; +extern const struct scmi_desc scmi_smc_desc; void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr); void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index dbec767222e9fc..e76a3fab10741b 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -827,6 +827,7 @@ ATTRIBUTE_GROUPS(versions); /* Each compatible listed below must have descriptor associated with it */ static const struct of_device_id scmi_of_match[] = { { .compatible = "arm,scmi", .data = &scmi_mailbox_desc }, + { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc}, { /* Sentinel */ }, }; diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c new file mode 100644 index 00000000000000..336168e40f4940 --- /dev/null +++ b/drivers/firmware/arm_scmi/smc.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Management Interface (SCMI) Message SMC/HVC + * Transport driver + * + * Copyright 2020 NXP + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/** + * struct scmi_smc - Structure representing a SCMI smc transport + * + * @cinfo: SCMI channel info + * @shmem: Transmit/Receive shared memory area + * @func_id: smc/hvc call function id + */ + +struct scmi_smc { + struct scmi_chan_info *cinfo; + struct scmi_shared_mem __iomem *shmem; + u32 func_id; +}; + +static DEFINE_MUTEX(smc_mutex); + +static bool smc_chan_available(struct device *dev, int idx) +{ + return true; +} + +static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, + bool tx) +{ + struct device *cdev = cinfo->dev; + struct scmi_smc *scmi_info; + resource_size_t size; + struct resource res; + struct device_node *np; + u32 func_id; + int ret; + + if (!tx) + return -ENODEV; + + scmi_info = devm_kzalloc(dev, sizeof(*scmi_info), GFP_KERNEL); + if (!scmi_info) + return -ENOMEM; + + np = of_parse_phandle(cdev->of_node, "shmem", 0); + if (!np) + np = of_parse_phandle(dev->of_node, "shmem", 0); + ret = of_address_to_resource(np, 0, &res); + of_node_put(np); + if (ret) { + dev_err(cdev, "failed to get SCMI Tx shared memory\n"); + return ret; + } + + size = resource_size(&res); + scmi_info->shmem = devm_ioremap(dev, res.start, size); + if (!scmi_info->shmem) { + dev_err(dev, "failed to ioremap SCMI Tx shared memory\n"); + return -EADDRNOTAVAIL; + } + + ret = of_property_read_u32(dev->of_node, "arm,smc-id", &func_id); + if (ret < 0) + return ret; + + scmi_info->func_id = func_id; + scmi_info->cinfo = cinfo; + cinfo->transport_info = scmi_info; + + return 0; +} + +static int smc_chan_free(int id, void *p, void *data) +{ + struct scmi_chan_info *cinfo = p; + struct scmi_smc *scmi_info = cinfo->transport_info; + + cinfo->transport_info = NULL; + scmi_info->cinfo = NULL; + + scmi_free_channel(cinfo, data, id); + + return 0; +} + +static int smc_send_message(struct scmi_chan_info *cinfo, + struct scmi_xfer *xfer) +{ + struct scmi_smc *scmi_info = cinfo->transport_info; + struct arm_smccc_res res; + + mutex_lock(&smc_mutex); + + shmem_tx_prepare(scmi_info->shmem, xfer); + + arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res); + scmi_rx_callback(scmi_info->cinfo, shmem_read_header(scmi_info->shmem)); + + mutex_unlock(&smc_mutex); + + return res.a0; +} + +static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret) +{ +} + +static void smc_fetch_response(struct scmi_chan_info *cinfo, + struct scmi_xfer *xfer) +{ + struct scmi_smc *scmi_info = cinfo->transport_info; + + shmem_fetch_response(scmi_info->shmem, xfer); +} + +static bool +smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) +{ + struct scmi_smc *scmi_info = cinfo->transport_info; + + return shmem_poll_done(scmi_info->shmem, xfer); +} + +static struct scmi_transport_ops scmi_smc_ops = { + .chan_available = smc_chan_available, + .chan_setup = smc_chan_setup, + .chan_free = smc_chan_free, + .send_message = smc_send_message, + .mark_txdone = smc_mark_txdone, + .fetch_response = smc_fetch_response, + .poll_done = smc_poll_done, +}; + +const struct scmi_desc scmi_smc_desc = { + .ops = &scmi_smc_ops, + .max_rx_timeout_ms = 30, + .max_msg = 1, + .max_msg_size = 128, +}; From 77c12351fac7c1d562de10f11c213eece66330b9 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Sat, 28 Mar 2020 13:35:24 +0100 Subject: [PATCH 03/15] fixup! firmware: arm_scmi: add smc/hvc transport (CONFIG_* deps) Embed SCMI mailbox transport upon CONFIG_MAILBOX configuration switch. Embed SCMI smc transport upon CONFIG_HAVE_ARM_SMCCC configuration switch. Signed-off-by: Etienne Carriere --- drivers/firmware/Kconfig | 2 +- drivers/firmware/arm_scmi/Makefile | 4 +++- drivers/firmware/arm_scmi/driver.c | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 8007d4aa76dcd6..57eddfd525a4f7 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -9,7 +9,7 @@ menu "Firmware Drivers" config ARM_SCMI_PROTOCOL bool "ARM System Control and Management Interface (SCMI) Message Protocol" depends on ARM || ARM64 || COMPILE_TEST - depends on MAILBOX + depends on MAILBOX || HAVE_ARM_SMCCC help ARM System Control and Management Interface (SCMI) protocol is a set of operating system-independent software interfaces that are diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 6b1b0d6c6d0e65..11b238f8192302 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -2,6 +2,8 @@ obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o scmi-bus-y = bus.o scmi-driver-y = driver.o -scmi-transport-y = mailbox.o shmem.o smc.o +scmi-transport-y = shmem.o +scmi-transport-$(CONFIG_MAILBOX) += mailbox.o +scmi-transport-$(CONFIG_HAVE_ARM_SMCCC) += smc.o scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index e76a3fab10741b..12fb431dfab4fb 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -826,8 +826,12 @@ ATTRIBUTE_GROUPS(versions); /* Each compatible listed below must have descriptor associated with it */ static const struct of_device_id scmi_of_match[] = { +#ifdef CONFIG_MAILBOX { .compatible = "arm,scmi", .data = &scmi_mailbox_desc }, +#endif +#ifdef CONFIG_HAVE_ARM_SMCCC { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc}, +#endif { /* Sentinel */ }, }; From 2b62d8d23892e1abb5c68915e59eee228f779455 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Apr 2020 09:39:15 +0200 Subject: [PATCH 04/15] fixup! firmware: arm_scmi: add smc/hvc transport (SMC return value) Don't mandate res.a0 to be 0 for a valid invocation. As per SMCCC specification, only value ~0 (sign extended -1) denoted a non supported function ID. Signed-off-by: Etienne Carriere --- drivers/firmware/arm_scmi/smc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index 336168e40f4940..56bc64dd937807 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -111,7 +111,7 @@ static int smc_send_message(struct scmi_chan_info *cinfo, mutex_unlock(&smc_mutex); - return res.a0; + return res.a0 == ~0 ? -EINVAL : 0; } static void smc_mark_txdone(struct scmi_chan_info *cinfo, int ret) From cbce29f1c82a9447ad5a2a6831535a6ad008556e Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Apr 2020 09:57:01 +0200 Subject: [PATCH 05/15] fixup! firmware: arm_scmi: add smc/hvc transport (Optional "method") Do not mandate to rely on arm_smccc_1_1_invoke() which depends on PSCI support to dynamically provide the expected method. Allow FDT to define the conduit method using property "method". If no property "method" is defined in the FDT, invocation relies on arm_smccc_1_1_invoke(). Signed-off-by: Etienne Carriere --- drivers/firmware/arm_scmi/smc.c | 46 +++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index 56bc64dd937807..75a4895178b84f 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -16,6 +16,8 @@ #include "common.h" +typedef void (scmi_arm_smccc_invoke_fn)(unsigned long, struct arm_smccc_res *); + /** * struct scmi_smc - Structure representing a SCMI smc transport * @@ -23,10 +25,10 @@ * @shmem: Transmit/Receive shared memory area * @func_id: smc/hvc call function id */ - struct scmi_smc { struct scmi_chan_info *cinfo; struct scmi_shared_mem __iomem *shmem; + scmi_arm_smccc_invoke_fn *invoke_fn; u32 func_id; }; @@ -37,6 +39,41 @@ static bool smc_chan_available(struct device *dev, int idx) return true; } +/* Simple wrapper functions to be able to use a function pointer */ +static void _smccc_smc(unsigned long func_id, struct arm_smccc_res *res) +{ + arm_smccc_smc(func_id, 0, 0, 0, 0, 0, 0, 0, res); +} + +static void _smccc_hvc(unsigned long func_id, struct arm_smccc_res *res) +{ + arm_smccc_hvc(func_id, 0, 0, 0, 0, 0, 0, 0, res); +} + +static void _smccc_1_1(unsigned long func_id, struct arm_smccc_res *res) +{ + arm_smccc_1_1_invoke(func_id, 0, 0, 0, 0, 0, 0, 0, res); +} + +static scmi_arm_smccc_invoke_fn *get_invoke_function(struct device *dev) +{ + const char *method; + + pr_info("probing for conduit method.\n"); + + if (device_property_read_string(dev, "method", &method)) + return _smccc_1_1; + + if (!strcmp("hvc", method)) + return _smccc_hvc; + + if (!strcmp("smc", method)) + return _smccc_smc; + + dev_err(dev, "Invalid \"method\" property: %s\n", method); + return ERR_PTR(-EINVAL); +} + static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, bool tx) { @@ -76,6 +113,10 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (ret < 0) return ret; + scmi_info->invoke_fn = get_invoke_function(dev); + if (IS_ERR(scmi_info->invoke_fn)) + return PTR_ERR(scmi_info->invoke_fn); + scmi_info->func_id = func_id; scmi_info->cinfo = cinfo; cinfo->transport_info = scmi_info; @@ -106,7 +147,8 @@ static int smc_send_message(struct scmi_chan_info *cinfo, shmem_tx_prepare(scmi_info->shmem, xfer); - arm_smccc_1_1_invoke(scmi_info->func_id, 0, 0, 0, 0, 0, 0, 0, &res); + scmi_info->invoke_fn(scmi_info->func_id, &res); + scmi_rx_callback(scmi_info->cinfo, shmem_read_header(scmi_info->shmem)); mutex_unlock(&smc_mutex); From d12a1d394aaf2a67e6d434076e6a38d55d24760d Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Sun, 12 Apr 2020 12:19:25 +0200 Subject: [PATCH 06/15] fixup! dt-bindings: arm: add Arm SMCCC transport channel (split descr.) Split binding properties description in 2 sections for clarity. Signed-off-by: Etienne Carriere --- .../devicetree/bindings/arm/arm,scmi.txt | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/arm,scmi.txt b/Documentation/devicetree/bindings/arm/arm,scmi.txt index 1f293ea24cd857..69e55bd651e999 100644 --- a/Documentation/devicetree/bindings/arm/arm,scmi.txt +++ b/Documentation/devicetree/bindings/arm/arm,scmi.txt @@ -10,22 +10,44 @@ the SCMI as described in ARM document number ARM DEN 0056A ("ARM System Control and Management Interface Platform Design Document")[0] provide for OSPM in the device tree. +The SCMI agent node with its properties shall be under the /firmware/ node. + +Each protocol supported by an agent be defined by a sub-node in the SCMI +agent node as described in the following sections. + +For a given SCMI agent node, the communication channel properties, as defined +by related SCMI tranport compatible bindings, can be either defined in the +root node of the SCMI device or in the subnode of the related SCMI protocol +supported by the device. In the former case, the communcation propoerties +are shared by all protocol. In the later case, each protocol node must +define all communication configuration expected by the related transport +channel. + +Required properties common to all SCMI agent node: + +- #address-cells : should be '1' if the device has sub-nodes, maps to + protocol identifier for a given sub-node. +- #size-cells : should be '0' as 'reg' property doesn't have any size + associated with it. + +SCMI Agent over Mailbox transport channel +----------------------------------------- + +SCMI messages can be exchange between agent and the SCMI server using a +mailbox device for message notification and a piece of shared memory for +message payload and protocol data transfer. + Required properties: -The scmi node with the following properties shall be under the /firmware/ node. +- compatible : "arm,scmi" -- compatible : shall be "arm,scmi" or "arm,scmi-smc" for smc/hvc transports - 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 supported. + - shmem : List of phandle pointing to the shared memory(SHM) area as per generic mailbox client binding. -- #address-cells : should be '1' if the device has sub-nodes, maps to - protocol identifier for a given sub-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 Optional properties: @@ -38,11 +60,23 @@ 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. +SCMI Agent over Arm SMCCC transport channel +------------------------------------------- + +On Arm based systems that support secure world invocation through secure +monitor, SCMI messages can be exchange between agent and the SCMI server +using an Arm SMC or HVC instruction for message notification and a piece +of shared memory for message payload and protocol data transfer. + +Required properties: + +- compatible : "arm,scmi-smc" + +- shmem : List of phandle pointing to the shared memory(SHM) area as per + generic mailbox client binding. + +- arm,smc-id : function identifier used a argument to the SMC/HVC instruction + as defined in Arm SMCCC specification [6]. Clock/Performance bindings for the clocks/OPPs based on SCMI Message Protocol ------------------------------------------------------------ @@ -105,6 +139,7 @@ Required sub-node properties: [3] Documentation/devicetree/bindings/thermal/thermal.txt [4] Documentation/devicetree/bindings/sram/sram.yaml [5] Documentation/devicetree/bindings/reset/reset.txt +[6] https://developer.arm.com/docs/den0028/latest Example: From 49b7de49fd513283ea835be8a97f9d6f788ac748 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Apr 2020 10:07:08 +0200 Subject: [PATCH 07/15] fixup! dt-bindings: arm: add Arm SMCCC transport channel (add "method") Add optional property "method" to define which of the Arm SMC or HVC instruction is to be used to invoke the SCMI server in secure world. This is needed when the platform do not provide a SMCCC 1.1 conduit method driven from the PSCI driver. Signed-off-by: Etienne Carriere --- Documentation/devicetree/bindings/arm/arm,scmi.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/arm,scmi.txt b/Documentation/devicetree/bindings/arm/arm,scmi.txt index 69e55bd651e999..e70d1e18980336 100644 --- a/Documentation/devicetree/bindings/arm/arm,scmi.txt +++ b/Documentation/devicetree/bindings/arm/arm,scmi.txt @@ -78,6 +78,12 @@ Required properties: - arm,smc-id : function identifier used a argument to the SMC/HVC instruction as defined in Arm SMCCC specification [6]. +- method : "smc" or "hvc" + Optional property defining the conduit method for to be used + for invoking the SCMI server in secure world. + "smc" states instruction SMC #0 is used whereas "hvc" states + instruction HVC #0 is used. + Clock/Performance bindings for the clocks/OPPs based on SCMI Message Protocol ------------------------------------------------------------ From 400b780dfd88daf28bf72df8f479780383ac9f1a Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Apr 2020 10:44:21 +0200 Subject: [PATCH 08/15] --- proposal of generic changes in scmi drivers --- From 60f99d34cf8b152cef2cdc7872801adc213742c3 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Sat, 28 Mar 2020 13:30:40 +0100 Subject: [PATCH 09/15] firmware: arm scmi: add header guard to local common.h Add missing header guards to local common.h. Signed-off-by: Etienne Carriere --- drivers/firmware/arm_scmi/common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 94fc2b2df94021..4f59cda89d1d75 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -6,6 +6,8 @@ * * Copyright (C) 2018 ARM Ltd. */ +#ifndef ARM_SCMI_COMMON_H +#define ARM_SCMI_COMMON_H #include #include @@ -225,3 +227,5 @@ void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer); bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, struct scmi_xfer *xfer); + +#endif /* ARM_SCMI_COMMON_H */ From 308b826bfeb6b63899fd5a09eb68eac7f64721df Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Sat, 28 Mar 2020 13:47:37 +0100 Subject: [PATCH 10/15] firmware: arm_scmi: prevent false positive timeout on message transfer Change scmi_do_xfer() to not report a timeout when transport poll_done callback handler reports success even if timeout occurred. This change prevent reporting of a timeout when poll operation is delayed, i.e. due to thread reschedule, and return success when timeout elapsed due to the executed thread being rescheduled. Signed-off-by: Etienne Carriere --- drivers/firmware/arm_scmi/driver.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 12fb431dfab4fb..c3587b52f79991 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -261,13 +261,17 @@ void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) #define SCMI_MAX_POLL_TO_NS (100 * NSEC_PER_USEC) -static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo, - struct scmi_xfer *xfer, ktime_t stop) +static bool scmi_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) { struct scmi_info *info = handle_to_scmi_info(cinfo->handle); - return info->desc->ops->poll_done(cinfo, xfer) || - ktime_after(ktime_get(), stop); + return info->desc->ops->poll_done(cinfo, xfer); +} + +static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo, + struct scmi_xfer *xfer, ktime_t stop) +{ + return scmi_poll_done(cinfo, xfer) || ktime_after(ktime_get(), stop); } /** @@ -307,7 +311,7 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) spin_until_cond(scmi_xfer_done_no_timeout(cinfo, xfer, stop)); - if (ktime_before(ktime_get(), stop)) + if (scmi_poll_done(cinfo, xfer)) info->desc->ops->fetch_response(cinfo, xfer); else ret = -ETIMEDOUT; From ff5169df6a5bb06637b1ac69940f975b9fe8d0e1 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Sat, 28 Mar 2020 13:51:42 +0100 Subject: [PATCH 11/15] firmware: arm_scmi: send_message callback returns 0 on success Fix scmi_do_xfer() to test SCMI transport callback handler return value this is expected to be 0 on success, not any positive value. Signed-off-by: Etienne Carriere --- drivers/firmware/arm_scmi/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index c3587b52f79991..3c68740d326236 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -301,7 +301,7 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) xfer->hdr.poll_completion); ret = info->desc->ops->send_message(cinfo, xfer); - if (ret < 0) { + if (ret) { dev_dbg(dev, "Failed to send message %d\n", ret); return ret; } From 655dc7ac3a21626930e44d7871712e5903e295b1 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Sat, 28 Mar 2020 13:52:59 +0100 Subject: [PATCH 12/15] firmware: arm_scmi: factorize root node test Remove transport callback handler chan_available that can be factorize for all transports. Indeed SCMI child nodes defining each expected SCMI protocol define expect protocol ID through FDT property "reg" whereas SCMI device root node does not define such "reg" property. This change replaces need for transport specific chan_available handler with a common test on SCMI root node to determine if currently probed device is the SCMI device which shall define the channel to be used whereas SCMI child node only define target protocols. This change updates mailbox transport driver accordingly. Signed-off-by: Etienne Carriere --- drivers/firmware/arm_scmi/common.h | 2 -- drivers/firmware/arm_scmi/driver.c | 11 ++++++++++- drivers/firmware/arm_scmi/mailbox.c | 7 ------- drivers/firmware/arm_scmi/smc.c | 6 ------ 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index 4f59cda89d1d75..bcb5f38042b9ab 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -174,7 +174,6 @@ struct scmi_chan_info { /** * struct scmi_transport_ops - Structure representing a SCMI transport ops * - * @chan_available: Callback to check if channel is available or not * @chan_setup: Callback to allocate and setup a channel * @chan_free: Callback to free a channel * @send_message: Callback to send a message @@ -183,7 +182,6 @@ struct scmi_chan_info { * @poll_done: Callback to poll transfer status */ struct scmi_transport_ops { - bool (*chan_available)(struct device *dev, int idx); int (*chan_setup)(struct scmi_chan_info *cinfo, struct device *dev, bool tx); int (*chan_free)(int id, void *p, void *data); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 3c68740d326236..77a31c09fa67d7 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -570,6 +570,14 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) return 0; } +/* SCMI root node has no reg property */ +static bool node_is_scmi_root_node(const struct device_node *np) +{ + u32 protocol_id; + + return of_property_read_u32(np, "reg", &protocol_id); +} + static int scmi_chan_setup(struct scmi_info *info, struct device *dev, int prot_id, bool tx) { @@ -586,7 +594,8 @@ static int scmi_chan_setup(struct scmi_info *info, struct device *dev, if (cinfo) return 0; - if (!info->desc->ops->chan_available(dev, idx)) { + /* Channels are defined in SCMI device root node */ + if (!node_is_scmi_root_node(dev->of_node)) { cinfo = idr_find(idr, SCMI_PROTOCOL_BASE); if (unlikely(!cinfo)) /* Possible only if platform has no Rx */ return -EINVAL; diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 73077bbc4ad9dc..0e3792395cc930 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -46,12 +46,6 @@ static void rx_callback(struct mbox_client *cl, void *m) scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem)); } -static bool mailbox_chan_available(struct device *dev, int idx) -{ - return !of_parse_phandle_with_args(dev->of_node, "mboxes", - "#mbox-cells", idx, NULL); -} - static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, bool tx) { @@ -167,7 +161,6 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) } static struct scmi_transport_ops scmi_mailbox_ops = { - .chan_available = mailbox_chan_available, .chan_setup = mailbox_chan_setup, .chan_free = mailbox_chan_free, .send_message = mailbox_send_message, diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index 75a4895178b84f..56cff7e5135d39 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -34,11 +34,6 @@ struct scmi_smc { static DEFINE_MUTEX(smc_mutex); -static bool smc_chan_available(struct device *dev, int idx) -{ - return true; -} - /* Simple wrapper functions to be able to use a function pointer */ static void _smccc_smc(unsigned long func_id, struct arm_smccc_res *res) { @@ -177,7 +172,6 @@ smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) } static struct scmi_transport_ops scmi_smc_ops = { - .chan_available = smc_chan_available, .chan_setup = smc_chan_setup, .chan_free = smc_chan_free, .send_message = smc_send_message, From 6b497dfa836e3d311397cf2070ab152a9cf2c36f Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 15 Apr 2020 11:07:03 +0200 Subject: [PATCH 13/15] --- draft for optee transport for scmi --- From ddb39c11d56192a5bb4d135e63fdbdd6b86fdbae Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Sat, 28 Mar 2020 14:18:53 +0100 Subject: [PATCH 14/15] [draft] firmware: arm_scmi: optee transport driver TODO: remove shmem from the bindings. Message buffer should be provided through a memref parameter to OP-TEE PTA invocation. Add a new transport channel to the SCMI firmware interface driver for SCMI message exchange based on OP-TEE transport channel that leverage OP-TEE secure threaded context for processing of SCMI messages. The current proposal uses a statically defined physical memory area to be used as shared memory SCMI endpoints. The location is extracted from the FDT upon property "shmem". Entry in OP-TEE threaded context is realized by invoking a service PTA (Pseudo TA) in OP-TEE OS. Each invocation carries a agent numerical identifier for which a message is pending in the shared memory. The OP-TEE service provides means to get the agent identifier value for a given shared memory location. OPTEE transport driver depends on CONFIG_OPTEE and probes from SCMI compatible identifier "arm,scmi-optee". Signed-off-by: Etienne Carriere # Conflicts: # drivers/firmware/arm_scmi/Makefile # drivers/firmware/arm_scmi/common.h --- drivers/firmware/Kconfig | 2 +- drivers/firmware/arm_scmi/Makefile | 1 + drivers/firmware/arm_scmi/common.h | 1 + drivers/firmware/arm_scmi/driver.c | 3 + drivers/firmware/arm_scmi/optee_service.c | 427 ++++++++++++++++++++++ 5 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/arm_scmi/optee_service.c diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 57eddfd525a4f7..28903ebfbe6070 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -9,7 +9,7 @@ menu "Firmware Drivers" config ARM_SCMI_PROTOCOL bool "ARM System Control and Management Interface (SCMI) Message Protocol" depends on ARM || ARM64 || COMPILE_TEST - depends on MAILBOX || HAVE_ARM_SMCCC + depends on MAILBOX || HAVE_ARM_SMCCC || OPTEE help ARM System Control and Management Interface (SCMI) protocol is a set of operating system-independent software interfaces that are diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 11b238f8192302..1473210c69f2ae 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -5,5 +5,6 @@ scmi-driver-y = driver.o scmi-transport-y = shmem.o scmi-transport-$(CONFIG_MAILBOX) += mailbox.o scmi-transport-$(CONFIG_HAVE_ARM_SMCCC) += smc.o +scmi-transport-$(CONFIG_OPTEE) += optee_service.o scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index bcb5f38042b9ab..aacfa14589b200 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -211,6 +211,7 @@ struct scmi_desc { extern const struct scmi_desc scmi_mailbox_desc; extern const struct scmi_desc scmi_smc_desc; +extern const struct scmi_desc scmi_optee_desc; void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr); void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id); diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 77a31c09fa67d7..9fa325560d997e 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -844,6 +844,9 @@ static const struct of_device_id scmi_of_match[] = { #endif #ifdef CONFIG_HAVE_ARM_SMCCC { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc}, +#endif +#ifdef CONFIG_OPTEE + { .compatible = "arm,scmi-optee", .data = &scmi_optee_desc }, #endif { /* Sentinel */ }, }; diff --git a/drivers/firmware/arm_scmi/optee_service.c b/drivers/firmware/arm_scmi/optee_service.c new file mode 100644 index 00000000000000..743877dd731277 --- /dev/null +++ b/drivers/firmware/arm_scmi/optee_service.c @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define DRIVER_NAME "optee-scmi-agent" + +/* + * TA_CMD_CHANNEL_COUNT - Get number of channels supported + * + * param[0] (out value) - value.a: Number of communication channels + * param[1] unused + * param[2] unused + * param[3] unused + * + * Result: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param + */ +#define TA_CMD_CHANNEL_COUNT 0x0 + +/* + * TA_CMD_GET_CHANNEL - Get channel identifer for a buffer pool + * + * param[0] (in value) - Message buffer physical start address + * param[1] (in value) - Message buffer byte size + * param[2] (out value) - value.a: Output channel identifier + * param[3] unused + * + * Result: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param + */ +#define TA_CMD_GET_CHANNEL 0x1 + + +/* + * TA_CMD_PROCESS_CHANNEL - Process message in SCMI channel + * + * param[0] (in value) - value.a: SCMI channel identifier + * param[1] unused + * param[2] unused + * param[3] unused + * + * Result: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param + */ +#define TA_CMD_PROCESS_CHANNEL 0x2 + +/** + * struct optee_scmi_agent - OP-TEE Random Number Generator private data + * @dev: OP-TEE based SCMI server device. + * @ctx: OP-TEE context handler. + * @session_id: SCMI server TA session identifier. + * @agent_count: Count of agent channels supported by the server + */ +struct optee_scmi_agent { + struct device *dev; + struct tee_context *ctx; + u32 session_id; + unsigned int agent_count; +}; + +static struct optee_scmi_agent agent_private; + +static int get_channel_count(void) +{ + int ret = 0; + struct tee_ioctl_invoke_arg inv_arg; + struct tee_param param[4]; + + dev_info(agent_private.dev, "count channels\n"); + + memset(&inv_arg, 0, sizeof(inv_arg)); + memset(¶m, 0, sizeof(param)); + + /* Invoke TA_CMD_CHANNEL_COUNT function of Trusted App */ + inv_arg.func = TA_CMD_CHANNEL_COUNT; + inv_arg.session = agent_private.session_id; + inv_arg.num_params = 4; + + /* Fill invoke cmd params */ + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; + + ret = tee_client_invoke_func(agent_private.ctx, &inv_arg, param); + if ((ret < 0) || (inv_arg.ret != 0)) { + dev_err(agent_private.dev, "Failed to get agent count: 0x%x\n", + inv_arg.ret); + return -ENOTSUPP; + } + + dev_info(agent_private.dev, "count channels: back: %u\n", + (unsigned)param[0].u.value.a); + + agent_private.agent_count = param[0].u.value.a; + + return 0; +} + +static int get_channel(unsigned long pa, size_t length, int *channel_id) +{ + int ret = 0; + struct tee_ioctl_invoke_arg inv_arg; + struct tee_param param[4]; + uint64_t addr = pa; + + memset(&inv_arg, 0, sizeof(inv_arg)); + memset(¶m, 0, sizeof(param)); + + /* Invoke TA_CMD_GET_CHANNEL function of Trusted App */ + inv_arg.func = TA_CMD_GET_CHANNEL; + inv_arg.session = agent_private.session_id; + inv_arg.num_params = 4; + + /* Fill invoke cmd params */ + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + param[0].u.value.a = addr >> 32; + param[0].u.value.b = addr & 0xffffffff; + param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + param[1].u.value.a = length; + param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; + + ret = tee_client_invoke_func(agent_private.ctx, &inv_arg, param); + if ((ret < 0) || (inv_arg.ret != 0)) { + dev_err(agent_private.dev, "Failed to get channel: 0x%x\n", + inv_arg.ret); + return -ENOTSUPP; + } + + *channel_id = param[2].u.value.a; + + return 0; +} + +static int process_event(unsigned int channel_id) +{ + int ret = 0; + struct tee_ioctl_invoke_arg inv_arg; + struct tee_param param[4]; + + memset(&inv_arg, 0, sizeof(inv_arg)); + memset(¶m, 0, sizeof(param)); + + /* Invoke TA_CMD_PROCESS_CHANNEL function of Trusted App */ + inv_arg.func = TA_CMD_PROCESS_CHANNEL; + inv_arg.session = agent_private.session_id; + inv_arg.num_params = 4; + + /* Fill invoke cmd params */ + param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT; + param[0].u.value.a = channel_id; + + ret = tee_client_invoke_func(agent_private.ctx, &inv_arg, param); + if ((ret < 0) || (inv_arg.ret != 0)) { + dev_err(agent_private.dev, "Failed on channel %u: 0x%x\n", + channel_id, inv_arg.ret); + return -EIO; + } + + return 0; +} + +/** + * struct optee_scmi_channel - OP-TEE server assigns channel ID per shmem + * @channle_id: Id provided by OP-TEE for the channel + */ +struct optee_scmi_channel { + uint32_t agent_id; + struct scmi_chan_info *cinfo; + struct scmi_shared_mem __iomem *shmem; +}; + +static int optee_scmi_get_channel(struct device *dev, struct resource *res, + struct optee_scmi_channel *channel) +{ + int ret; + unsigned int id = 0; + + if (!agent_private.ctx) + return -EPROBE_DEFER; + + if (!agent_private.agent_count) + return -ENOENT; + + ret = get_channel(res->start, resource_size(res), &id); + if (ret) + return ret; + + if (channel->agent_id != id) + dev_warn(dev, "Channel ID mismatch\n"); + + return 0; +} + +static int optee_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, + bool tx) +{ + const char *desc = tx ? "Tx" : "Rx"; + int idx = tx ? 0 : 1; + struct device *cdev = cinfo->dev; + struct optee_scmi_channel *channel; + u32 agent_id; + struct device_node *shmem; + resource_size_t size; + struct resource res; + int ret; + + channel = devm_kzalloc(dev, sizeof(*channel), GFP_KERNEL); + if (!channel) + return -ENOMEM; + + if (of_property_read_u32(dev->of_node, "agent-id", &agent_id)) { + dev_err(dev, "Missing \"agent-id\" property\n"); + return -EINVAL; + } + channel->agent_id = agent_id; + + // TODO: remove this: push buffer in invocation memeref parameter + shmem = of_parse_phandle(cdev->of_node, "shmem", idx); + if (!shmem) { + dev_err(cdev, "OPTEE failed to get SCMI %s shm\n", desc); + return -ENOENT; + } + + ret = of_address_to_resource(shmem, 0, &res); + of_node_put(shmem); + if (ret) { + dev_err(cdev, "failed to get SCMI %s shared memory\n", desc); + return ret; + } + + /* Get channel IDs from shm location */ + ret = optee_scmi_get_channel(dev, &res, channel); + if (ret) { + dev_err(dev, "failed to get OP-TEE channel %d\n", ret); + return ret; + } + + size = resource_size(&res); + channel->shmem = devm_ioremap(dev, res.start, size); + if (!channel->shmem) { + dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc); + return -EADDRNOTAVAIL; + } + + cinfo->transport_info = channel; + channel->cinfo = cinfo; + + return 0; +} + +static int optee_chan_free(int id, void *p, void *data) +{ + struct scmi_chan_info *cinfo = p; + struct optee_scmi_channel *channel = cinfo->transport_info; + + cinfo->transport_info = NULL; + channel->cinfo = NULL; + + scmi_free_channel(cinfo, data, id); + + return 0; +} + +static int optee_send_message(struct scmi_chan_info *cinfo, + struct scmi_xfer *xfer) +{ + struct optee_scmi_channel *channel = cinfo->transport_info; + int ret; + + if (!channel && !agent_private.ctx) + return -EINVAL; + + shmem_tx_prepare(channel->shmem, xfer); + + ret = process_event(channel->agent_id); + if (ret) + return ret; + + scmi_rx_callback(cinfo, shmem_read_header(channel->shmem)); + + return 0; +} + +static void optee_fetch_response(struct scmi_chan_info *cinfo, + struct scmi_xfer *xfer) +{ + struct optee_scmi_channel *channel = cinfo->transport_info; + + shmem_fetch_response(channel->shmem, xfer); +} + +static bool optee_poll_done(struct scmi_chan_info *cinfo, + struct scmi_xfer *xfer) +{ + struct optee_scmi_channel *channel = cinfo->transport_info; + + return shmem_poll_done(channel->shmem, xfer); +} + +static struct scmi_transport_ops scmi_optee_ops = { + .chan_setup = optee_chan_setup, + .chan_free = optee_chan_free, + .send_message = optee_send_message, + .fetch_response = optee_fetch_response, + .poll_done = optee_poll_done, +}; + +const struct scmi_desc scmi_optee_desc = { + .ops = &scmi_optee_ops, + .max_rx_timeout_ms = 30, /* We may increase this if required */ + .max_msg = 1, + .max_msg_size = 128, +}; + +static int optee_ctx_match(struct tee_ioctl_version_data *ver, + const void *data) +{ + return ver->impl_id == TEE_IMPL_ID_OPTEE; +} + +static int optee_scmi_probe(struct device *dev) +{ + struct tee_client_device *scmi_device = to_tee_client_device(dev); + int ret = 0, err = -ENODEV; + struct tee_ioctl_open_session_arg sess_arg; + + memset(&sess_arg, 0, sizeof(sess_arg)); + + /* Open context with TEE driver */ + agent_private.ctx = tee_client_open_context(NULL, optee_ctx_match, + NULL, NULL); + if (IS_ERR(agent_private.ctx)) + return -ENODEV; + + /* Open session with SCMI server TA */ + memcpy(sess_arg.uuid, scmi_device->id.uuid.b, TEE_IOCTL_UUID_LEN); + sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; + sess_arg.num_params = 0; + + ret = tee_client_open_session(agent_private.ctx, &sess_arg, NULL); + if ((ret < 0) || (sess_arg.ret != 0)) { + dev_err(dev, "tee_client_open_session failed, err: %x\n", + sess_arg.ret); + err = -EINVAL; + goto out_ctx; + } + agent_private.session_id = sess_arg.session; + + err = get_channel_count(); + if (err) + goto out_sess; + + agent_private.dev = dev; + + dev_info(dev, "OP-TEE SCMI channel probed\n"); + + return 0; + +out_sess: + tee_client_close_session(agent_private.ctx, agent_private.session_id); +out_ctx: + tee_client_close_context(agent_private.ctx); + agent_private.ctx = NULL; + + return err; +} + +static int optee_scmi_remove(struct device *dev) +{ + tee_client_close_session(agent_private.ctx, agent_private.session_id); + tee_client_close_context(agent_private.ctx); + agent_private.ctx = NULL; + + return 0; +} + +static const struct tee_client_device_id optee_scmi_id_table[] = { + { + UUID_INIT(0xa8cfe406, 0xd4f5, 0x4a2e, + 0x9f, 0x8d, 0xa2, 0x5d, 0xc7, 0x54, 0xc0, 0x99) + }, + { } +}; + +MODULE_DEVICE_TABLE(tee, optee_scmi_id_table); + +static struct tee_client_driver optee_scmi_driver = { + .id_table = optee_scmi_id_table, + .driver = { + .name = DRIVER_NAME, + .bus = &tee_bus_type, + .probe = optee_scmi_probe, + .remove = optee_scmi_remove, + }, +}; + +static int __init optee_scmi_init(void) +{ + return driver_register(&optee_scmi_driver.driver); +} + +static void __exit optee_scmi_exit(void) +{ + driver_unregister(&optee_scmi_driver.driver); +} + +module_init(optee_scmi_init); +module_exit(optee_scmi_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Etienne Carriere "); +MODULE_DESCRIPTION("OP-TEE SCMI agent driver"); From 026fff1db4f8c3b0319f0deafc4d0a9881f4200d Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Sun, 12 Apr 2020 15:32:35 +0200 Subject: [PATCH 15/15] dt-bindings: arm: OP-TEE as transport channel for SCMI messages Introduce compatible "linaro,scmi-optee" for SCMI transport channel based on an OP-TEE service invocation. This device mandates an agent_id property to identify the SCMI agent invoking the OP-TEE service. SCMI message is transmitted to the OP-TEE using OP-TEE native shared buffer support. Signed-off-by: Etienne Carriere --- Documentation/devicetree/bindings/arm/arm,scmi.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/arm,scmi.txt b/Documentation/devicetree/bindings/arm/arm,scmi.txt index e70d1e18980336..596561a569fe81 100644 --- a/Documentation/devicetree/bindings/arm/arm,scmi.txt +++ b/Documentation/devicetree/bindings/arm/arm,scmi.txt @@ -84,6 +84,19 @@ Required properties: "smc" states instruction SMC #0 is used whereas "hvc" states instruction HVC #0 is used. +SCMI Agent over on OP-TEE Service +--------------------------------- + +On systems that support OP-TEE, SCMI messages can be exchange between agent +and the SCMI server using an OP-TEE invocation. + +Required properties: + +- compatible : "linaro,scmi-optee" + +- agent-id : agent identifier assigned to the agent/channel and known from + the SCMI server in OP-TEE. + Clock/Performance bindings for the clocks/OPPs based on SCMI Message Protocol ------------------------------------------------------------