* [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware
@ 2026-03-17 18:03 Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 1/6] dt-bindings: firmware: Add TEE remoteproc service binding Arnaud Pouliquen
` (6 more replies)
0 siblings, 7 replies; 13+ messages in thread
From: Arnaud Pouliquen @ 2026-03-17 18:03 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
Main updates from version V20[4]:
--------------------------------
To address Rob’s concern on v20concerning resource declaration under the
tee node, the device tree is now structured as follows,replacing the
child-parent hierarchy with a phandle:
firmware {
tee_rproc: optee-rproc {
compatible = "80a4c275-0a47-4905-8285-1486a9771a08";
};
};
m4: m4@0 {
compatible = "st,stm32mp1-m4-tee";
reg = <0 0>;
mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
mbox-names = "vq0", "vq1", "shutdown";
memory-region = <&vdev0vring0>, <&m_ipc_shm>, <&mcuram2>,
<&vdev0vring1>, <&vdev0buffer>, <&retram>;
interrupt-parent = <&exti>;
interrupts = <68 1>;
rproc-tee-phandle = <&tee_rproc 0>;
st,auto-boot;
wakeup-source;
status = "okay";
};
As a consequence, this version:
- Updates the device tree and bindings to:
- Change the compatible property from
"rproc-service-80a4c275-0a47-4905-8285-1486a9771a08" to
"80a4c275-0a47-4905-8285-1486a9771a08".
- Use the rproc-tee-phandle to avoid the parent-child hierarchy.
- Updates stm32_rproc_tee.c and remoteproc_tee.c to adapt to the new bindings.
- Updates remoteproc_tee.c to compute the device tree compatible string from
the TEE UUID.
Main updates from version V19[3]:
--------------------------------
The devicetree is now structured as follows:
firmware {
optee {
compatible = "linaro,optee-tz";
method = "smc";
#address-cells = <1>;
#size-cells = <0>;
rproc-service@0 {
compatible = "rproc-service-80a4c275-0a47-4905-8285-1486a9771a08";
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
m4: m4@0 {
compatible = "st,stm32mp15-m4-tee";
reg = <0>;
mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
mbox-names = "vq0", "vq1", "shutdown";
memory-region = <&vdev0vring0>, <&m_ipc_shm>, <&mcuram2>,
<&vdev0vring1>, <&vdev0buffer>, <&retram>;
interrupt-parent = <&exti>;
interrupts = <68 1>;
status = "okay";
};
};
};
};
As a consequence, this version:
- Introduces a new stm32_rproc_tee.c remoteproc driver.
Instead of further complicating the existing stm32_rproc.c driver, a
dedicated TEE-based driver is added. Both drivers are intended to also
support the STM32MP2x Cortex-M33 remote processor in a next step.
- Reworks the bindings:
- Drop the st,stm32-rproc.yaml updates that were introduced in previous
revisions.
- Add remoteproc-tee.yaml for the
"rproc-service-80a4c275-0a47-4905-8285-1486a9771a08" compatible.
- Add st,stm32-rproc-tee.yaml for the "st,stm32mp15-m4-tee" compatible.
- Reworks the probing sequence:
The m4@0 device is now probed by the remoteproc-tee driver, which itself
is instantiated by the TEE (OP-TEE) bus.
Main updates from version V18[2]:
--------------------------------
- rework documentation for the release_fw ops
- rework function documentation in remoteproc_tee.c
- replace spinlock by mutex and generalize usage in remoteproc_tee.c
Main updates from version V17[1]:
--------------------------------
- Fix: warning: EXPORT_SYMBOL() is used, but #include <linux/export.h>
is missing
More details are available in each patch commit message.
[1] https://lore.kernel.org/linux-remoteproc/20250613091650.2337411-1-arnaud.pouliquen@foss.st.com/
[2] https://lore.kernel.org/linux-remoteproc/20250616075530.4106090-1-arnaud.pouliquen@foss.st.com/
[3] https://lore.kernel.org/linux-devicetree/20250625094028.758016-1-arnaud.pouliquen@foss.st.com/
[3] https://lore.kernel.org/linux-remoteproc/20251217153917.3998544-1-arnaud.pouliquen@foss.st.com/
Tested-on:
---------
commit 1f318b96cc84 ("Linux 7.0-rc3")
Description of the feature:
--------------------------
This series proposes the implementation of a remoteproc tee driver to
communicate with a TEE trusted application responsible for authenticating
and loading the remoteproc firmware image in an Arm secure context.
1) Principle:
The remoteproc tee driver provides services to communicate with the OP-TEE
trusted application running on the Trusted Execution Context (TEE).
The trusted application in TEE manages the remote processor lifecycle:
- authenticating and loading firmware images,
- isolating and securing the remote processor memories,
- supporting multi-firmware (e.g., TF-M + Zephyr on a Cortex-M33),
- managing the start and stop of the firmware by the TEE.
2) Format of the signed image:
Refer to:
https://github.com/OP-TEE/optee_os/blob/master/ta/remoteproc/src/remoteproc_core.c#L18-L57
3) OP-TEE trusted application API:
Refer to:
https://github.com/OP-TEE/optee_os/blob/master/ta/remoteproc/include/ta_remoteproc.h
4) OP-TEE signature script
Refer to:
https://github.com/OP-TEE/optee_os/blob/master/scripts/sign_rproc_fw.py
Example of usage:
sign_rproc_fw.py --in <fw1.elf> --in <fw2.elf> --out <signed_fw.sign> --key ${OP-TEE_PATH}/keys/default.pem
5) Impact on User space Application
No sysfs impact. The user only needs to provide the signed firmware image
instead of the ELF image.
For more information about the implementation, a presentation is available here
(note that the format of the signed image has evolved between the presentation
and the integration in OP-TEE).
https://resources.linaro.org/en/resource/6c5bGvZwUAjX56fvxthxds
Arnaud Pouliquen (6):
dt-bindings: firmware: Add TEE remoteproc service binding
dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding
remoteproc: core: Introduce rproc_pa_to_va helper
remoteproc: Introduce optional release_fw operation
remoteproc: Add TEE support
remoteproc: stm32: Add TEE-controlled STM32 driver
.../bindings/remoteproc/remoteproc-tee.yaml | 36 +
.../remoteproc/st,stm32-rproc-tee.yaml | 108 +++
drivers/remoteproc/Kconfig | 10 +
drivers/remoteproc/Makefile | 3 +-
drivers/remoteproc/remoteproc_core.c | 52 ++
drivers/remoteproc/remoteproc_internal.h | 6 +
drivers/remoteproc/remoteproc_tee.c | 810 ++++++++++++++++++
drivers/remoteproc/stm32_rproc_tee.c | 537 ++++++++++++
include/linux/remoteproc.h | 6 +
include/linux/remoteproc_tee.h | 91 ++
10 files changed, 1658 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
create mode 100644 Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
create mode 100644 drivers/remoteproc/remoteproc_tee.c
create mode 100644 drivers/remoteproc/stm32_rproc_tee.c
create mode 100644 include/linux/remoteproc_tee.h
base-commit: 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681
--
2.43.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v21 1/6] dt-bindings: firmware: Add TEE remoteproc service binding
2026-03-17 18:03 [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
@ 2026-03-17 18:03 ` Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding Arnaud Pouliquen
` (5 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Arnaud Pouliquen @ 2026-03-17 18:03 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
Add a device tree binding for the TEE-based remote processor control
service implemented as an OP-TEE Trusted Application identified by
UUID 80a4c275-0a47-4905-8285-1486a9771a08.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
v21 update:
- rename compatible to exactly match with the TEE UUID
- the remoteproc device driver is no more declared as a child,
but use phandle as done for the SCMI.
- remove linaro,optee-tz bindings update are now useless.
---
.../bindings/remoteproc/remoteproc-tee.yaml | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
diff --git a/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
new file mode 100644
index 000000000000..e7bf135136bf
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/remoteproc-tee.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: TEE Remote Processor Control Service (UUID 80a4c275-0a47-4905-8285-1486a9771a08)
+
+maintainers:
+ - Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
+
+description: |
+ Node describing a TEE-based remote processor control service implemented as
+ a Trusted Application identified by UUID 80a4c275-0a47-4905-8285-1486a9771a08.
+
+ This binding is intended to define the interface for remoteproc services
+ implemented as TAs running in a TEE, and is used by the a remoteproc driver
+ to bind to such a service and control a remote processor through it.
+
+properties:
+ compatible:
+ const: 80a4c275-0a47-4905-8285-1486a9771a08
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ firmware {
+ tee_rproc: optee-rproc {
+ compatible = "80a4c275-0a47-4905-8285-1486a9771a08";
+ };
+ };
+...
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding
2026-03-17 18:03 [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 1/6] dt-bindings: firmware: Add TEE remoteproc service binding Arnaud Pouliquen
@ 2026-03-17 18:03 ` Arnaud Pouliquen
2026-03-19 8:06 ` Krzysztof Kozlowski
2026-03-19 8:06 ` Krzysztof Kozlowski
2026-03-17 18:03 ` [PATCH v21 3/6] remoteproc: core: Introduce rproc_pa_to_va helper Arnaud Pouliquen
` (4 subsequent siblings)
6 siblings, 2 replies; 13+ messages in thread
From: Arnaud Pouliquen @ 2026-03-17 18:03 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
Add a Device Tree binding for the STM32 remote processor controlled
via a Trusted Application running in OP-TEE.
This binding describes the interface and properties required for STM32MP
remoteproc instances managed by the TEE rproc service, including a
linkage to the TEE backend through the property "rproc-tee-phandle".
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
V21 updates:
- the m4 node is no more declared as a child of the optee-rproc node
- "rproc-tee-phandle" property is introduced to reference the optee-rproc
---
.../remoteproc/st,stm32-rproc-tee.yaml | 108 ++++++++++++++++++
1 file changed, 108 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
new file mode 100644
index 000000000000..ca4dd1c8e7b0
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/st,stm32-rproc-tee.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 remote processor controlled via TEE
+
+maintainers:
+ - Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
+
+description: |
+ STM32MP remote processor controlled by a Trusted Application
+ running in OP-TEE. This node is a child of the TEE remoteproc service
+ (UUID 80a4c275-0a47-4905-8285-1486a9771a08) and exposes a remoteproc
+ instance managed by the Linux remoteproc core via the TEE rproc service.
+
+ Firmware loading, authentication and remote processor start/stop are managed
+ by the TEE application. The STM32-specific driver handles platform resources
+ such as the mailboxes and reserved-memory.
+
+properties:
+ compatible:
+ const: st,stm32mp1-m4-tee
+
+ reg:
+ description: |
+ Remote processor identifier used by the TEE service. The <0> value
+ in the example denotes a single instance with ID 0.
+ maxItems: 1
+
+ mboxes:
+ description: |
+ Mailbox channels used for rpmsg/virtio functionality and processor
+ shutdown.
+ maxItems: 3
+
+ mbox-names:
+ items:
+ - const: vq0
+ - const: vq1
+ - const: shutdown
+
+ memory-region:
+ description: |
+ List of phandles to reserved-memory nodes describing the memory layout
+ for the interprocessors communication.
+
+ interrupts:
+ description: |
+ Optional watchdog / status interrupt line used to detect crashes
+ and optionally wake up the system.
+ maxItems: 1
+
+ st,auto-boot:
+ type: boolean
+ description: |
+ If present, the remote processor will be automatically started by
+ the remoteproc core at boot.
+
+ wakeup-source:
+ type: boolean
+ description: |
+ Indicates that the watchdog interrupt can be used as a wakeup source.
+
+ rproc-tee-phandle:
+ description: |
+ Phandle to the remote processor backend node and its identifier. This property
+ is used to link the TEE remoteproc service to the remote processor instance
+ it controls. The value is a phandle reference to the remote processor node,
+ followed by a cell specifying the remote processor identifier used by the TEE.
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+
+required:
+ - compatible
+ - reg
+ - rproc-tee-phandle
+
+additionalProperties: false
+
+examples:
+ - |
+ firmware {
+ tee_rproc: optee-rproc {
+ compatible = "80a4c275-0a47-4905-8285-1486a9771a08";
+ };
+ };
+
+ m4: m4@0 {
+ compatible = "st,stm32mp1-m4-tee";
+ reg = <0 0>;
+
+ mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
+ mbox-names = "vq0", "vq1", "shutdown";
+
+ memory-region = <&vdev0vring0>, <&m_ipc_shm>, <&mcuram2>,
+ <&vdev0vring1>, <&vdev0buffer>, <&retram>;
+
+ interrupt-parent = <&exti>;
+ interrupts = <68 1>;
+
+ rproc-tee-phandle = <&tee_rproc 0>;
+ st,auto-boot;
+ wakeup-source;
+
+ status = "okay";
+ };
+...
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v21 3/6] remoteproc: core: Introduce rproc_pa_to_va helper
2026-03-17 18:03 [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 1/6] dt-bindings: firmware: Add TEE remoteproc service binding Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding Arnaud Pouliquen
@ 2026-03-17 18:03 ` Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 4/6] remoteproc: Introduce optional release_fw operation Arnaud Pouliquen
` (3 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Arnaud Pouliquen @ 2026-03-17 18:03 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
When a resource table is loaded by an external entity such as U-boot or
OP-TEE, we do not necessarily get the device address(da) but the physical
address(pa).
This helper performs similar translation than the rproc_da_to_va()
but based on a physical address.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
drivers/remoteproc/remoteproc_core.c | 46 ++++++++++++++++++++++++++++
include/linux/remoteproc.h | 1 +
2 files changed, 47 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index b087ed21858a..a44c8039449d 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -225,6 +225,52 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem)
}
EXPORT_SYMBOL(rproc_da_to_va);
+/**
+ * rproc_pa_to_va() - lookup the kernel virtual address for a physical address of a remoteproc
+ * memory
+ *
+ * @rproc: handle of a remote processor
+ * @pa: remoteproc physical address
+ * @len: length of the memory region @pa is pointing to
+ * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory
+ *
+ * This function is a helper function similar to rproc_da_to_va() but it deals with physical
+ * addresses instead of device addresses.
+ *
+ * Return: a valid kernel address on success or NULL on failure
+ */
+void *rproc_pa_to_va(struct rproc *rproc, phys_addr_t pa, size_t len, bool *is_iomem)
+{
+ struct rproc_mem_entry *carveout;
+ void *ptr = NULL;
+
+ list_for_each_entry(carveout, &rproc->carveouts, node) {
+ int offset = pa - carveout->dma;
+
+ /* Verify that carveout is allocated */
+ if (!carveout->va)
+ continue;
+
+ /* try next carveout if da is too small */
+ if (offset < 0)
+ continue;
+
+ /* try next carveout if da is too large */
+ if (offset + len > carveout->len)
+ continue;
+
+ ptr = carveout->va + offset;
+
+ if (is_iomem)
+ *is_iomem = carveout->is_iomem;
+
+ break;
+ }
+
+ return ptr;
+}
+EXPORT_SYMBOL(rproc_pa_to_va);
+
/**
* rproc_find_carveout_by_name() - lookup the carveout region by a name
* @rproc: handle of a remote processor
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index b4795698d8c2..8fd0d7f63c8e 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -690,6 +690,7 @@ int rproc_detach(struct rproc *rproc);
int rproc_set_firmware(struct rproc *rproc, const char *fw_name);
void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type);
void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem);
+void *rproc_pa_to_va(struct rproc *rproc, phys_addr_t pa, size_t len, bool *is_iomem);
/* from remoteproc_coredump.c */
void rproc_coredump_cleanup(struct rproc *rproc);
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v21 4/6] remoteproc: Introduce optional release_fw operation
2026-03-17 18:03 [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
` (2 preceding siblings ...)
2026-03-17 18:03 ` [PATCH v21 3/6] remoteproc: core: Introduce rproc_pa_to_va helper Arnaud Pouliquen
@ 2026-03-17 18:03 ` Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 5/6] remoteproc: Add TEE support Arnaud Pouliquen
` (2 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Arnaud Pouliquen @ 2026-03-17 18:03 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
The release_fw operation allows releasing remote processor resources
configured during rproc_parse_fw() and rproc_load_segments().
For example, it can release carveouts mapped during these operations.
This operation is invoked in the following cases:
- When an error occurs during remote processor boot.
- When an error occurs during remote processor recovery start.
- After stopping the remote processor.
This operation is required for the remoteproc_tee implementation following
a stop or upon encountering an error. Since the remoteproc image is loaded
during resource table parsing, multiple failure scenarios may occur prior
to remote processor startup, including issues with resource handling and
carveout allocation.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
Updates from version 18:
- Rewrite rproc_ops::release_fw documentation
- Improve commit message
Updates from version 16:
- Removed the rproc:load_fw() ops introduced in previous version.
- Removed duplicate calls to rproc_release_fw in rproc_fw_boot and rproc_boot.
---
drivers/remoteproc/remoteproc_core.c | 6 ++++++
drivers/remoteproc/remoteproc_internal.h | 6 ++++++
include/linux/remoteproc.h | 5 +++++
3 files changed, 17 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index a44c8039449d..a0760ad76b13 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1852,6 +1852,8 @@ static int rproc_boot_recovery(struct rproc *rproc)
/* boot the remote processor up again */
ret = rproc_start(rproc, firmware_p);
+ if (ret)
+ rproc_release_fw(rproc);
release_firmware(firmware_p);
@@ -1993,6 +1995,8 @@ int rproc_boot(struct rproc *rproc)
}
ret = rproc_fw_boot(rproc, firmware_p);
+ if (ret)
+ rproc_release_fw(rproc);
release_firmware(firmware_p);
}
@@ -2062,6 +2066,8 @@ int rproc_shutdown(struct rproc *rproc)
rproc_disable_iommu(rproc);
+ rproc_release_fw(rproc);
+
/* Free the copy of the resource table */
kfree(rproc->cached_table);
rproc->cached_table = NULL;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 0cd09e67ac14..c7fb908f8652 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -221,4 +221,10 @@ bool rproc_u64_fit_in_size_t(u64 val)
return (val <= (size_t) -1);
}
+static inline void rproc_release_fw(struct rproc *rproc)
+{
+ if (rproc->ops->release_fw)
+ rproc->ops->release_fw(rproc);
+}
+
#endif /* REMOTEPROC_INTERNAL_H */
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 8fd0d7f63c8e..a2bb51a113b1 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -381,6 +381,10 @@ enum rsc_handling_status {
* @panic: optional callback to react to system panic, core will delay
* panic at least the returned number of milliseconds
* @coredump: collect firmware dump after the subsystem is shutdown
+ * @release_fw: Optional function to release resources allocated during
+ * parse_fw() or load() operations. This function is called after
+ * stopping the remote processor or in case of an error during the
+ * boot or recovery sequence.
*/
struct rproc_ops {
int (*prepare)(struct rproc *rproc);
@@ -403,6 +407,7 @@ struct rproc_ops {
u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
unsigned long (*panic)(struct rproc *rproc);
void (*coredump)(struct rproc *rproc);
+ void (*release_fw)(struct rproc *rproc);
};
/**
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v21 5/6] remoteproc: Add TEE support
2026-03-17 18:03 [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
` (3 preceding siblings ...)
2026-03-17 18:03 ` [PATCH v21 4/6] remoteproc: Introduce optional release_fw operation Arnaud Pouliquen
@ 2026-03-17 18:03 ` Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 6/6] remoteproc: stm32: Add TEE-controlled STM32 driver Arnaud Pouliquen
2026-03-19 8:07 ` [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Krzysztof Kozlowski
6 siblings, 0 replies; 13+ messages in thread
From: Arnaud Pouliquen @ 2026-03-17 18:03 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
Add a remoteproc TEE (Trusted Execution Environment) driver that will be
probed by the TEE bus. If the associated Trusted application is supported
on the secure part, this driver offers a client interface to load firmware
by the secure part.
This firmware could be authenticated by the secure trusted application.
A specificity of the implementation is that the firmware has to be
authenticated and optionally decrypted to access the resource table.
Consequently, the boot sequence is:
1) rproc_parse_fw --> rproc_tee_parse_fw
remoteproc TEE:
- Requests the TEE application to authenticate and load the firmware
in the remote processor memories.
- Requests the TEE application for the address of the resource table.
- Creates a copy of the resource table stored in rproc->cached_table.
2) rproc_load_segments --> rproc_tee_load_fw
remoteproc TEE:
- Requests the TEE application to load the firmware. Nothing is done
at the TEE application as the firmware is already loaded.
- In case of recovery, the TEE application has to reload the firmware.
3) rproc_tee_get_loaded_rsc_table
remoteproc TEE requests the TEE application for the address of the
resource table.
4) rproc_start --> rproc_tee_start
- Requests the TEE application to start the remote processor.
The shutdown sequence is:
5) rproc_stop --> rproc_tee_stop
- Requests the TEE application to stop the remote processor.
6) rproc_tee_release_fw
This function is used to request the TEE application to perform actions
to return to the initial state on stop or on error during the boot
sequence.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
Version 21 updates:
- introduce uuid_to_str() to compute the compatible from the TEE UUID
- update rproc_tee_register() to provide phandle referenced in the
remoteproc driver client.
- use device_link_add() to link the remoteproc driver client.
Version 20 updates:
- rework probe. the remoteproc-tee now probe the remoteproc devices
defined in device tree as child.
- creation of rproc-service-80a4c275-0a47-4905-8285-1486a9771a08 compatible
- use of of_find_compatible_node() to find node in DT
- use of of_platform_populate() to probe remoteproc devices
- remove device_link_add() as now managed by of_platform_populate)
- add "auto_boot" parameter in rproc_tee_register()
- rename TA_RPROC_FW_CMD_* TEE CMD in TA_RPROC_CMD_* command
- use of DEFINE_MUTEX
Version 19 updates:
- rework/fix function headers
- use memremap instead of ioremap for the resource table.
- realign comments to 80 chars limit, with few exceptions for readability
- replace spinlock by mutex and and protect APIs from concurrent access
- add support of 64-bit address in rproc_tee_get_loaded_rsc_table()
- update copyright year
Version 18 updates
Fix warning:
warning: EXPORT_SYMBOL() is used, but #include <linux/export.h> is missing
---
drivers/remoteproc/Kconfig | 10 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/remoteproc_tee.c | 810 ++++++++++++++++++++++++++++
include/linux/remoteproc_tee.h | 91 ++++
4 files changed, 912 insertions(+)
create mode 100644 drivers/remoteproc/remoteproc_tee.c
create mode 100644 include/linux/remoteproc_tee.h
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index ee54436fea5a..87d69f200590 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -23,6 +23,16 @@ config REMOTEPROC_CDEV
It's safe to say N if you don't want to use this interface.
+config REMOTEPROC_TEE
+ bool "Remoteproc support by a TEE application"
+ depends on OPTEE
+ help
+ Support a remote processor that is managed by an application running in a Trusted
+ Execution Environment (TEE). This application is responsible for loading the remote
+ processor firmware image and managing its lifecycle.
+
+ It's safe to say N if the remote processor is not managed by a TEE.
+
config IMX_REMOTEPROC
tristate "i.MX remoteproc support"
depends on ARCH_MXC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 1c7598b8475d..a1a5201982d4 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -11,6 +11,7 @@ remoteproc-y += remoteproc_sysfs.o
remoteproc-y += remoteproc_virtio.o
remoteproc-y += remoteproc_elf_loader.o
obj-$(CONFIG_REMOTEPROC_CDEV) += remoteproc_cdev.o
+obj-$(CONFIG_REMOTEPROC_TEE) += remoteproc_tee.o
obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o
obj-$(CONFIG_IMX_DSP_REMOTEPROC) += imx_dsp_rproc.o
obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o
diff --git a/drivers/remoteproc/remoteproc_tee.c b/drivers/remoteproc/remoteproc_tee.c
new file mode 100644
index 000000000000..d9b6e3d5f476
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_tee.c
@@ -0,0 +1,810 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) STMicroelectronics 2025
+ * Author: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
+ */
+
+#include <linux/firmware.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/mutex.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
+#include <linux/slab.h>
+#include <linux/tee_drv.h>
+
+#include "remoteproc_internal.h"
+
+#define MAX_TEE_PARAM_ARRAY_MEMBER 4
+
+/*
+ * Authentication and load of the firmware image in the remote processor
+ * memories by the TEE. After this step the firmware is installed in destination
+ * memories, which can then be locked to prevent access by Linux.
+ *
+ * [in] params[0].value.a: remote processor identifier
+ * [in] params[1].memref: buffer containing a temporary copy of the signed
+ * image to load.
+ */
+#define TA_RPROC_CMD_LOAD_FW 1
+
+/*
+ * Start the remote processor by the TEE
+ *
+ * [in] params[0].value.a: remote processor identifier
+ */
+#define TA_RPROC_CMD_START 2
+
+/*
+ * Stop the remote processor by the TEE
+ *
+ * [in] params[0].value.a: remote processor identifier
+ */
+#define TA_RPROC_CMD_STOP 3
+
+/*
+ * Return the address of the resource table, or 0 if not found.
+ *
+ * [in] params[0].value.a: remote processor identifier
+ * [out] params[1].value.a: 32bit LSB resource table memory address
+ * [out] params[1].value.b: 32bit MSB resource table memory address
+ * [out] params[2].value.a: 32bit LSB resource table memory size
+ * [out] params[2].value.b: 32bit MSB resource table memory size
+ */
+#define TA_RPROC_CMD_GET_RSC_TABLE 4
+
+/*
+ * Release remote processor firmware images and associated resources.
+ * This command should be used in case an error occurs between the loading of
+ * the firmware images (TA_RPROC_CMD_LOAD_FW) and the starting of the remote
+ * processor (TA_RPROC_CMD_START) or after stopping the remote processor
+ * to release associated resources (TA_RPROC_CMD_STOP).
+ *
+ * [in] params[0].value.a: remote processor identifier
+ */
+#define TA_RPROC_CMD_RELEASE_FW 6
+
+/**
+ * struct rproc_tee_context - Global TEE backend context
+ * @rproc_list: List of registered TEE-backed remoteprocs
+ * @tee_ctx: TEE context handle
+ * @dev: TEE client device
+ */
+struct rproc_tee_context {
+ struct list_head rproc_list;
+ struct tee_context *tee_ctx;
+ struct device *dev;
+};
+
+/**
+ * struct rproc_tee - TEE remoteproc structure
+ * @node: Reference in global list
+ * @rproc: Remoteproc reference
+ * @rproc_id: remote processor identifier
+ * @session_id: TEE session identifier
+ */
+struct rproc_tee {
+ struct list_head node;
+ struct rproc *rproc;
+ u32 rproc_id;
+ u32 session_id;
+};
+
+static struct rproc_tee_context rproc_tee_ctx;
+static DEFINE_MUTEX(ctx_lock); /* Protects concurrent manipulations of the rproc_tee_ctx*/
+
+static struct rproc_tee *rproc_to_trproc(struct rproc *rproc)
+{
+ struct rproc_tee *trproc;
+
+ list_for_each_entry(trproc, &rproc_tee_ctx.rproc_list, node)
+ if (trproc->rproc == rproc)
+ return trproc;
+ return NULL;
+}
+
+static void rproc_tee_prepare_args(struct rproc_tee *trproc, int cmd,
+ struct tee_ioctl_invoke_arg *arg,
+ struct tee_param *param,
+ unsigned int num_params)
+{
+ memset(arg, 0, sizeof(*arg));
+ memset(param, 0, MAX_TEE_PARAM_ARRAY_MEMBER * sizeof(*param));
+
+ arg->func = cmd;
+ arg->session = trproc->session_id;
+ arg->num_params = num_params + 1;
+
+ param[0] = (struct tee_param) {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = trproc->rproc_id,
+ };
+}
+
+static int rproc_tee_sanity_check(struct device_node *tee_np)
+{
+ /* Backend not probed yet */
+ if (!rproc_tee_ctx.dev || !rproc_tee_ctx.dev->of_node)
+ return -EPROBE_DEFER;
+
+ /* DT error: phandle points to different node than the backend we use */
+ if (tee_np != rproc_tee_ctx.dev->of_node)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * rproc_tee_release_fw() - Release the firmware for a TEE-based remote processor
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function invokes the TA_RPROC_CMD_RELEASE_FW TEE client function to
+ * release the firmware. It should only be called when the remoteproc state is
+ * RPROC_OFFLINE or RPROC_DETACHED. The function requests the TEE remoteproc
+ * application to release the firmware loaded by rproc_tee_load_fw().
+ * The request is ignored if the rproc state is RPROC_DETACHED as the remote
+ * processor is still running.
+ */
+void rproc_tee_release_fw(struct rproc *rproc)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return;
+
+ if (!rproc_tee_ctx.dev)
+ goto out;
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc)
+ goto out;
+
+ /*
+ * If the remote processor state is RPROC_DETACHED, just ignore the
+ * request, as the remote processor is still running.
+ */
+ if (rproc->state == RPROC_DETACHED)
+ goto out;
+
+ if (rproc->state != RPROC_OFFLINE) {
+ dev_err(rproc_tee_ctx.dev, "unexpected rproc state: %d\n", rproc->state);
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_RELEASE_FW, &arg, param, 0);
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_RELEASE_FW invoke failed TEE err: %#x, ret:%d\n",
+ arg.ret, ret);
+ }
+
+out:
+ mutex_unlock(&ctx_lock);
+}
+EXPORT_SYMBOL_GPL(rproc_tee_release_fw);
+
+/**
+ * rproc_tee_load_fw() - Load firmware from TEE application
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @fw: Pointer to the firmware structure containing the firmware data and size
+ *
+ * This function invokes the TA_RPROC_CMD_LOAD_FW TEE client function to load
+ * the firmware. It registers the fw->data as a shared memory region with the
+ * TEE, and request the TEE to load the firmware. This function can be called
+ * twice during the remote processor boot, a first by rproc_tee_parse_fw() to
+ * parse the resource table , and a second time by rproc_tee_load_fw().
+ * The TEE application should ignores the command if the firmware
+ * is already loaded by rproc_tee_parse_fw().
+ *
+ * Return: 0 on success, or an error code on failure
+ */
+int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ struct tee_shm *fw_shm;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ fw_shm = tee_shm_register_kernel_buf(rproc_tee_ctx.tee_ctx, (void *)fw->data, fw->size);
+ if (IS_ERR(fw_shm)) {
+ ret = PTR_ERR(fw_shm);
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_LOAD_FW, &arg, param, 1);
+
+ /* Provide the address of the firmware image */
+ param[1] = (struct tee_param) {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT,
+ .u.memref = {
+ .shm = fw_shm,
+ .size = fw->size,
+ .shm_offs = 0,
+ },
+ };
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_LOAD_FW invoke failed TEE err: %#x, ret:%d\n",
+ arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+
+ tee_shm_free(fw_shm);
+
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_load_fw);
+
+static int rproc_tee_get_loaded_rsc_table(struct rproc *rproc, phys_addr_t *rsc_pa,
+ size_t *table_sz)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_GET_RSC_TABLE, &arg, param, 2);
+
+ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+ param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_GET_RSC_TABLE invoke failed TEE err: %#x, ret:%d\n",
+ arg.ret, ret);
+ ret = -EIO;
+ goto out;
+ }
+
+ *table_sz = param[2].u.value.a;
+ if (sizeof(phys_addr_t) == sizeof(u64))
+ *table_sz |= param[2].u.value.b << 32;
+
+ if (*table_sz) {
+ *rsc_pa = param[1].u.value.a;
+ if (sizeof(phys_addr_t) == sizeof(u64))
+ *rsc_pa |= param[1].u.value.b << 32;
+ } else {
+ *rsc_pa = 0;
+ }
+
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+
+/**
+ * rproc_tee_parse_fw() - Get the resource table from TEE application
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @fw: Pointer to the firmware structure containing the firmware data and size
+ *
+ * This function retrieves the loaded resource table and creates a cached_table
+ * copy. Since the firmware image is signed and potentially encrypted, the
+ * firmware must be loaded first to access the loaded resource table.
+ *
+ * Return: 0 on success, or an error code on failure
+ */
+int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ phys_addr_t rsc_table;
+ void *rsc_va;
+ size_t table_sz;
+ int ret;
+
+ if (!rproc)
+ return -EINVAL;
+
+ /* We need first to Load the firmware, to be able to get the resource table. */
+ ret = rproc_tee_load_fw(rproc, fw);
+ if (ret)
+ return ret;
+
+ ret = rproc_tee_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
+ if (ret)
+ goto release_fw;
+
+ /*
+ * We assume here that the memory mapping is the same between the TEE
+ * and Linux kernel contexts. Else a new TEE remoteproc service could be
+ * needed to get a copy of the resource table.
+ */
+ rsc_va = memremap(rsc_table, table_sz, MEMREMAP_WC);
+ if (!rsc_va) {
+ dev_err(rproc_tee_ctx.dev, "Unable to map memory region: %pa+%zx\n",
+ &rsc_table, table_sz);
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ /*
+ * Create a copy of the resource table to have the same behavior as the
+ * ELF loader. This cached table will be used by the remoteproc core
+ * after the remoteproc stops to free resources and for crash recovery
+ * to reapply the settings.
+ * The cached table will be freed by the remoteproc core.
+ */
+ rproc->cached_table = kmemdup(rsc_va, table_sz, GFP_KERNEL);
+ memunmap(rsc_va);
+
+ if (!rproc->cached_table) {
+ ret = -ENOMEM;
+ goto release_fw;
+ }
+
+ rproc->table_ptr = rproc->cached_table;
+ rproc->table_sz = table_sz;
+
+ return 0;
+
+release_fw:
+ rproc_tee_release_fw(rproc);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_parse_fw);
+
+/**
+ * rproc_tee_find_loaded_rsc_table() - Find the loaded resource table loaded by
+ * the TEE application
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ * @fw: Pointer to the firmware structure containing the firmware data and size
+ *
+ * This function retrieves the physical address and size of the resource table
+ * loaded by the TEE application.
+ *
+ * Return: pointer to the resource table if found, or NULL if not found or size
+ * is 0
+ */
+struct resource_table *rproc_tee_find_loaded_rsc_table(struct rproc *rproc,
+ const struct firmware *fw)
+{
+ phys_addr_t rsc_table;
+ size_t table_sz;
+ int ret;
+
+ ret = rproc_tee_get_loaded_rsc_table(rproc, &rsc_table, &table_sz);
+ if (ret)
+ return NULL;
+
+ rproc->table_sz = table_sz;
+ if (!table_sz)
+ return NULL;
+
+ /*
+ * At this step the memory area that contains the resource table should
+ * have been registered by the remote proc platform driver and allocated
+ * by rproc_alloc_registered_carveouts().
+ */
+ return rproc_pa_to_va(rproc, rsc_table, table_sz, NULL);
+}
+EXPORT_SYMBOL_GPL(rproc_tee_find_loaded_rsc_table);
+
+/**
+ * rproc_tee_start() - Request the TEE application to start the remote processor
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function invokes the TA_RPROC_CMD_START command to start the remote
+ * processor.
+ *
+ * Return: Returns 0 on success, -EINVAL or -EIO on failure
+ */
+int rproc_tee_start(struct rproc *rproc)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_START, &arg, param, 0);
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_START invoke failed TEE err: %#x, ret:%d\n", arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_start);
+
+/**
+ * rproc_tee_stop() - Request the TEE application to start the remote processor
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function invokes the TA_RPROC_CMD_STOP command to stop the remote
+ * processor.
+ *
+ * Return: Returns 0 on success, -EINVAL or -EIO on failure
+ */
+int rproc_tee_stop(struct rproc *rproc)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ struct rproc_tee *trproc;
+ struct tee_ioctl_invoke_arg arg;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ rproc_tee_prepare_args(trproc, TA_RPROC_CMD_STOP, &arg, param, 0);
+
+ ret = tee_client_invoke_func(rproc_tee_ctx.tee_ctx, &arg, param);
+ if (ret < 0 || arg.ret != 0) {
+ dev_err(rproc_tee_ctx.dev,
+ "TA_RPROC_CMD_STOP invoke failed TEE err: %#x, ret:%d\n", arg.ret, ret);
+ if (!ret)
+ ret = -EIO;
+ }
+
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_stop);
+
+static const struct rproc_ops rproc_tee_default_ops = {
+ .start = rproc_tee_start,
+ .stop = rproc_tee_stop,
+ .load = rproc_tee_load_fw,
+ .parse_fw = rproc_tee_parse_fw,
+ .find_loaded_rsc_table = rproc_tee_find_loaded_rsc_table,
+ .release_fw = rproc_tee_release_fw,
+};
+
+/**
+ * rproc_tee_register() - Register a remote processor controlled by the TEE application
+ * @dev: client rproc device
+ * @rproc: out pointer to the struct rproc representing the remote processor
+ * @tee_phandle: backend phandle args (np + 1 cell: rproc_id)
+ * @auto_boot: flag to indicate if remote processor should be auto-started
+ *
+ * The phandle must point to the same DT node that rproc_tee_probe() attached
+ * to the TEE client device.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int rproc_tee_register(struct device *dev, struct rproc **rproc,
+ const struct of_phandle_args *tee_phandle,
+ bool auto_boot)
+{
+ struct tee_param param[MAX_TEE_PARAM_ARRAY_MEMBER];
+ unsigned int rproc_id;
+ struct device_node *tee_np;
+ struct tee_ioctl_open_session_arg sess_arg;
+ struct device_node *np = dev->of_node;
+ struct tee_client_device *tee_device;
+ struct device_link *link;
+ struct rproc_tee *trproc;
+ struct rproc *new_rproc;
+ const char *fw_name;
+ int ret;
+
+ if (!tee_phandle || !tee_phandle->np || tee_phandle->args_count < 1)
+ return -EINVAL;
+
+ rproc_id = tee_phandle->args[0];
+ tee_np = tee_phandle->np;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ ret = rproc_tee_sanity_check(tee_np);
+ if (ret)
+ goto out;
+
+ trproc = kzalloc_obj(*trproc);
+ if (!trproc) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Look for an optional firmware name */
+ ret = rproc_of_parse_firmware(dev, 0, &fw_name);
+ if (ret < 0 && ret != -EINVAL)
+ goto free_trproc;
+
+ new_rproc = rproc_alloc(dev, np->name, &rproc_tee_default_ops,
+ fw_name, sizeof(*trproc));
+ if (!new_rproc) {
+ ret = -ENOMEM;
+ goto free_trproc;
+ }
+
+ tee_device = to_tee_client_device(rproc_tee_ctx.dev);
+ memset(&sess_arg, 0, sizeof(sess_arg));
+ memcpy(sess_arg.uuid, tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN);
+
+ sess_arg.clnt_login = TEE_IOCTL_LOGIN_REE_KERNEL;
+ sess_arg.num_params = 1;
+
+ param[0] = (struct tee_param) {
+ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT,
+ .u.value.a = rproc_id,
+ };
+
+ ret = tee_client_open_session(rproc_tee_ctx.tee_ctx, &sess_arg, param);
+ if (ret < 0 || sess_arg.ret != 0) {
+ dev_err(dev, "tee_client_open_session failed, err: %#x\n",
+ sess_arg.ret);
+ ret = -EINVAL;
+ goto free_rproc;
+ }
+
+ trproc->rproc_id = rproc_id;
+ trproc->session_id = sess_arg.session;
+ new_rproc->auto_boot = auto_boot;
+
+ ret = rproc_add(new_rproc);
+ if (ret)
+ goto close_tee;
+
+ trproc->rproc = new_rproc;
+ *rproc = new_rproc;
+
+ /* Create device link between the rproc device and the TEE device */
+ link = device_link_add(dev, rproc_tee_ctx.dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!link) {
+ ret = -ENOMEM;
+ goto del_rproc;
+ }
+
+ list_add_tail(&trproc->node, &rproc_tee_ctx.rproc_list);
+
+ mutex_unlock(&ctx_lock);
+
+ return 0;
+
+del_rproc:
+ rproc_del(new_rproc);
+close_tee:
+ if (tee_client_close_session(rproc_tee_ctx.tee_ctx, trproc->session_id))
+ dev_err(rproc_tee_ctx.dev,
+ "tee_client_close_session failed\n");
+free_rproc:
+ rproc_free(new_rproc);
+free_trproc:
+ kfree(trproc);
+out:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_register);
+
+/**
+ * rproc_tee_unregister - Unregister a remote processor controlled by the TEE
+ * application.
+ * @dev: Pointer to client rproc device
+ * @rproc: Pointer to the struct rproc representing the remote processor
+ *
+ * This function unregisters a remote processor previously registered by the
+ * rproc_tee_register() function.
+ *
+ * Return: Returns 0 on success, or an error code on failure
+ */
+int rproc_tee_unregister(struct device *dev, struct rproc *rproc)
+{
+ struct rproc_tee *trproc;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ if (!rproc_tee_ctx.dev) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
+
+ trproc = rproc_to_trproc(rproc);
+ if (!trproc) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ /*
+ * Unlock ctx_lock before calling rproc_del()/rproc_free(),
+ * they may call into rproc core and take other locks to stop the
+ * remote processor, if it is running.
+ */
+ mutex_unlock(&ctx_lock);
+
+ rproc_del(rproc);
+ rproc_free(rproc);
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return ret;
+
+ ret = tee_client_close_session(rproc_tee_ctx.tee_ctx,
+ trproc->session_id);
+ if (ret < 0)
+ dev_err(rproc_tee_ctx.dev,
+ "tee_client_close_session failed, err: %#x\n", ret);
+
+ list_del(&trproc->node);
+ kfree(trproc);
+
+out_unlock:
+ mutex_unlock(&ctx_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rproc_tee_unregister);
+
+static int rproc_tee_ctx_match(struct tee_ioctl_version_data *ver,
+ const void *data)
+{
+ /* Today we support only OP-TEE; could be extended to other TEEs */
+ return ver->impl_id == TEE_IMPL_ID_OPTEE;
+}
+
+static const struct tee_client_device_id rproc_tee_id_table[] = {
+ {UUID_INIT(0x80a4c275, 0x0a47, 0x4905, 0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(tee, rproc_tee_id_table);
+
+static void uuid_to_str(const struct tee_client_device_id *id, char *uuid_str)
+{
+ snprintf(uuid_str, UUID_STRING_LEN + 1,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ id->uuid.b[0], id->uuid.b[1], id->uuid.b[2], id->uuid.b[3],
+ id->uuid.b[4], id->uuid.b[5], id->uuid.b[6], id->uuid.b[7],
+ id->uuid.b[8], id->uuid.b[9], id->uuid.b[10], id->uuid.b[11],
+ id->uuid.b[12], id->uuid.b[13], id->uuid.b[14], id->uuid.b[15]);
+}
+
+static int rproc_tee_probe(struct tee_client_device *tee_dev)
+{
+ struct device *dev = &tee_dev->dev;
+ struct tee_context *tee_ctx;
+ struct device_node *np;
+ char uuid_str[UUID_STRING_LEN + 1];
+ int ret;
+
+ uuid_to_str(&rproc_tee_id_table[0], uuid_str);
+ np = of_find_compatible_node(NULL, NULL, uuid_str);
+ if (!np) {
+ dev_err(dev, "Device node not found for UUID: %s\n", uuid_str);
+ return -ENODEV;
+ }
+
+ /* Open context with TEE driver */
+ tee_ctx = tee_client_open_context(NULL, rproc_tee_ctx_match, NULL, NULL);
+ if (IS_ERR(tee_ctx)) {
+ ret = PTR_ERR(tee_ctx);
+ goto put_node;
+ }
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ goto close_ctx;
+
+ INIT_LIST_HEAD(&rproc_tee_ctx.rproc_list);
+
+ ret = device_add_of_node(dev, np);
+
+ if (ret) {
+ mutex_unlock(&ctx_lock);
+ goto close_ctx;
+ }
+ rproc_tee_ctx.dev = dev;
+ rproc_tee_ctx.tee_ctx = tee_ctx;
+
+ mutex_unlock(&ctx_lock);
+ of_node_put(np);
+
+ return 0;
+
+close_ctx:
+ tee_client_close_context(tee_ctx);
+put_node:
+ of_node_put(np);
+ return ret;
+}
+
+static void rproc_tee_remove(struct tee_client_device *tee_dev)
+{
+ struct device *dev = &tee_dev->dev;
+ int ret;
+
+ ret = mutex_lock_interruptible(&ctx_lock);
+ if (ret)
+ return;
+
+ rproc_tee_ctx.dev = NULL;
+ mutex_unlock(&ctx_lock);
+ device_remove_of_node(dev);
+
+ tee_client_close_context(rproc_tee_ctx.tee_ctx);
+ rproc_tee_ctx.tee_ctx = NULL;
+}
+
+static struct tee_client_driver rproc_tee_fw_driver = {
+ .id_table = rproc_tee_id_table,
+ .probe = rproc_tee_probe,
+ .remove = rproc_tee_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ },
+};
+
+module_tee_client_driver(rproc_tee_fw_driver);
+
+MODULE_DESCRIPTION("remote processor TEE module");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/remoteproc_tee.h b/include/linux/remoteproc_tee.h
new file mode 100644
index 000000000000..23021d19c352
--- /dev/null
+++ b/include/linux/remoteproc_tee.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright(c) 2025 STMicroelectronics
+ */
+
+#ifndef REMOTEPROC_TEE_H
+#define REMOTEPROC_TEE_H
+
+#include <linux/tee_drv.h>
+#include <linux/firmware.h>
+#include <linux/remoteproc.h>
+
+#if IS_ENABLED(CONFIG_REMOTEPROC_TEE)
+
+int rproc_tee_register(struct device *dev, struct rproc **rproc,
+ const struct of_phandle_args *tee_phandle,
+ bool auto_boot);
+int rproc_tee_unregister(struct device *dev, struct rproc *rproc);
+int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw);
+int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw);
+void rproc_tee_release_fw(struct rproc *rproc);
+struct resource_table *rproc_tee_find_loaded_rsc_table(struct rproc *rproc,
+ const struct firmware *fw);
+int rproc_tee_start(struct rproc *rproc);
+int rproc_tee_stop(struct rproc *rproc);
+int rproc_tee_pa_to_da(struct rproc *rproc, phys_addr_t pa, size_t size, u64 *da);
+#else
+
+static inline int rproc_tee_register(struct device *dev, struct rproc **rproc,
+ const struct of_phandle_args *tee_phandle,
+ bool auto_boot)
+{
+ return -ENODEV;
+}
+
+static inline int rproc_tee_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline int rproc_tee_unregister(struct device *dev, struct rproc *rproc)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline int rproc_tee_load_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline int rproc_tee_start(struct rproc *rproc)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline int rproc_tee_stop(struct rproc *rproc)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return 0;
+}
+
+static inline void rproc_tee_release_fw(struct rproc *rproc)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+}
+
+static inline struct resource_table *
+rproc_tee_find_loaded_rsc_table(struct rproc *rproc, const struct firmware *fw)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return NULL;
+}
+#endif /* CONFIG_REMOTEPROC_TEE */
+#endif /* REMOTEPROC_TEE_H */
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH v21 6/6] remoteproc: stm32: Add TEE-controlled STM32 driver
2026-03-17 18:03 [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
` (4 preceding siblings ...)
2026-03-17 18:03 ` [PATCH v21 5/6] remoteproc: Add TEE support Arnaud Pouliquen
@ 2026-03-17 18:03 ` Arnaud Pouliquen
2026-03-19 8:07 ` [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Krzysztof Kozlowski
6 siblings, 0 replies; 13+ messages in thread
From: Arnaud Pouliquen @ 2026-03-17 18:03 UTC (permalink / raw)
To: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg
Cc: linux-stm32, linux-arm-kernel, linux-remoteproc, linux-kernel,
op-tee, devicetree, Arnaud Pouliquen
Add a remoteproc platform driver for the STM32MP15 Cortex-M4 core
controlled via a TEE Trusted Application.
The driver integrates with the generic TEE remoteproc layer
(rproc_tee_*) to delegate firmware authentication, loading and
start/stop operations to the TEE, while handling STM32-specific
platform resources on the Linux side:
- Translation between physical and device addresses using
SoC-specific DMA ranges.
- Registration of reserved-memory carveouts from "memory-region"
phandles (including vdev vrings and buffers).
- Mailbox-based virtio queue kicks and a shutdown channel using
the IPCC mailbox controller.
- Optional watchdog interrupt for crash reporting and wakeup.
This enables secure boot and runtime isolation of the M4 firmware
while still using the standard remoteproc and rpmsg frameworks
on STM32MP15.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
V21 updates:
- use of the rproc-tee-phandle property
---
drivers/remoteproc/Makefile | 2 +-
drivers/remoteproc/stm32_rproc_tee.c | 537 +++++++++++++++++++++++++++
2 files changed, 538 insertions(+), 1 deletion(-)
create mode 100644 drivers/remoteproc/stm32_rproc_tee.c
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index a1a5201982d4..80f0965bac95 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -36,7 +36,7 @@ qcom_wcnss_pil-y += qcom_wcnss_iris.o
obj-$(CONFIG_RCAR_REMOTEPROC) += rcar_rproc.o
obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o
obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o
-obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o
+obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o stm32_rproc_tee.o
obj-$(CONFIG_TI_K3_DSP_REMOTEPROC) += ti_k3_dsp_remoteproc.o ti_k3_common.o
obj-$(CONFIG_TI_K3_M4_REMOTEPROC) += ti_k3_m4_remoteproc.o ti_k3_common.o
obj-$(CONFIG_TI_K3_R5_REMOTEPROC) += ti_k3_r5_remoteproc.o ti_k3_common.o
diff --git a/drivers/remoteproc/stm32_rproc_tee.c b/drivers/remoteproc/stm32_rproc_tee.c
new file mode 100644
index 000000000000..7012f0a17a43
--- /dev/null
+++ b/drivers/remoteproc/stm32_rproc_tee.c
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025, STMicroelectronics - All Rights Reserved
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+
+#include "remoteproc_internal.h"
+
+#define MBOX_NB_VQ 2
+#define MBOX_NB_MBX 3
+
+#define STM32_MBX_VQ0 "vq0"
+#define STM32_MBX_VQ0_ID 0
+#define STM32_MBX_VQ1 "vq1"
+#define STM32_MBX_VQ1_ID 1
+#define STM32_MBX_SHUTDOWN "shutdown"
+
+struct stm32_rproc_tee_mem {
+ char name[20];
+ void __iomem *cpu_addr;
+ phys_addr_t phy_addr;
+ u32 dev_addr;
+ size_t size;
+};
+
+struct stm32_rproc_tee_dma_ranges {
+ u32 dev_addr;
+ u32 phy_addr;
+ u32 size;
+};
+
+struct stm32_mbox {
+ const unsigned char name[10];
+ struct mbox_chan *chan;
+ struct mbox_client client;
+ struct work_struct vq_work;
+ int vq_id;
+};
+
+struct stm32_rproc_tee {
+ int wdg_irq;
+ const struct stm32_rproc_tee_dma_ranges *ranges;
+ struct stm32_mbox mb[MBOX_NB_MBX];
+ struct workqueue_struct *workqueue;
+ struct of_phandle_args tee_phandle;
+};
+
+static const struct stm32_rproc_tee_dma_ranges stm32mp15_m4_dma_ranges[] = {
+ /* RETRAM address translation */
+ { .dev_addr = 0x0, .phy_addr = 0x38000000, .size = 0x10000 },
+ {/* sentinel */}
+};
+
+static int stm32_rproc_tee_pa_to_da(struct rproc *rproc, phys_addr_t pa,
+ size_t size, u64 *da)
+{
+ struct stm32_rproc_tee *ddata = rproc->priv;
+ const struct stm32_rproc_tee_dma_ranges *range;
+ struct device *dev = rproc->dev.parent;
+
+ for (range = ddata->ranges; range->phy_addr; range++) {
+ if (pa < range->phy_addr ||
+ pa >= range->phy_addr + range->size)
+ continue;
+ if (pa + size > range->phy_addr + range->size) {
+ dev_err(dev, "range too small for %pa+0x%zx\n", &pa, size);
+ return -EINVAL;
+ }
+ *da = pa - range->phy_addr + range->dev_addr;
+ dev_dbg(dev, "pa %pa to da %llx\n", &pa, *da);
+ return 0;
+ }
+
+ *da = pa;
+
+ return 0;
+}
+
+static int stm32_rproc_tee_mem_alloc(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ struct device *dev = rproc->dev.parent;
+ void *va;
+
+ dev_dbg(dev, "map memory: %pad+%zx\n", &mem->dma, mem->len);
+ va = (__force void *)ioremap_wc(mem->dma, mem->len);
+ if (IS_ERR_OR_NULL(va)) {
+ dev_err(dev, "Unable to map memory region: %pad+0x%zx\n",
+ &mem->dma, mem->len);
+ return -ENOMEM;
+ }
+
+ /* Update memory entry va */
+ mem->va = va;
+
+ return 0;
+}
+
+static int stm32_rproc_tee_mem_release(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ dev_dbg(rproc->dev.parent, "unmap memory: %pa\n", &mem->dma);
+ iounmap((__force __iomem void *)mem->va);
+
+ return 0;
+}
+
+static int stm32_rproc_tee_mbox_idx(struct rproc *rproc, const unsigned char *name)
+{
+ struct stm32_rproc_tee *ddata = rproc->priv;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
+ if (!strncmp(ddata->mb[i].name, name, strlen(name)))
+ return i;
+ }
+ dev_err(&rproc->dev, "mailbox %s not found\n", name);
+
+ return -EINVAL;
+}
+
+static void stm32_rproc_tee_request_shutdown(struct rproc *rproc)
+{
+ struct stm32_rproc_tee *ddata = rproc->priv;
+ int err, idx;
+
+ /* Request shutdown of the remote processor */
+ if (rproc->state != RPROC_OFFLINE && rproc->state != RPROC_CRASHED) {
+ idx = stm32_rproc_tee_mbox_idx(rproc, STM32_MBX_SHUTDOWN);
+ if (idx >= 0 && ddata->mb[idx].chan) {
+ err = mbox_send_message(ddata->mb[idx].chan, "detach");
+ if (err < 0)
+ dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n");
+ }
+ }
+}
+
+static int stm32_rproc_tee_stop(struct rproc *rproc)
+{
+ stm32_rproc_tee_request_shutdown(rproc);
+
+ return rproc_tee_stop(rproc);
+}
+
+static int stm32_rproc_tee_prepare(struct rproc *rproc)
+{
+ struct device *dev = rproc->dev.parent;
+ struct device_node *np = dev->of_node;
+ struct rproc_mem_entry *mem;
+ int index = 0, mr = 0, nph;
+ u64 da;
+
+ nph = of_reserved_mem_region_count(np);
+ if (nph <= 0)
+ return 0;
+
+ /* Register associated reserved memory regions */
+ for (index = 0; index < nph; index++) {
+ struct resource res;
+ int ret;
+
+ ret = of_reserved_mem_region_to_resource(np, mr++, &res);
+ if (ret)
+ return ret;
+
+ if (stm32_rproc_tee_pa_to_da(rproc, res.start,
+ resource_size(&res), &da) < 0) {
+ dev_err(dev, "memory region not valid %pR\n", &res);
+ return -EINVAL;
+ }
+
+ /* No need to map vdev buffer */
+ if (strstarts(res.name, "vdev0buffer")) {
+ /* Register reserved memory for vdev buffer alloc */
+ mem = rproc_of_resm_mem_entry_init(dev, index,
+ resource_size(&res),
+ res.start,
+ "vdev0buffer");
+ } else {
+ /* Register memory region */
+ mem = rproc_mem_entry_init(dev, NULL,
+ (dma_addr_t)res.start,
+ resource_size(&res), da,
+ stm32_rproc_tee_mem_alloc,
+ stm32_rproc_tee_mem_release,
+ "%.*s",
+ (int)(strchrnul(res.name, '@') - res.name),
+ res.name);
+ if (mem)
+ rproc_coredump_add_segment(rproc, da,
+ resource_size(&res));
+ }
+
+ if (!mem)
+ return -ENOMEM;
+
+ rproc_add_carveout(rproc, mem);
+ }
+
+ return 0;
+}
+
+static irqreturn_t stm32_rproc_tee_wdg(int irq, void *data)
+{
+ struct platform_device *pdev = data;
+ struct rproc *rproc = platform_get_drvdata(pdev);
+
+ rproc_report_crash(rproc, RPROC_WATCHDOG);
+
+ return IRQ_HANDLED;
+}
+
+static void stm32_rproc_tee_mb_vq_work(struct work_struct *work)
+{
+ struct stm32_mbox *mb = container_of(work, struct stm32_mbox, vq_work);
+ struct rproc *rproc = dev_get_drvdata(mb->client.dev);
+
+ mutex_lock(&rproc->lock);
+
+ if (rproc->state != RPROC_RUNNING && rproc->state != RPROC_ATTACHED)
+ goto unlock_mutex;
+
+ if (rproc_vq_interrupt(rproc, mb->vq_id) == IRQ_NONE)
+ dev_dbg(&rproc->dev, "no message found in vq%d\n", mb->vq_id);
+
+unlock_mutex:
+ mutex_unlock(&rproc->lock);
+}
+
+static void stm32_rproc_tee_mb_callback(struct mbox_client *cl, void *data)
+{
+ struct rproc *rproc = dev_get_drvdata(cl->dev);
+ struct stm32_mbox *mb = container_of(cl, struct stm32_mbox, client);
+ struct stm32_rproc_tee *ddata = rproc->priv;
+
+ queue_work(ddata->workqueue, &mb->vq_work);
+}
+
+static void stm32_rproc_tee_free_mbox(struct rproc *rproc)
+{
+ struct stm32_rproc_tee *ddata = rproc->priv;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ddata->mb); i++) {
+ if (ddata->mb[i].chan)
+ mbox_free_channel(ddata->mb[i].chan);
+ ddata->mb[i].chan = NULL;
+ }
+}
+
+static const struct stm32_mbox stm32_rproc_tee_mbox[MBOX_NB_MBX] = {
+ {
+ .name = STM32_MBX_VQ0,
+ .vq_id = STM32_MBX_VQ0_ID,
+ .client = {
+ .rx_callback = stm32_rproc_tee_mb_callback,
+ .tx_block = false,
+ },
+ },
+ {
+ .name = STM32_MBX_VQ1,
+ .vq_id = STM32_MBX_VQ1_ID,
+ .client = {
+ .rx_callback = stm32_rproc_tee_mb_callback,
+ .tx_block = false,
+ },
+ },
+ {
+ .name = STM32_MBX_SHUTDOWN,
+ .vq_id = -1,
+ .client = {
+ .tx_block = true,
+ .tx_done = NULL,
+ .tx_tout = 500, /* 500 ms time out */
+ },
+ },
+};
+
+static int stm32_rproc_tee_request_mbox(struct rproc *rproc)
+{
+ struct stm32_rproc_tee *ddata = rproc->priv;
+ struct device *dev = &rproc->dev;
+ unsigned int i;
+ int j;
+ const unsigned char *name;
+ struct mbox_client *cl;
+
+ /* Initialise mailbox structure table */
+ memcpy(ddata->mb, stm32_rproc_tee_mbox, sizeof(stm32_rproc_tee_mbox));
+
+ for (i = 0; i < MBOX_NB_MBX; i++) {
+ name = ddata->mb[i].name;
+
+ cl = &ddata->mb[i].client;
+ cl->dev = dev->parent;
+
+ ddata->mb[i].chan = mbox_request_channel_byname(cl, name);
+ if (IS_ERR(ddata->mb[i].chan)) {
+ if (PTR_ERR(ddata->mb[i].chan) == -EPROBE_DEFER) {
+ dev_err_probe(dev->parent,
+ PTR_ERR(ddata->mb[i].chan),
+ "failed to request mailbox %s\n",
+ name);
+ goto err_probe;
+ }
+ dev_info(dev, "mailbox %s mbox not used\n", name);
+ ddata->mb[i].chan = NULL;
+ }
+ if (ddata->mb[i].vq_id >= 0) {
+ INIT_WORK(&ddata->mb[i].vq_work,
+ stm32_rproc_tee_mb_vq_work);
+ }
+ }
+
+ return 0;
+
+err_probe:
+ for (j = i - 1; j >= 0; j--)
+ if (ddata->mb[j].chan) {
+ mbox_free_channel(ddata->mb[j].chan);
+ ddata->mb[j].chan = NULL;
+ }
+ return -EPROBE_DEFER;
+}
+
+static void stm32_rproc_tee_kick(struct rproc *rproc, int vqid)
+{
+ struct stm32_rproc_tee *ddata = rproc->priv;
+ unsigned int i;
+ int err;
+
+ if (WARN_ON(vqid >= MBOX_NB_VQ))
+ return;
+
+ for (i = 0; i < MBOX_NB_MBX; i++) {
+ if (vqid != ddata->mb[i].vq_id)
+ continue;
+ if (!ddata->mb[i].chan)
+ return;
+ err = mbox_send_message(ddata->mb[i].chan, "kick");
+ if (err < 0)
+ dev_err(&rproc->dev, "%s: failed (%s, err:%d)\n",
+ __func__, ddata->mb[i].name, err);
+ return;
+ }
+}
+
+static int stm32_rproc_tee_parse_dt(struct platform_device *pdev,
+ struct stm32_rproc_tee *ddata,
+ bool *auto_boot)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ int err, irq;
+
+ /*
+ * remoteproc-backend = <&sproc N>;
+ * args.np : backend node
+ * args.args[0] : remote processor identifier used by TEE
+ */
+ err = of_parse_phandle_with_fixed_args(np, "rproc-tee-phandle",
+ 1, 0, &ddata->tee_phandle);
+ if (err) {
+ dev_err_probe(dev, err,
+ "failed to parse remoteproc-backend (%d)\n", err);
+ return err;
+ }
+
+ of_node_put(ddata->tee_phandle.np);
+
+ irq = platform_get_irq_optional(pdev, 0);
+ if (irq == -EPROBE_DEFER)
+ return irq;
+
+ if (irq > 0) {
+ err = devm_request_irq(dev, irq, stm32_rproc_tee_wdg, 0,
+ dev_name(dev), pdev);
+ if (err)
+ return dev_err_probe(dev, err,
+ "failed to request wdg irq\n");
+
+ ddata->wdg_irq = irq;
+
+ if (of_property_read_bool(np, "wakeup-source")) {
+ device_init_wakeup(dev, true);
+ dev_pm_set_wake_irq(dev, irq);
+ }
+
+ dev_info(dev, "wdg irq registered\n");
+ }
+
+ *auto_boot = of_property_read_bool(np, "st,auto-boot");
+
+ return 0;
+}
+
+static int stm32_rproc_tee_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct stm32_rproc_tee *ddata;
+ struct rproc *rproc;
+ bool auto_boot;
+ int ret;
+
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ ret = stm32_rproc_tee_parse_dt(pdev, ddata, &auto_boot);
+ if (ret)
+ return ret;
+
+ ret = rproc_tee_register(dev, &rproc, &ddata->tee_phandle, auto_boot);
+ if (ret)
+ return dev_err_probe(dev, ret, "signed firmware not supported by TEE\n");
+
+ rproc->ops->prepare = stm32_rproc_tee_prepare;
+ rproc->ops->stop = stm32_rproc_tee_stop;
+ rproc->ops->kick = stm32_rproc_tee_kick;
+
+ ddata = rproc->priv;
+
+ ddata->ranges = device_get_match_data(&pdev->dev);
+
+ rproc->has_iommu = false;
+ ddata->workqueue = create_workqueue(dev_name(dev));
+ if (!ddata->workqueue) {
+ dev_err(dev, "cannot create workqueue\n");
+ ret = -ENOMEM;
+ goto free_resources;
+ }
+
+ platform_set_drvdata(pdev, rproc);
+
+ ret = stm32_rproc_tee_request_mbox(rproc);
+ if (ret)
+ goto free_wkq;
+
+ return 0;
+
+free_wkq:
+ destroy_workqueue(ddata->workqueue);
+free_resources:
+ rproc_resource_cleanup(rproc);
+ if (device_may_wakeup(dev)) {
+ dev_pm_clear_wake_irq(dev);
+ device_init_wakeup(dev, false);
+ }
+ rproc_tee_unregister(dev, rproc);
+
+ return ret;
+}
+
+static void stm32_rproc_tee_remove(struct platform_device *pdev)
+{
+ struct rproc *rproc = platform_get_drvdata(pdev);
+ struct stm32_rproc_tee *ddata = rproc->priv;
+ struct device *dev = &pdev->dev;
+
+ stm32_rproc_tee_free_mbox(rproc);
+ destroy_workqueue(ddata->workqueue);
+
+ if (device_may_wakeup(dev)) {
+ dev_pm_clear_wake_irq(dev);
+ device_init_wakeup(dev, false);
+ }
+
+ rproc_tee_unregister(dev, rproc);
+}
+
+static int stm32_rproc_tee_suspend(struct device *dev)
+{
+ struct rproc *rproc = dev_get_drvdata(dev);
+ struct stm32_rproc_tee *ddata = rproc->priv;
+
+ if (device_may_wakeup(dev))
+ return enable_irq_wake(ddata->wdg_irq);
+
+ return 0;
+}
+
+static int stm32_rproc_tee_resume(struct device *dev)
+{
+ struct rproc *rproc = dev_get_drvdata(dev);
+ struct stm32_rproc_tee *ddata = rproc->priv;
+
+ if (device_may_wakeup(dev))
+ return disable_irq_wake(ddata->wdg_irq);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(stm32_rproc_tee_pm_ops,
+ stm32_rproc_tee_suspend, stm32_rproc_tee_resume);
+
+static const struct of_device_id stm32_rproc_tee_match[] = {
+ {
+ .compatible = "st,stm32mp1-m4-tee",
+ .data = &stm32mp15_m4_dma_ranges,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_rproc_tee_match);
+
+static struct platform_driver stm32_rproc_tee_driver = {
+ .probe = stm32_rproc_tee_probe,
+ .remove = stm32_rproc_tee_remove,
+ .driver = {
+ .name = "stm32-rproc-tee",
+ .pm = pm_ptr(&stm32_rproc_tee_pm_ops),
+ .of_match_table = stm32_rproc_tee_match,
+ },
+};
+module_platform_driver(stm32_rproc_tee_driver);
+
+MODULE_DESCRIPTION("STM32 Remote Processor TEE Control Driver");
+MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>");
+MODULE_LICENSE("GPL");
+
--
2.43.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding
2026-03-17 18:03 ` [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding Arnaud Pouliquen
@ 2026-03-19 8:06 ` Krzysztof Kozlowski
2026-03-19 10:31 ` Arnaud POULIQUEN
2026-03-19 8:06 ` Krzysztof Kozlowski
1 sibling, 1 reply; 13+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-19 8:06 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg, linux-stm32,
linux-arm-kernel, linux-remoteproc, linux-kernel, op-tee,
devicetree
On Tue, Mar 17, 2026 at 07:03:23PM +0100, Arnaud Pouliquen wrote:
> Add a Device Tree binding for the STM32 remote processor controlled
> via a Trusted Application running in OP-TEE.
> This binding describes the interface and properties required for STM32MP
> remoteproc instances managed by the TEE rproc service, including a
> linkage to the TEE backend through the property "rproc-tee-phandle".
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
> V21 updates:
> - the m4 node is no more declared as a child of the optee-rproc node
> - "rproc-tee-phandle" property is introduced to reference the optee-rproc
> ---
> .../remoteproc/st,stm32-rproc-tee.yaml | 108 ++++++++++++++++++
> 1 file changed, 108 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>
> diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
> new file mode 100644
> index 000000000000..ca4dd1c8e7b0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
> @@ -0,0 +1,108 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/remoteproc/st,stm32-rproc-tee.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: STMicroelectronics STM32 remote processor controlled via TEE
> +
> +maintainers:
> + - Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> +
> +description: |
> + STM32MP remote processor controlled by a Trusted Application
> + running in OP-TEE. This node is a child of the TEE remoteproc service
> + (UUID 80a4c275-0a47-4905-8285-1486a9771a08) and exposes a remoteproc
> + instance managed by the Linux remoteproc core via the TEE rproc service.
> +
> + Firmware loading, authentication and remote processor start/stop are managed
> + by the TEE application. The STM32-specific driver handles platform resources
> + such as the mailboxes and reserved-memory.
> +
> +properties:
> + compatible:
> + const: st,stm32mp1-m4-tee
Drop "tee", it suggests that compatible is tied to implementation of FW
you put there.
> +
> + reg:
> + description: |
Do not need '|' unless you need to preserve formatting.
> + Remote processor identifier used by the TEE service. The <0> value
> + in the example denotes a single instance with ID 0.
> + maxItems: 1
> +
> + mboxes:
> + description: |
> + Mailbox channels used for rpmsg/virtio functionality and processor
> + shutdown.
> + maxItems: 3
> +
> + mbox-names:
> + items:
> + - const: vq0
> + - const: vq1
> + - const: shutdown
> +
> + memory-region:
> + description: |
> + List of phandles to reserved-memory nodes describing the memory layout
> + for the interprocessors communication.
Drop description. You miss maxItems, though.
> +
> + interrupts:
> + description: |
Same comments...
> + Optional watchdog / status interrupt line used to detect crashes
> + and optionally wake up the system.
> + maxItems: 1
> +
> + st,auto-boot:
> + type: boolean
> + description: |
> + If present, the remote processor will be automatically started by
> + the remoteproc core at boot.
That's policy, not DT property.
> +
> + wakeup-source:
> + type: boolean
> + description: |
> + Indicates that the watchdog interrupt can be used as a wakeup source.
> +
> + rproc-tee-phandle:
Missing vendor prefix, drop phandle. You do not say that "st,auto-boot"
is "st,auto-boot-boolean"
> + description: |
> + Phandle to the remote processor backend node and its identifier. This property
> + is used to link the TEE remoteproc service to the remote processor instance
> + it controls. The value is a phandle reference to the remote processor node,
> + followed by a cell specifying the remote processor identifier used by the TEE.
> + $ref: /schemas/types.yaml#/definitions/phandle-array
Missing constraints.
I also do not understand which bus node this is being child, if not
remote proc.
> +
> +required:
> + - compatible
> + - reg
> + - rproc-tee-phandle
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + firmware {
> + tee_rproc: optee-rproc {
> + compatible = "80a4c275-0a47-4905-8285-1486a9771a08";
> + };
> + };
Drop
> +
> + m4: m4@0 {
Drop unused label.
Node names should be generic. See also an explanation and list of
examples (not exhaustive) in DT specification:
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
If you cannot find a name matching your device, please check in kernel
sources for similar cases or you can grow the spec (via pull request to
DT spec repo).
e.g. mcu, because m4 feels like given model (Cortex M4?).
> + compatible = "st,stm32mp1-m4-tee";
> + reg = <0 0>;
> +
> + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
> + mbox-names = "vq0", "vq1", "shutdown";
> +
> + memory-region = <&vdev0vring0>, <&m_ipc_shm>, <&mcuram2>,
> + <&vdev0vring1>, <&vdev0buffer>, <&retram>;
> +
> + interrupt-parent = <&exti>;
> + interrupts = <68 1>;
> +
> + rproc-tee-phandle = <&tee_rproc 0>;
> + st,auto-boot;
> + wakeup-source;
> +
> + status = "okay";
Drop
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding
2026-03-17 18:03 ` [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding Arnaud Pouliquen
2026-03-19 8:06 ` Krzysztof Kozlowski
@ 2026-03-19 8:06 ` Krzysztof Kozlowski
1 sibling, 0 replies; 13+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-19 8:06 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg, linux-stm32,
linux-arm-kernel, linux-remoteproc, linux-kernel, op-tee,
devicetree
On Tue, Mar 17, 2026 at 07:03:23PM +0100, Arnaud Pouliquen wrote:
> Add a Device Tree binding for the STM32 remote processor controlled
> via a Trusted Application running in OP-TEE.
> This binding describes the interface and properties required for STM32MP
> remoteproc instances managed by the TEE rproc service, including a
> linkage to the TEE backend through the property "rproc-tee-phandle".
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
> ---
Heh, and standard comment...
A nit, subject: drop second/last, redundant "binding". The
"dt-bindings" prefix is already stating that these are bindings.
See also:
https://elixir.bootlin.com/linux/v6.17-rc3/source/Documentation/devicetree/bindings/submitting-patches.rst#L18
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware
2026-03-17 18:03 [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
` (5 preceding siblings ...)
2026-03-17 18:03 ` [PATCH v21 6/6] remoteproc: stm32: Add TEE-controlled STM32 driver Arnaud Pouliquen
@ 2026-03-19 8:07 ` Krzysztof Kozlowski
6 siblings, 0 replies; 13+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-19 8:07 UTC (permalink / raw)
To: Arnaud Pouliquen
Cc: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg, linux-stm32,
linux-arm-kernel, linux-remoteproc, linux-kernel, op-tee,
devicetree
On Tue, Mar 17, 2026 at 07:03:21PM +0100, Arnaud Pouliquen wrote:
>
> Main updates from version V20[4]:
> --------------------------------
> To address Rob’s concern on v20concerning resource declaration under the
> tee node, the device tree is now structured as follows,replacing the
> child-parent hierarchy with a phandle:
>
> firmware {
> tee_rproc: optee-rproc {
> compatible = "80a4c275-0a47-4905-8285-1486a9771a08";
> };
> };
>
And what is the parent here?
> m4: m4@0 {
What sort of bus do you have here (IOW, what does this 0 mean?)
> compatible = "st,stm32mp1-m4-tee";
> reg = <0 0>;
>
> mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
> mbox-names = "vq0", "vq1", "shutdown";
>
> memory-region = <&vdev0vring0>, <&m_ipc_shm>, <&mcuram2>,
> <&vdev0vring1>, <&vdev0buffer>, <&retram>;
>
> interrupt-parent = <&exti>;
> interrupts = <68 1>;
>
> rproc-tee-phandle = <&tee_rproc 0>;
> st,auto-boot;
> wakeup-source;
>
> status = "okay";
> };
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding
2026-03-19 8:06 ` Krzysztof Kozlowski
@ 2026-03-19 10:31 ` Arnaud POULIQUEN
2026-03-19 10:41 ` Krzysztof Kozlowski
0 siblings, 1 reply; 13+ messages in thread
From: Arnaud POULIQUEN @ 2026-03-19 10:31 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg, linux-stm32,
linux-arm-kernel, linux-remoteproc, linux-kernel, op-tee,
devicetree
Hello Krzysztof,
On 3/19/26 09:06, Krzysztof Kozlowski wrote:
> On Tue, Mar 17, 2026 at 07:03:23PM +0100, Arnaud Pouliquen wrote:
>> Add a Device Tree binding for the STM32 remote processor controlled
>> via a Trusted Application running in OP-TEE.
>> This binding describes the interface and properties required for STM32MP
>> remoteproc instances managed by the TEE rproc service, including a
>> linkage to the TEE backend through the property "rproc-tee-phandle".
>>
>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>> ---
>> V21 updates:
>> - the m4 node is no more declared as a child of the optee-rproc node
>> - "rproc-tee-phandle" property is introduced to reference the optee-rproc
>> ---
>> .../remoteproc/st,stm32-rproc-tee.yaml | 108 ++++++++++++++++++
>> 1 file changed, 108 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>> new file mode 100644
>> index 000000000000..ca4dd1c8e7b0
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>> @@ -0,0 +1,108 @@
>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/remoteproc/st,stm32-rproc-tee.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: STMicroelectronics STM32 remote processor controlled via TEE
>> +
>> +maintainers:
>> + - Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>> +
>> +description: |
>> + STM32MP remote processor controlled by a Trusted Application
>> + running in OP-TEE. This node is a child of the TEE remoteproc service
>> + (UUID 80a4c275-0a47-4905-8285-1486a9771a08) and exposes a remoteproc
>> + instance managed by the Linux remoteproc core via the TEE rproc service.
>> +
>> + Firmware loading, authentication and remote processor start/stop are managed
>> + by the TEE application. The STM32-specific driver handles platform resources
>> + such as the mailboxes and reserved-memory.
>> +
>> +properties:
>> + compatible:
>> + const: st,stm32mp1-m4-tee
>
> Drop "tee", it suggests that compatible is tied to implementation of FW
> you put there.
The "st,stm32mp1-m4" compatible string already exists in
drivers/remoteproc/stm32_rproc.c, and "st,stm32mp1-m4-tee" compatible is
upstreamed in OP-TEE.
Notice that I have also the stm32mp2 SoC to upstream expecting to have
similar compatible:
- st,stm32mp1-m33
- st,stm32mp2-m33-tee
Depending on the compatible string, the hardware behavior changes.
With the "xxxx-tee" compatible, OP-TEE also manages the isolation of
remote processor resources (memory, clock reset, peripherals).
Without the "xxxx-tee" compatible, OP-TEE have to ensure that the Linux
has the good access right to manage the remote processor.
For instance if st,stm32mp1-m4-tee is set instead of st,stm32mp1-m4, on
linux side
- only memory regions used for IPC should be declared
- memory regions containing the remote firmware must not be declared as
not accessible by the Linux ( managed by OP-TEE).
- resets must not be declared ( managed by OP-TEE)
You probably don't remember, as it was a long time ago, but we already
discussed this point with Rob[1].
[1] https://lkml.org/lkml/2024/1/18/100
Do it still reasonable to you and Rob or should we find an alternative?
Thanks and Regards,
Arnaud
>
>> +
>> + reg:
>> + description: |
>
> Do not need '|' unless you need to preserve formatting.
>
>> + Remote processor identifier used by the TEE service. The <0> value
>> + in the example denotes a single instance with ID 0.
>> + maxItems: 1
>> +
>> + mboxes:
>> + description: |
>> + Mailbox channels used for rpmsg/virtio functionality and processor
>> + shutdown.
>> + maxItems: 3
>> +
>> + mbox-names:
>> + items:
>> + - const: vq0
>> + - const: vq1
>> + - const: shutdown
>> +
>> + memory-region:
>> + description: |
>> + List of phandles to reserved-memory nodes describing the memory layout
>> + for the interprocessors communication.
>
> Drop description. You miss maxItems, though.
>
>> +
>> + interrupts:
>> + description: |
>
> Same comments...
>
>> + Optional watchdog / status interrupt line used to detect crashes
>> + and optionally wake up the system.
>> + maxItems: 1
>> +
>> + st,auto-boot:
>> + type: boolean
>> + description: |
>> + If present, the remote processor will be automatically started by
>> + the remoteproc core at boot.
>
> That's policy, not DT property.
>
>> +
>> + wakeup-source:
>> + type: boolean
>> + description: |
>> + Indicates that the watchdog interrupt can be used as a wakeup source.
>> +
>> + rproc-tee-phandle:
>
> Missing vendor prefix, drop phandle. You do not say that "st,auto-boot"
> is "st,auto-boot-boolean"
>
>> + description: |
>> + Phandle to the remote processor backend node and its identifier. This property
>> + is used to link the TEE remoteproc service to the remote processor instance
>> + it controls. The value is a phandle reference to the remote processor node,
>> + followed by a cell specifying the remote processor identifier used by the TEE.
>> + $ref: /schemas/types.yaml#/definitions/phandle-array
>
> Missing constraints.
>
> I also do not understand which bus node this is being child, if not
> remote proc.
>
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - rproc-tee-phandle
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + firmware {
>> + tee_rproc: optee-rproc {
>> + compatible = "80a4c275-0a47-4905-8285-1486a9771a08";
>> + };
>> + };
>
> Drop
>
>> +
>> + m4: m4@0 {
>
> Drop unused label.
>
> Node names should be generic. See also an explanation and list of
> examples (not exhaustive) in DT specification:
> https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
> If you cannot find a name matching your device, please check in kernel
> sources for similar cases or you can grow the spec (via pull request to
> DT spec repo).
>
> e.g. mcu, because m4 feels like given model (Cortex M4?).
>
>> + compatible = "st,stm32mp1-m4-tee";
>> + reg = <0 0>;
>> +
>> + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;
>> + mbox-names = "vq0", "vq1", "shutdown";
>> +
>> + memory-region = <&vdev0vring0>, <&m_ipc_shm>, <&mcuram2>,
>> + <&vdev0vring1>, <&vdev0buffer>, <&retram>;
>> +
>> + interrupt-parent = <&exti>;
>> + interrupts = <68 1>;
>> +
>> + rproc-tee-phandle = <&tee_rproc 0>;
>> + st,auto-boot;
>> + wakeup-source;
>> +
>> + status = "okay";
>
> Drop
>
> Best regards,
> Krzysztof
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding
2026-03-19 10:31 ` Arnaud POULIQUEN
@ 2026-03-19 10:41 ` Krzysztof Kozlowski
2026-03-20 9:58 ` Arnaud POULIQUEN
0 siblings, 1 reply; 13+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-19 10:41 UTC (permalink / raw)
To: Arnaud POULIQUEN
Cc: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg, linux-stm32,
linux-arm-kernel, linux-remoteproc, linux-kernel, op-tee,
devicetree
On 19/03/2026 11:31, Arnaud POULIQUEN wrote:
> Hello Krzysztof,
>
>
> On 3/19/26 09:06, Krzysztof Kozlowski wrote:
>> On Tue, Mar 17, 2026 at 07:03:23PM +0100, Arnaud Pouliquen wrote:
>>> Add a Device Tree binding for the STM32 remote processor controlled
>>> via a Trusted Application running in OP-TEE.
>>> This binding describes the interface and properties required for STM32MP
>>> remoteproc instances managed by the TEE rproc service, including a
>>> linkage to the TEE backend through the property "rproc-tee-phandle".
>>>
>>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>>> ---
>>> V21 updates:
>>> - the m4 node is no more declared as a child of the optee-rproc node
>>> - "rproc-tee-phandle" property is introduced to reference the optee-rproc
>>> ---
>>> .../remoteproc/st,stm32-rproc-tee.yaml | 108 ++++++++++++++++++
>>> 1 file changed, 108 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>>>
>>> diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>>> new file mode 100644
>>> index 000000000000..ca4dd1c8e7b0
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>>> @@ -0,0 +1,108 @@
>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>> +%YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/remoteproc/st,stm32-rproc-tee.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: STMicroelectronics STM32 remote processor controlled via TEE
>>> +
>>> +maintainers:
>>> + - Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>>> +
>>> +description: |
>>> + STM32MP remote processor controlled by a Trusted Application
>>> + running in OP-TEE. This node is a child of the TEE remoteproc service
>>> + (UUID 80a4c275-0a47-4905-8285-1486a9771a08) and exposes a remoteproc
>>> + instance managed by the Linux remoteproc core via the TEE rproc service.
>>> +
>>> + Firmware loading, authentication and remote processor start/stop are managed
>>> + by the TEE application. The STM32-specific driver handles platform resources
>>> + such as the mailboxes and reserved-memory.
>>> +
>>> +properties:
>>> + compatible:
>>> + const: st,stm32mp1-m4-tee
>>
>> Drop "tee", it suggests that compatible is tied to implementation of FW
>> you put there.
>
> The "st,stm32mp1-m4" compatible string already exists in
Then probably this binding needs changes, because in general you should
not have two compatibles for the same hardware. Maybe that's special
case, but then needs explanations in commit msg why is that.
> drivers/remoteproc/stm32_rproc.c, and "st,stm32mp1-m4-tee" compatible is
> upstreamed in OP-TEE.
That is not our problem and strong no-go. Other projects are supposed to
participate in upstream bindings review and take the bindings once they
are reviewed and accepted here. If they take without review, it's their
problem.
Imagine that: some whatever project takes whatever crap (not saying
Optee is like that, just imagine for sake of discussion) and then you
send bindings to upstream and claim "that project took it, so you must
do as well". Great loophole to squeeze poor stuff to the kernel, so any
such argument is for me a warning sign.
>
> Notice that I have also the stm32mp2 SoC to upstream expecting to have
> similar compatible:
> - st,stm32mp1-m33
> - st,stm32mp2-m33-tee
>
> Depending on the compatible string, the hardware behavior changes.
> With the "xxxx-tee" compatible, OP-TEE also manages the isolation of
> remote processor resources (memory, clock reset, peripherals).
> Without the "xxxx-tee" compatible, OP-TEE have to ensure that the Linux
> has the good access right to manage the remote processor.
Still the same device, no?
You can have a property defining how Linux should access such device,
e.g. because FW does this and that.
>
> For instance if st,stm32mp1-m4-tee is set instead of st,stm32mp1-m4, on
> linux side
> - only memory regions used for IPC should be declared
> - memory regions containing the remote firmware must not be declared as
> not accessible by the Linux ( managed by OP-TEE).
> - resets must not be declared ( managed by OP-TEE)
>
> You probably don't remember, as it was a long time ago, but we already
> discussed this point with Rob[1].
> [1] https://lkml.org/lkml/2024/1/18/100
>
> Do it still reasonable to you and Rob or should we find an alternative?
Get ack from Rob then.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding
2026-03-19 10:41 ` Krzysztof Kozlowski
@ 2026-03-20 9:58 ` Arnaud POULIQUEN
0 siblings, 0 replies; 13+ messages in thread
From: Arnaud POULIQUEN @ 2026-03-20 9:58 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Bjorn Andersson, Mathieu Poirier, Jens Wiklander, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sumit Garg, linux-stm32,
linux-arm-kernel, linux-remoteproc, linux-kernel, op-tee,
devicetree
On 3/19/26 11:41, Krzysztof Kozlowski wrote:
> On 19/03/2026 11:31, Arnaud POULIQUEN wrote:
>> Hello Krzysztof,
>>
>>
>> On 3/19/26 09:06, Krzysztof Kozlowski wrote:
>>> On Tue, Mar 17, 2026 at 07:03:23PM +0100, Arnaud Pouliquen wrote:
>>>> Add a Device Tree binding for the STM32 remote processor controlled
>>>> via a Trusted Application running in OP-TEE.
>>>> This binding describes the interface and properties required for STM32MP
>>>> remoteproc instances managed by the TEE rproc service, including a
>>>> linkage to the TEE backend through the property "rproc-tee-phandle".
>>>>
>>>> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>>>> ---
>>>> V21 updates:
>>>> - the m4 node is no more declared as a child of the optee-rproc node
>>>> - "rproc-tee-phandle" property is introduced to reference the optee-rproc
>>>> ---
>>>> .../remoteproc/st,stm32-rproc-tee.yaml | 108 ++++++++++++++++++
>>>> 1 file changed, 108 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>>>> new file mode 100644
>>>> index 000000000000..ca4dd1c8e7b0
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc-tee.yaml
>>>> @@ -0,0 +1,108 @@
>>>> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
>>>> +%YAML 1.2
>>>> +---
>>>> +$id: http://devicetree.org/schemas/remoteproc/st,stm32-rproc-tee.yaml#
>>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>>> +
>>>> +title: STMicroelectronics STM32 remote processor controlled via TEE
>>>> +
>>>> +maintainers:
>>>> + - Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
>>>> +
>>>> +description: |
>>>> + STM32MP remote processor controlled by a Trusted Application
>>>> + running in OP-TEE. This node is a child of the TEE remoteproc service
>>>> + (UUID 80a4c275-0a47-4905-8285-1486a9771a08) and exposes a remoteproc
>>>> + instance managed by the Linux remoteproc core via the TEE rproc service.
>>>> +
>>>> + Firmware loading, authentication and remote processor start/stop are managed
>>>> + by the TEE application. The STM32-specific driver handles platform resources
>>>> + such as the mailboxes and reserved-memory.
>>>> +
>>>> +properties:
>>>> + compatible:
>>>> + const: st,stm32mp1-m4-tee
>>>
>>> Drop "tee", it suggests that compatible is tied to implementation of FW
>>> you put there.
>>
>> The "st,stm32mp1-m4" compatible string already exists in
>
> Then probably this binding needs changes, because in general you should
> not have two compatibles for the same hardware. Maybe that's special
> case, but then needs explanations in commit msg why is that.
>
>> drivers/remoteproc/stm32_rproc.c, and "st,stm32mp1-m4-tee" compatible is
>> upstreamed in OP-TEE.
>
> That is not our problem and strong no-go. Other projects are supposed to
> participate in upstream bindings review and take the bindings once they
> are reviewed and accepted here. If they take without review, it's their
> problem.
>
> Imagine that: some whatever project takes whatever crap (not saying
> Optee is like that, just imagine for sake of discussion) and then you
> send bindings to upstream and claim "that project took it, so you must
> do as well". Great loophole to squeeze poor stuff to the kernel, so any
> such argument is for me a warning sign.
>
>
>>
>> Notice that I have also the stm32mp2 SoC to upstream expecting to have
>> similar compatible:
>> - st,stm32mp1-m33
>> - st,stm32mp2-m33-tee
>>
>> Depending on the compatible string, the hardware behavior changes.
>> With the "xxxx-tee" compatible, OP-TEE also manages the isolation of
>> remote processor resources (memory, clock reset, peripherals).
>> Without the "xxxx-tee" compatible, OP-TEE have to ensure that the Linux
>> has the good access right to manage the remote processor.
>
> Still the same device, no?
>
> You can have a property defining how Linux should access such device,
> e.g. because FW does this and that.
>
>>
>> For instance if st,stm32mp1-m4-tee is set instead of st,stm32mp1-m4, on
>> linux side
>> - only memory regions used for IPC should be declared
>> - memory regions containing the remote firmware must not be declared as
>> not accessible by the Linux ( managed by OP-TEE).
>> - resets must not be declared ( managed by OP-TEE)
>>
>> You probably don't remember, as it was a long time ago, but we already
>> discussed this point with Rob[1].
>> [1] https://lkml.org/lkml/2024/1/18/100
>>
>> Do it still reasonable to you and Rob or should we find an alternative?
>
> Get ack from Rob then.
A previous acknowledgment from Rob was given here:
https://lkml.org/lkml/2024/2/22/1264.
What frustrates me is that, if the compatible usage is no longer
accepted, I have lost time basing all my other versions on this
assumption. But that’s part of the game, and this series is already a
concatenation of redesigns resulting in version V21.
My expectation is simply that you and Rob provide me with a clear
direction to move forward.
The compatible string is one topic; I also need an acknowledgment or
rejection of the concept of using a phandle to link the remoteproc
driver with the TEE service.
Thanks and regards,
Arnaud
>
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-03-20 9:59 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-17 18:03 [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 1/6] dt-bindings: firmware: Add TEE remoteproc service binding Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 2/6] dt-bindings: remoteproc: Add STM32 TEE-controlled rproc binding Arnaud Pouliquen
2026-03-19 8:06 ` Krzysztof Kozlowski
2026-03-19 10:31 ` Arnaud POULIQUEN
2026-03-19 10:41 ` Krzysztof Kozlowski
2026-03-20 9:58 ` Arnaud POULIQUEN
2026-03-19 8:06 ` Krzysztof Kozlowski
2026-03-17 18:03 ` [PATCH v21 3/6] remoteproc: core: Introduce rproc_pa_to_va helper Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 4/6] remoteproc: Introduce optional release_fw operation Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 5/6] remoteproc: Add TEE support Arnaud Pouliquen
2026-03-17 18:03 ` [PATCH v21 6/6] remoteproc: stm32: Add TEE-controlled STM32 driver Arnaud Pouliquen
2026-03-19 8:07 ` [PATCH v21 0/6] Introduction of a remoteproc tee to load signed firmware Krzysztof Kozlowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox