* [PATCH v2 1/7] dt-bindings: spi: qcom,spi-qcom-qspi: Add qcom,qcs615-qspi compatible
From: Viken Dadhaniya @ 2026-04-14 17:08 UTC (permalink / raw)
To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-spi, devicetree, linux-kernel,
Viken Dadhaniya
In-Reply-To: <20260414-spi-nor-v2-0-bcca40de4b5f@oss.qualcomm.com>
Add support for the QSPI controller on QCS615 SoC.
Move allOf section after required properties and add if:then constraint
to require minimum 2 interconnects for qcs615 variant.
Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
---
.../devicetree/bindings/spi/qcom,spi-qcom-qspi.yaml | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-qcom-qspi.yaml b/Documentation/devicetree/bindings/spi/qcom,spi-qcom-qspi.yaml
index 1696ac46a660..38b3408ae163 100644
--- a/Documentation/devicetree/bindings/spi/qcom,spi-qcom-qspi.yaml
+++ b/Documentation/devicetree/bindings/spi/qcom,spi-qcom-qspi.yaml
@@ -13,13 +13,11 @@ description: The QSPI controller allows SPI protocol communication in single,
dual, or quad wire transmission modes for read/write access to slaves such
as NOR flash.
-allOf:
- - $ref: /schemas/spi/spi-controller.yaml#
-
properties:
compatible:
items:
- enum:
+ - qcom,qcs615-qspi
- qcom,sc7180-qspi
- qcom,sc7280-qspi
- qcom,sdm845-qspi
@@ -67,6 +65,21 @@ required:
- clock-names
- clocks
+allOf:
+ - $ref: /schemas/spi/spi-controller.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: qcom,qcs615-qspi
+ then:
+ properties:
+ interconnects:
+ minItems: 2
+ required:
+ - interconnects
+ - interconnect-names
+
unevaluatedProperties: false
examples:
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/7] Add QSPI support for QCS615 and improve interconnect handling
From: Viken Dadhaniya @ 2026-04-14 17:08 UTC (permalink / raw)
To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, cros-qcom-dts-watchers
Cc: linux-arm-msm, linux-spi, devicetree, linux-kernel,
Viken Dadhaniya, Dmitry Baryshkov
Add QSPI controller support for the QCS615 (Talos) platform and improve
interconnect bandwidth management for QSPI controllers across multiple
Qualcomm SoCs.
The series consists of:
1. Add QCS615 compatible string to device tree bindings.
2. Add qspi-memory interconnect path support to the driver for proper DMA
bandwidth allocation.
3. Add QSPI support to QCS615 platform including OPP table, pinmux, and
controller node.
4. Enable QSPI controller and SPI-NOR flash on QCS615-RIDE board.
5. Add QSPI memory interconnect paths to existing SC7180 and Kodiak
platforms.
The key improvement in this series is adding the qspi-memory interconnect
path. Previously, the QSPI driver only managed the CPU-to-QSPI
configuration path. Add support for the QSPI-to-memory path, which is
essential for proper bandwidth allocation during DMA operations when the
QSPI controller transfers data to/from system memory.
Set the memory path bandwidth equal to the transfer speed, matching the
existing pattern used for the CPU path. Enable and disable both paths
properly during runtime PM transitions to ensure efficient power
management.
Apply this change to existing platforms (SC7180/Kodiak) as well as the
newly added QCS615 platform to ensure consistent interconnect handling
across all QSPI-enabled SoCs.
Testing:
- Verified QSPI functionality on QCS615-RIDE with SPI-NOR flash
- Confirmed proper interconnect bandwidth voting during transfers
- Validated runtime PM transitions with both interconnect paths
Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
---
Changes in v2:
- Moved allOf section to bottom of binding schema
- Added if:then constraint requiring minimum 2 interconnects for qcs615
- Fixed runtime PM error handling with complete goto-based cleanup
- Added proper error paths in suspend/resume functions
- Changed interconnect tags from raw 0 to QCOM_ICC_TAG_ACTIVE_ONLY
- Link to v1: https://patch.msgid.link/20260324-spi-nor-v1-0-3efe59c1c119@oss.qualcomm.com
---
Viken Dadhaniya (7):
dt-bindings: spi: qcom,spi-qcom-qspi: Add qcom,qcs615-qspi compatible
spi: qcom-qspi: Fix incomplete error handling in runtime PM
spi: qcom-qspi: Add interconnect support for memory path
arm64: dts: qcom: talos: Add QSPI support
arm64: dts: qcom: qcs615-ride: enable QSPI and NOR flash
arm64: dts: qcom: kodiak: Add QSPI memory interconnect path
arm64: dts: qcom: sc7180: Add QSPI memory interconnect path
.../bindings/spi/qcom,spi-qcom-qspi.yaml | 19 ++++-
arch/arm64/boot/dts/qcom/kodiak.dtsi | 9 ++-
arch/arm64/boot/dts/qcom/qcs615-ride.dts | 12 ++++
arch/arm64/boot/dts/qcom/sc7180.dtsi | 9 ++-
arch/arm64/boot/dts/qcom/talos.dtsi | 80 ++++++++++++++++++++++
drivers/spi/spi-qcom-qspi.c | 73 +++++++++++++++++---
6 files changed, 184 insertions(+), 18 deletions(-)
---
base-commit: c369299895a591d96745d6492d4888259b004a9e
change-id: 20260324-spi-nor-09c6d9e0de05
Best regards,
--
Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>
^ permalink raw reply
* [PATCH] arm64: dts: qcom: glymur: Drop RPMh CXO clocks from QMP PHYs
From: Abel Vesa @ 2026-04-14 17:05 UTC (permalink / raw)
To: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Wesley Cheng, Dmitry Baryshkov
Cc: Konrad Dybcio, linux-arm-msm, devicetree, linux-kernel,
Krzysztof Kozlowski, Abel Vesa
On Glymur, all QMP PHYs except the one used by USB SS0 take their
reference clock from the TCSR clock controller. Since these TCSR clocks
already derive from RPMH_CXO_CLK as their sole parent, there is no need
to provide an extra `clkref` clock to the PHY nodes.
Drop the extra RPMh CXO clock inputs and use the TCSR clocks as the PHY
reference clocks instead.
This also fixes the devicetree schema validation, as the bindings do not
allow a separate `clkref` clock.
Fixes: 4eee57dd4df9 ("arm64: dts: qcom: glymur: Add USB related nodes")
Reported-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reported-by: Rob Herring <robh@kernel.org>
Closes: https://lore.kernel.org/r/20260410145205.GA554754-robh@kernel.org/
Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/glymur.dtsi | 20 ++++++--------------
1 file changed, 6 insertions(+), 14 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
index f23cf81ddb77..82436984485d 100644
--- a/arch/arm64/boot/dts/qcom/glymur.dtsi
+++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
@@ -2314,11 +2314,9 @@ usb_mp_qmpphy0: phy@fa3000 {
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
<&tcsr TCSR_USB3_0_CLKREF_EN>,
- <&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
<&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>;
clock-names = "aux",
- "clkref",
"ref",
"com_aux",
"pipe";
@@ -2343,11 +2341,9 @@ usb_mp_qmpphy1: phy@fa5000 {
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
<&tcsr TCSR_USB3_1_CLKREF_EN>,
- <&rpmhcc RPMH_CXO_CLK>,
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
<&gcc GCC_USB3_MP_PHY_PIPE_1_CLK>;
clock-names = "aux",
- "clkref",
"ref",
"com_aux",
"pipe";
@@ -2482,15 +2478,13 @@ usb_1_qmpphy: phy@fde000 {
reg = <0x0 0x00fde000 0x0 0x8000>;
clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>,
- <&rpmhcc RPMH_CXO_CLK>,
+ <&tcsr TCSR_USB4_1_CLKREF_EN>,
<&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>,
- <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>,
- <&tcsr TCSR_USB4_1_CLKREF_EN>;
+ <&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
clock-names = "aux",
"ref",
"com_aux",
- "usb3_pipe",
- "clkref";
+ "usb3_pipe";
power-domains = <&gcc GCC_USB_1_PHY_GDSC>;
@@ -3750,15 +3744,13 @@ usb_2_qmpphy: phy@88e1000 {
reg = <0x0 0x088e1000 0x0 0x8000>;
clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>,
- <&rpmhcc RPMH_CXO_CLK>,
+ <&tcsr TCSR_USB4_2_CLKREF_EN>,
<&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>,
- <&gcc GCC_USB3_TERT_PHY_PIPE_CLK>,
- <&tcsr TCSR_USB4_2_CLKREF_EN>;
+ <&gcc GCC_USB3_TERT_PHY_PIPE_CLK>;
clock-names = "aux",
"ref",
"com_aux",
- "usb3_pipe",
- "clkref";
+ "usb3_pipe";
power-domains = <&gcc GCC_USB_2_PHY_GDSC>;
---
base-commit: e6efabc0afca02efa263aba533f35d90117ab283
change-id: 20260414-dts-glymur-drop-rpmh-cxo-clk-from-qmpphys-543285e18a78
Best regards,
--
Abel Vesa <abel.vesa@oss.qualcomm.com>
^ permalink raw reply related
* Re: [PATCH] spi: dt-bindings: fsl: Correct GPIO flags in the example
From: Mark Brown @ 2026-04-14 11:56 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley,
J. Neuschäfer, linux-spi, devicetree, linux-kernel,
Krzysztof Kozlowski
In-Reply-To: <20260413085947.51047-2-krzysztof.kozlowski@oss.qualcomm.com>
On Mon, 13 Apr 2026 10:59:48 +0200, Krzysztof Kozlowski wrote:
> spi: dt-bindings: fsl: Correct GPIO flags in the example
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-7.1
Thanks!
[1/1] spi: dt-bindings: fsl: Correct GPIO flags in the example
https://git.kernel.org/broonie/spi/c/ebeef57b7ba9
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply
* Re: [PATCH v8 1/4] dt-bindings: backlight: Add max25014 support
From: Daniel Thompson @ 2026-04-14 16:25 UTC (permalink / raw)
To: maudspierings
Cc: Lee Jones, Jingoo Han, Pavel Machek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Helge Deller, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Liam Girdwood, Mark Brown, Frank Li, dri-devel, linux-leds,
devicetree, linux-kernel, linux-fbdev, imx, linux-arm-kernel
In-Reply-To: <20260407-max25014-v8-1-14eac7ed673a@gocontroll.com>
On Tue, Apr 07, 2026 at 04:41:42PM +0200, Maud Spierings via B4 Relay wrote:
> From: Maud Spierings <maudspierings@gocontroll.com>
>
> The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> with integrated boost controller.
>
> Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> Signed-off-by: Maud Spierings <maudspierings@gocontroll.com>
Reviewed-by: Daniel Thompson (RISCstar) <danielt@kernel.org>
Daniel.
^ permalink raw reply
* Re: [PATCH 01/35] dt-bindings: qcom,pdc: Tighten reg to single APSS DRV region
From: Dmitry Baryshkov @ 2026-04-14 16:23 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Mukesh Ojha, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Konrad Dybcio,
cros-qcom-dts-watchers, linux-arm-msm, linux-kernel, devicetree
In-Reply-To: <ecb75ada-60c4-40e6-81bd-fc392007e9d8@oss.qualcomm.com>
On Mon, Apr 13, 2026 at 10:23:59AM +0200, Konrad Dybcio wrote:
> On 4/11/26 4:32 PM, Dmitry Baryshkov wrote:
> > On Sat, Apr 11, 2026 at 12:10:38AM +0530, Mukesh Ojha wrote:
> >> The PDC has multiple DRV regions, each sized 0x10000, where each region
> >> serves a specific client in the system. Linux only needs access to the
> >
> > Nit: there are other OS than Linux. Would you rather point out that
> > other DRV regions are to be used by ... what?
>
> TZ, HYP, HLOS, CPUCP..
=> commit message
>
> I'm wondering if we can make use of the HYP one on e.g. Glymur, to
> parallelize accesses (and whether that would bring any practical
> benefit).
>
> In the RPMH architecture, each "client" has their own (GPU, AOP, DISP,
> etc.). Then, each one of those clients may have an associates RSC
> (Resource State Coordinator) and/or anyOf BCM ("interconnect"), VRM
> ("regulator"), ARC ("RPMHPD") voting interfaces
At least the RSC should be visible to the OS. We don't use it (now), but
we probably will at some point (at least the DISP_RSC) if I understand
it correctly.
>
> Konrad
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH RFC v2 01/11] ASoC: meson: gx: add gx-formatter and gx-interface
From: Mark Brown @ 2026-04-14 16:21 UTC (permalink / raw)
To: Valerio Setti
Cc: Jerome Brunet, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Neil Armstrong, Kevin Hilman, Martin Blumenstingl, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-kernel, linux-sound,
linux-arm-kernel, linux-amlogic, devicetree
In-Reply-To: <20260411-audin-rfc-v2-1-4c8a6ec5fcab@baylibre.com>
[-- Attachment #1: Type: text/plain, Size: 704 bytes --]
On Sat, Apr 11, 2026 at 04:57:26PM +0200, Valerio Setti wrote:
> These files are the basic block which allow to shape I2S in GX devices
> the same as the AXG ones: the DAI backend only controls the interface
> (i.e. clocks and pins) whereas a formatter takes care of properly
> formatting the data.
> +int gx_formatter_probe(struct platform_device *pdev)
> +{
> +
> + return snd_soc_register_component(dev, drv->component_drv, NULL, 0);
> +}
> +EXPORT_SYMBOL_GPL(gx_formatter_probe);
The other allocations in this are devm_ but the component is registered
without using devm. Not using devm also means that all the users need
remove() functions to unregister the component, there isn't one for
AUDIN.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v1] arm64: dts: qcom: Enable CAN RX via GPIO expander
From: Konrad Dybcio @ 2026-04-14 16:20 UTC (permalink / raw)
To: Dmitry Baryshkov, Anup Kulkarni
Cc: andersson, konradybcio, robh, krzk+dt, conor+dt, linux-arm-msm,
devicetree, linux-kernel, mukesh.savaliya, viken.dadhaniya
In-Reply-To: <tuanv2szadq5pnndy4zfxg4mo73pplfv3omanpsc3mcjorpmbc@itd2hayrix5h>
On 4/14/26 6:08 PM, Dmitry Baryshkov wrote:
> On Thu, Apr 02, 2026 at 04:22:53PM +0530, Anup Kulkarni wrote:
>> Few CAN controllers, part of RTSS sub-system on LeMans, route
>> their RX signal through a I2C GPIO expander at address 0x3b.
>> RTSS subsystem is an MCU like sub-system on LeMans with independent
>> booting capability through OSPI interface and supports peripherals like
>> RGMII, CAN-FD, UART, I2C, SPI etc.
>>
>> Describe this hardware wiring by configuring the expander GPIO 4 pin as
>> hog with output-high, asserting the selected line during boot.
>
> Missing platform name in the subject.
>
>>
>> Signed-off-by: Anup Kulkarni <anup.kulkarni@oss.qualcomm.com>
>> ---
>> arch/arm64/boot/dts/qcom/lemans-evk.dts | 7 +++++++
>> 1 file changed, 7 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts
>> index a1ef4eba2a20..b8371bdf9933 100644
>> --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts
>> +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts
>> @@ -615,6 +615,13 @@ expander3: gpio@3b {
>> interrupts-extended = <&tlmm 39 IRQ_TYPE_LEVEL_LOW>;
>> pinctrl-0 = <&expander3_int>;
>> pinctrl-names = "default";
>> +
>> + rtss-can-sel-hog {
>
> Why is it being described as a hog rather than a pinctrl used by the
> CAN device?
My understanding is that the CAN bus is managed by SAIL ("RTSS")
Konrad
^ permalink raw reply
* [PATCH 2/2] remoteproc: add AMD MicroBlaze driver
From: Ben Levinsky @ 2026-04-14 16:15 UTC (permalink / raw)
To: andersson, mathieu.poirier
Cc: robh, krzk+dt, conor+dt, linux-remoteproc, devicetree,
linux-kernel, ben.levinsky, tanmay.shah, michal.simek
In-Reply-To: <20260414161558.2579920-1-ben.levinsky@amd.com>
Add an AMD MicroBlaze remoteproc driver.
The driver parses the executable firmware memory window from
the remoteproc device node's reg property, interprets that
address and size in the MicroBlaze-local address space, and
then uses standard devicetree address translation through the
parent bus ranges property to obtain the corresponding
Linux-visible system physical address.
The resulting translated region is registered as the executable
remoteproc carveout and coredump segment.
The MicroBlaze is controlled through an active-low reset GPIO and kept in
reset until firmware loading completes.
The firmware-name property is optional, allowing firmware to be
assigned later through the remoteproc framework.
Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>
---
MAINTAINERS | 7 +
drivers/remoteproc/Kconfig | 15 ++
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/amd_microblaze_rproc.c | 202 ++++++++++++++++++++++
4 files changed, 225 insertions(+)
create mode 100644 drivers/remoteproc/amd_microblaze_rproc.c
diff --git a/MAINTAINERS b/MAINTAINERS
index a7e30df8ba5d..a70397b9ca71 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1172,6 +1172,13 @@ F: drivers/gpu/drm/amd/include/vi_structs.h
F: include/uapi/linux/kfd_ioctl.h
F: include/uapi/linux/kfd_sysfs.h
+AMD MICROBLAZE REMOTEPROC DRIVER
+M: Ben Levinsky <ben.levinsky@amd.com>
+L: linux-remoteproc@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/remoteproc/amd,microblaze.yaml
+F: drivers/remoteproc/amd_microblaze_rproc.c
+
AMD MP2 I2C DRIVER
M: Elie Morisse <syniurge@gmail.com>
M: Shyam Sundar S K <shyam-sundar.s-k@amd.com>
diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index ee54436fea5a..76de743241a7 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -23,6 +23,21 @@ config REMOTEPROC_CDEV
It's safe to say N if you don't want to use this interface.
+config AMD_MICROBLAZE_REMOTEPROC
+ tristate "AMD MicroBlaze remoteproc support"
+ depends on OF
+ depends on GPIOLIB || COMPILE_TEST
+ help
+ Say y or m here to support a MicroBlaze remote processor controlled
+ by Linux through the remoteproc framework.
+
+ This driver matches designs where executable firmware memory is
+ described in the MicroBlaze-local address space and translated to
+ the system physical address space with standard devicetree address
+ translation.
+
+ If unsure, say N.
+
config IMX_REMOTEPROC
tristate "i.MX remoteproc support"
depends on ARCH_MXC
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 1c7598b8475d..8717a0aec2e6 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_AMD_MICROBLAZE_REMOTEPROC) += amd_microblaze_rproc.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/amd_microblaze_rproc.c b/drivers/remoteproc/amd_microblaze_rproc.c
new file mode 100644
index 000000000000..c664a70d246b
--- /dev/null
+++ b/drivers/remoteproc/amd_microblaze_rproc.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * AMD MicroBlaze Remote Processor driver
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ *
+ * This driver supports a MicroBlaze remote processor managed by Linux
+ * through the remoteproc framework.
+ *
+ * The executable firmware memory is described in the MicroBlaze-local
+ * address space and translated to the Linux-visible system physical
+ * address with standard devicetree address translation.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+
+#include "remoteproc_internal.h"
+
+struct mb_rproc {
+ struct device *dev;
+ struct gpio_desc *reset;
+};
+
+static int mb_rproc_mem_region_map(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ void __iomem *va;
+
+ va = ioremap_wc(mem->dma, mem->len);
+ if (!va)
+ return -ENOMEM;
+
+ mem->va = (__force void *)va;
+ mem->is_iomem = true;
+
+ return 0;
+}
+
+static int mb_rproc_mem_region_unmap(struct rproc *rproc,
+ struct rproc_mem_entry *mem)
+{
+ iounmap((void __iomem *)mem->va);
+
+ return 0;
+}
+
+static int mb_rproc_prepare(struct rproc *rproc)
+{
+ struct mb_rproc *mb = rproc->priv;
+ struct rproc_mem_entry *mem;
+ struct resource res;
+ u64 da, size;
+ int ret;
+
+ ret = of_property_read_reg(mb->dev->of_node, 0, &da, &size);
+ if (ret) {
+ dev_err(mb->dev, "failed to parse executable memory reg\n");
+ return ret;
+ }
+
+ if (!size || size > U32_MAX) {
+ dev_err(mb->dev, "invalid executable memory size\n");
+ return -EINVAL;
+ }
+
+ ret = of_address_to_resource(mb->dev->of_node, 0, &res);
+ if (ret) {
+ dev_err(mb->dev, "failed to translate executable memory reg\n");
+ return ret;
+ }
+
+ mem = rproc_mem_entry_init(mb->dev, NULL, (dma_addr_t)res.start,
+ (size_t)size, da,
+ mb_rproc_mem_region_map,
+ mb_rproc_mem_region_unmap,
+ dev_name(mb->dev));
+ if (!mem)
+ return -ENOMEM;
+
+ rproc_add_carveout(rproc, mem);
+ rproc_coredump_add_segment(rproc, da, (size_t)size);
+
+ return 0;
+}
+
+static int mb_rproc_start(struct rproc *rproc)
+{
+ struct mb_rproc *mb = rproc->priv;
+
+ /* reset-gpios is declared active-low, so logical 0 releases reset */
+ gpiod_set_value_cansleep(mb->reset, 0);
+
+ return 0;
+}
+
+static int mb_rproc_stop(struct rproc *rproc)
+{
+ struct mb_rproc *mb = rproc->priv;
+
+ /* reset-gpios is declared active-low, so logical 1 asserts reset */
+ gpiod_set_value_cansleep(mb->reset, 1);
+
+ return 0;
+}
+
+static int mb_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw)
+{
+ int ret;
+
+ ret = rproc_elf_load_rsc_table(rproc, fw);
+ if (ret == -EINVAL) {
+ dev_dbg(&rproc->dev, "no resource table found\n");
+ return 0;
+ }
+
+ return ret;
+}
+
+static const struct rproc_ops mb_rproc_ops = {
+ .prepare = mb_rproc_prepare,
+ .start = mb_rproc_start,
+ .stop = mb_rproc_stop,
+ .load = rproc_elf_load_segments,
+ .sanity_check = rproc_elf_sanity_check,
+ .get_boot_addr = rproc_elf_get_boot_addr,
+ .parse_fw = mb_rproc_parse_fw,
+};
+
+static int mb_rproc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mb_rproc *mb;
+ struct rproc *rproc;
+ const char *fw_name = NULL;
+ int ret;
+
+ ret = rproc_of_parse_firmware(dev, 0, &fw_name);
+ if (ret < 0 && ret != -EINVAL)
+ return dev_err_probe(dev, ret,
+ "failed to parse firmware-name property\n");
+
+ rproc = devm_rproc_alloc(dev, dev_name(dev), &mb_rproc_ops, fw_name,
+ sizeof(*mb));
+ if (!rproc)
+ return -ENOMEM;
+
+ mb = rproc->priv;
+ mb->dev = dev;
+
+ /*
+ * Keep the MicroBlaze in reset until remoteproc has finished loading
+ * firmware into the executable memory window described by reg and
+ * translated through the parent bus ranges property.
+ */
+ mb->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(mb->reset))
+ return dev_err_probe(dev, PTR_ERR(mb->reset),
+ "failed to get reset gpio\n");
+
+ rproc->auto_boot = false;
+
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set DMA mask\n");
+
+ platform_set_drvdata(pdev, rproc);
+
+ ret = devm_rproc_add(dev, rproc);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register rproc\n");
+
+ dev_dbg(dev, "MicroBlaze remoteproc registered\n");
+
+ return 0;
+}
+
+static const struct of_device_id mb_rproc_of_match[] = {
+ { .compatible = "amd,microblaze" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mb_rproc_of_match);
+
+static struct platform_driver mb_rproc_driver = {
+ .probe = mb_rproc_probe,
+ .driver = {
+ .name = "amd-microblaze-rproc",
+ .of_match_table = mb_rproc_of_match,
+ },
+};
+module_platform_driver(mb_rproc_driver);
+
+MODULE_DESCRIPTION("AMD MicroBlaze Remote Processor driver");
+MODULE_AUTHOR("Ben Levinsky");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related
* [PATCH 0/2] Add a MicroBlaze remoteproc driver and binding
From: Ben Levinsky @ 2026-04-14 16:15 UTC (permalink / raw)
To: andersson, mathieu.poirier
Cc: robh, krzk+dt, conor+dt, linux-remoteproc, devicetree,
linux-kernel, ben.levinsky, tanmay.shah, michal.simek
This series adds initial remoteproc support for AMD MicroBlaze soft
processors.
The binding models the MicroBlaze remote processor as a child node whose
reg property describes the executable firmware memory window in the
MicroBlaze-local address space. The parent bus ranges property provides
the standard devicetree address translation to the Linux-visible system
physical address.
The driver uses that translated memory window as the executable
remoteproc carveout and coredump segment, holds the MicroBlaze in reset
through an active-low GPIO until firmware loading completes, and allows
the firmware image to be selected with the optional firmware-name
property. Firmware images without a resource table are also accepted.
This initial series focuses on basic load/start/stop support for a
single executable memory window. It does not add any transport or
mailbox integration.
Ben Levinsky (2):
dt-bindings: remoteproc: add AMD MicroBlaze binding
remoteproc: add AMD MicroBlaze driver
.../bindings/remoteproc/amd,microblaze.yaml | 67 ++++++
MAINTAINERS | 7 +
drivers/remoteproc/Kconfig | 15 ++
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/amd_microblaze_rproc.c | 202 ++++++++++++++++++
5 files changed, 292 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/amd,microblaze.yaml
create mode 100644 drivers/remoteproc/amd_microblaze_rproc.c
--
2.34.1
^ permalink raw reply
* [PATCH 1/2] dt-bindings: remoteproc: add AMD MicroBlaze binding
From: Ben Levinsky @ 2026-04-14 16:15 UTC (permalink / raw)
To: andersson, mathieu.poirier
Cc: robh, krzk+dt, conor+dt, linux-remoteproc, devicetree,
linux-kernel, ben.levinsky, tanmay.shah, michal.simek
In-Reply-To: <20260414161558.2579920-1-ben.levinsky@amd.com>
Describe an AMD MicroBlaze remote processor controlled
through the remoteproc framework.
The binding models the MicroBlaze remoteproc device as a
child node whose reg property describes the executable firmware
memory window in the MicroBlaze-local address space. The parent bus
node provides standard devicetree address translation through ranges
so Linux can access the same memory through the system physical
address space.
An active-low reset GPIO holds the MicroBlaze in reset until
firmware loading completes.
Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>
---
.../bindings/remoteproc/amd,microblaze.yaml | 67 +++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100644 Documentation/devicetree/bindings/remoteproc/amd,microblaze.yaml
diff --git a/Documentation/devicetree/bindings/remoteproc/amd,microblaze.yaml b/Documentation/devicetree/bindings/remoteproc/amd,microblaze.yaml
new file mode 100644
index 000000000000..2811610204a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/remoteproc/amd,microblaze.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/remoteproc/amd,microblaze.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: AMD MicroBlaze remote processor
+
+maintainers:
+ - Ben Levinsky <ben.levinsky@amd.com>
+
+description:
+ MicroBlaze remote processor controlled by Linux through the remoteproc
+ framework.
+
+ The executable firmware memory window is described in the
+ MicroBlaze-local address space by the node's reg property and translated
+ to the system physical address space with standard devicetree address
+ translation provided by the parent bus node's ranges property.
+
+properties:
+ $nodename:
+ pattern: "^remoteproc@[0-9a-f]+$"
+
+ compatible:
+ const: amd,microblaze
+
+ reg:
+ maxItems: 1
+ description:
+ MicroBlaze-local address and size of the executable firmware memory
+ window.
+
+ firmware-name:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - reset-gpios
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ / {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ bus@b0000000 {
+ compatible = "simple-pm-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0xb0000000 0x40000>;
+
+ remoteproc@0 {
+ compatible = "amd,microblaze";
+ reg = <0x0 0x40000>;
+ reset-gpios = <&mbv_reset_gpio 0 GPIO_ACTIVE_LOW>;
+ };
+ };
+ };
--
2.34.1
^ permalink raw reply related
* Re: [PATCH RFC v2 02/11] ASoC: meson: aiu-encoder-i2s: use gx_iface and gx_stream structures
From: Mark Brown @ 2026-04-14 16:13 UTC (permalink / raw)
To: Valerio Setti
Cc: Jerome Brunet, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Neil Armstrong, Kevin Hilman, Martin Blumenstingl, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-kernel, linux-sound,
linux-arm-kernel, linux-amlogic, devicetree
In-Reply-To: <20260411-audin-rfc-v2-2-4c8a6ec5fcab@baylibre.com>
[-- Attachment #1: Type: text/plain, Size: 1601 bytes --]
On Sat, Apr 11, 2026 at 04:57:27PM +0200, Valerio Setti wrote:
> @@ -200,13 +200,17 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
> - aiu_encoder_i2s_divider_enable(component, true);
> + ret = gx_stream_set_cont_clocks(ts, iface->fmt);
> + if (ret)
> + dev_err(dai->dev, "failed to apply continuous clock setting\n");
> +
> + aiu_encoder_i2s_divider_enable(component, 1);
If we're checking the error here we should probably return it as well.
Including the error code in the log message is also generally helpful.
> @@ -214,16 +218,20 @@ static int aiu_encoder_i2s_hw_params(struct snd_pcm_substream *substream,
> static int aiu_encoder_i2s_hw_free(struct snd_pcm_substream *substream,
> struct snd_soc_dai *dai)
> {
> + struct gx_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
> struct snd_soc_component *component = dai->component;
>
> - aiu_encoder_i2s_divider_enable(component, false);
> -
> - return 0;
> + /* This is the last substream open and that is going to be closed. */
> + if (snd_soc_dai_active(dai) <= 1)
> + aiu_encoder_i2s_divider_enable(component, 0);
> + return gx_stream_set_cont_clocks(ts, 0);
> }
Note that we only hw_free() if we preprared, but we enable in
hw_params().
> @@ -284,6 +295,8 @@ static int aiu_encoder_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id,
> if (ret)
> dev_err(dai->dev, "Failed to set sysclk to %uHz", freq);
>
> + aiu->i2s.iface.mclk_rate = freq;
> +
> return ret;
> }
This means we store the new rate even if the set above failed.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v1] arm64: dts: qcom: Enable CAN RX via GPIO expander
From: Dmitry Baryshkov @ 2026-04-14 16:08 UTC (permalink / raw)
To: Anup Kulkarni
Cc: andersson, konradybcio, robh, krzk+dt, conor+dt, linux-arm-msm,
devicetree, linux-kernel, mukesh.savaliya, viken.dadhaniya
In-Reply-To: <20260402105253.3009382-1-anup.kulkarni@oss.qualcomm.com>
On Thu, Apr 02, 2026 at 04:22:53PM +0530, Anup Kulkarni wrote:
> Few CAN controllers, part of RTSS sub-system on LeMans, route
> their RX signal through a I2C GPIO expander at address 0x3b.
> RTSS subsystem is an MCU like sub-system on LeMans with independent
> booting capability through OSPI interface and supports peripherals like
> RGMII, CAN-FD, UART, I2C, SPI etc.
>
> Describe this hardware wiring by configuring the expander GPIO 4 pin as
> hog with output-high, asserting the selected line during boot.
Missing platform name in the subject.
>
> Signed-off-by: Anup Kulkarni <anup.kulkarni@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/lemans-evk.dts | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts
> index a1ef4eba2a20..b8371bdf9933 100644
> --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts
> +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts
> @@ -615,6 +615,13 @@ expander3: gpio@3b {
> interrupts-extended = <&tlmm 39 IRQ_TYPE_LEVEL_LOW>;
> pinctrl-0 = <&expander3_int>;
> pinctrl-names = "default";
> +
> + rtss-can-sel-hog {
Why is it being described as a hog rather than a pinctrl used by the
CAN device?
> + gpio-hog;
> + gpios = <4 GPIO_ACTIVE_HIGH>;
> + output-high;
> + line-name = "rtss-can-sel";
> + };
> };
>
> eeprom@50 {
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 10/11] media: iris: Add platform data for glymur
From: Dmitry Baryshkov @ 2026-04-14 16:05 UTC (permalink / raw)
To: Vishnu Reddy
Cc: Bryan O'Donoghue, Vikash Garodia, Dikshita Agarwal,
Abhinav Kumar, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joerg Roedel, Will Deacon,
Robin Murphy, Bjorn Andersson, Konrad Dybcio, Stefan Schmidt,
Hans Verkuil, linux-media, linux-arm-msm, devicetree,
linux-kernel, iommu
In-Reply-To: <20260414-glymur-v1-10-7d3d1cf57b16@oss.qualcomm.com>
On Tue, Apr 14, 2026 at 10:30:06AM +0530, Vishnu Reddy wrote:
> Add glymur platform data by reusing most of the SM8550 definitions.
> Move configuration that differs in a per-SoC platform specific data.
>
> Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
> ---
> drivers/media/platform/qcom/iris/Makefile | 1 +
> .../platform/qcom/iris/iris_platform_common.h | 1 +
> .../media/platform/qcom/iris/iris_platform_gen2.c | 100 +++++++++++++++++++++
> .../platform/qcom/iris/iris_platform_glymur.c | 93 +++++++++++++++++++
> .../platform/qcom/iris/iris_platform_glymur.h | 17 ++++
> drivers/media/platform/qcom/iris/iris_probe.c | 4 +
> 6 files changed, 216 insertions(+)
>
> diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile
> index 6f4052b98491..677513c7c045 100644
> --- a/drivers/media/platform/qcom/iris/Makefile
> +++ b/drivers/media/platform/qcom/iris/Makefile
> @@ -11,6 +11,7 @@ qcom-iris-objs += iris_buffer.o \
> iris_hfi_gen2_response.o \
> iris_hfi_queue.o \
> iris_platform_gen2.o \
> + iris_platform_glymur.o \
> iris_power.o \
> iris_probe.o \
> iris_resources.o \
> diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
> index aeb70f54be10..a279ea462ee6 100644
> --- a/drivers/media/platform/qcom/iris/iris_platform_common.h
> +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
> @@ -41,6 +41,7 @@ enum pipe_type {
> PIPE_4 = 4,
> };
>
> +extern const struct iris_platform_data glymur_data;
> extern const struct iris_platform_data qcs8300_data;
> extern const struct iris_platform_data sc7280_data;
> extern const struct iris_platform_data sm8250_data;
> diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c
> index 47c6b650f0b4..fa2115092be8 100644
> --- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c
> +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c
> @@ -12,6 +12,7 @@
> #include "iris_vpu_buffer.h"
> #include "iris_vpu_common.h"
>
> +#include "iris_platform_glymur.h"
> #include "iris_platform_qcs8300.h"
> #include "iris_platform_sm8650.h"
> #include "iris_platform_sm8750.h"
> @@ -921,6 +922,105 @@ static const u32 sm8550_enc_op_int_buf_tbl[] = {
> BUF_SCRATCH_2,
> };
>
> +const struct iris_platform_data glymur_data = {
If you add a platform-specific file, then move the data to the file too.
Also, please use iris_something prefix for all your visible symbols.
> + .get_instance = iris_hfi_gen2_get_instance,
> + .init_hfi_command_ops = iris_hfi_gen2_command_ops_init,
> + .init_hfi_response_ops = iris_hfi_gen2_response_ops_init,
> + .get_vpu_buffer_size = iris_vpu_buf_size,
> + .vpu_ops = &iris_vpu36_ops,
> + .set_preset_registers = iris_set_sm8550_preset_registers,
> + .init_cb_devs = glymur_init_cb_devs,
> + .deinit_cb_devs = glymur_deinit_cb_devs,
> + .icc_tbl = sm8550_icc_table,
> + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table),
> + .clk_rst_tbl = glymur_clk_reset_table,
> + .clk_rst_tbl_size = ARRAY_SIZE(glymur_clk_reset_table),
> + .bw_tbl_dec = sm8550_bw_table_dec,
> + .bw_tbl_dec_size = ARRAY_SIZE(sm8550_bw_table_dec),
> + .pmdomain_tbl = glymur_pmdomain_table,
> + .pmdomain_tbl_size = ARRAY_SIZE(glymur_pmdomain_table),
> + .opp_pd_tbl = sm8550_opp_pd_table,
> + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table),
> + .clk_tbl = glymur_clk_table,
> + .clk_tbl_size = ARRAY_SIZE(glymur_clk_table),
> + .opp_clk_tbl = glymur_opp_clk_table,
> + /* Upper bound of DMA address range */
> + .dma_mask = 0xffe00000 - 1,
> + .fwname = "qcom/vpu/vpu36_p4_s7.mbn",
> + .pas_id = IRIS_PAS_ID,
> + .dual_core = true,
> + .inst_iris_fmts = platform_fmts_sm8550_dec,
> + .inst_iris_fmts_size = ARRAY_SIZE(platform_fmts_sm8550_dec),
> + .inst_caps = &platform_inst_cap_sm8550,
> + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec,
> + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec),
> + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc,
> + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc),
> + .tz_cp_config_data = tz_cp_config_glymur,
> + .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_glymur),
> + .core_arch = VIDEO_ARCH_LX,
> + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE,
> + .ubwc_config = &ubwc_config_sm8550,
> + .num_vpp_pipe = 4,
> + .max_session_count = 16,
> + .max_core_mbpf = NUM_MBS_8K * 2,
> + .max_core_mbps = ((8192 * 4320) / 256) * 60,
> + .dec_input_config_params_default =
> + sm8550_vdec_input_config_params_default,
> + .dec_input_config_params_default_size =
> + ARRAY_SIZE(sm8550_vdec_input_config_params_default),
> + .dec_input_config_params_hevc =
> + sm8550_vdec_input_config_param_hevc,
> + .dec_input_config_params_hevc_size =
> + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc),
> + .dec_input_config_params_vp9 =
> + sm8550_vdec_input_config_param_vp9,
> + .dec_input_config_params_vp9_size =
> + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9),
> + .dec_input_config_params_av1 =
> + sm8550_vdec_input_config_param_av1,
> + .dec_input_config_params_av1_size =
> + ARRAY_SIZE(sm8550_vdec_input_config_param_av1),
> + .dec_output_config_params =
> + sm8550_vdec_output_config_params,
> + .dec_output_config_params_size =
> + ARRAY_SIZE(sm8550_vdec_output_config_params),
> +
> + .enc_input_config_params =
> + sm8550_venc_input_config_params,
> + .enc_input_config_params_size =
> + ARRAY_SIZE(sm8550_venc_input_config_params),
> + .enc_output_config_params =
> + sm8550_venc_output_config_params,
> + .enc_output_config_params_size =
> + ARRAY_SIZE(sm8550_venc_output_config_params),
> +
> + .dec_input_prop = sm8550_vdec_subscribe_input_properties,
> + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties),
> + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc,
> + .dec_output_prop_avc_size =
> + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc),
> + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc,
> + .dec_output_prop_hevc_size =
> + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc),
> + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9,
> + .dec_output_prop_vp9_size =
> + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9),
> + .dec_output_prop_av1 = sm8550_vdec_subscribe_output_properties_av1,
> + .dec_output_prop_av1_size =
> + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_av1),
> +
> + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl,
> + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl),
> + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl,
> + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl),
> +
> + .enc_ip_int_buf_tbl = sm8550_enc_ip_int_buf_tbl,
> + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_ip_int_buf_tbl),
> + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl,
> + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl),
> +};
> +
> const struct iris_platform_data sm8550_data = {
> .get_instance = iris_hfi_gen2_get_instance,
> .init_hfi_command_ops = iris_hfi_gen2_command_ops_init,
> diff --git a/drivers/media/platform/qcom/iris/iris_platform_glymur.c b/drivers/media/platform/qcom/iris/iris_platform_glymur.c
> new file mode 100644
> index 000000000000..64b150db9f73
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/iris_platform_glymur.c
> @@ -0,0 +1,93 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#include <dt-bindings/media/qcom,glymur-iris.h>
> +#include "iris_core.h"
> +#include "iris_platform_common.h"
> +#include "iris_platform_glymur.h"
> +
> +#define VIDEO_REGION_SECURE_FW_REGION_ID 0
> +#define VIDEO_REGION_VM0_SECURE_NP_ID 1
> +#define VIDEO_REGION_VM0_NONSECURE_NP_ID 5
These are not glymur-specific, are they?
> +
> +const struct platform_clk_data glymur_clk_table[] = {
> + {IRIS_AXI_VCODEC_CLK, "iface" },
> + {IRIS_CTRL_CLK, "core" },
> + {IRIS_VCODEC_CLK, "vcodec0_core" },
> + {IRIS_AXI_CTRL_CLK, "iface_ctrl" },
> + {IRIS_CTRL_FREERUN_CLK, "core_freerun" },
> + {IRIS_VCODEC_FREERUN_CLK, "vcodec0_core_freerun" },
> + {IRIS_AXI_VCODEC1_CLK, "iface1" },
> + {IRIS_VCODEC1_CLK, "vcodec1_core" },
> + {IRIS_VCODEC1_FREERUN_CLK, "vcodec1_core_freerun" },
> +};
> +
> +const char * const glymur_clk_reset_table[] = {
> + "bus0",
> + "bus_ctrl",
> + "core",
> + "vcodec0_core",
> + "bus1",
> + "vcodec1_core",
> +};
> +
> +const char * const glymur_opp_clk_table[] = {
> + "vcodec0_core",
> + "vcodec1_core",
> + "core",
> + NULL,
> +};
> +
> +const char * const glymur_pmdomain_table[] = {
> + "venus",
> + "vcodec0",
> + "vcodec1",
> +};
> +
> +const struct tz_cp_config tz_cp_config_glymur[] = {
> + {
> + .cp_start = VIDEO_REGION_SECURE_FW_REGION_ID,
> + .cp_size = 0,
> + .cp_nonpixel_start = 0,
> + .cp_nonpixel_size = 0x1000000,
> + },
> + {
> + .cp_start = VIDEO_REGION_VM0_SECURE_NP_ID,
> + .cp_size = 0,
> + .cp_nonpixel_start = 0x1000000,
> + .cp_nonpixel_size = 0x24800000,
> + },
> + {
> + .cp_start = VIDEO_REGION_VM0_NONSECURE_NP_ID,
> + .cp_size = 0,
> + .cp_nonpixel_start = 0x25800000,
> + .cp_nonpixel_size = 0xda600000,
> + },
> +};
> +
> +int glymur_init_cb_devs(struct iris_core *core)
> +{
> + const u32 f_id = IRIS_FIRMWARE;
> + struct device *dev;
> +
> + dev = iris_create_cb_dev(core, "iris_firmware", &f_id);
> + if (IS_ERR(dev))
> + return PTR_ERR(dev);
> +
> + if (device_iommu_mapped(dev))
> + core->dev_fw = dev;
> + else
> + device_unregister(dev);
> +
> + return 0;
> +}
> +
> +void glymur_deinit_cb_devs(struct iris_core *core)
> +{
> + if (core->dev_fw)
> + device_unregister(core->dev_fw);
> +
> + core->dev_fw = NULL;
Why do you need to set it to NULL?
> +}
> diff --git a/drivers/media/platform/qcom/iris/iris_platform_glymur.h b/drivers/media/platform/qcom/iris/iris_platform_glymur.h
> new file mode 100644
> index 000000000000..03c83922f0d9
> --- /dev/null
> +++ b/drivers/media/platform/qcom/iris/iris_platform_glymur.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) Qualcomm Innovation Center, Inc. All rights reserved.
> + */
> +
> +#ifndef __IRIS_PLATFORM_GLYMUR_H__
> +#define __IRIS_PLATFORM_GLYMUR_H__
> +
> +extern const struct platform_clk_data glymur_clk_table[9];
> +extern const char * const glymur_clk_reset_table[6];
> +extern const char * const glymur_opp_clk_table[4];
> +extern const char * const glymur_pmdomain_table[3];
> +extern const struct tz_cp_config tz_cp_config_glymur[3];
> +int glymur_init_cb_devs(struct iris_core *core);
> +void glymur_deinit_cb_devs(struct iris_core *core);
> +
> +#endif
> diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c
> index 34751912f871..53869d9113d5 100644
> --- a/drivers/media/platform/qcom/iris/iris_probe.c
> +++ b/drivers/media/platform/qcom/iris/iris_probe.c
> @@ -369,6 +369,10 @@ static const struct dev_pm_ops iris_pm_ops = {
> };
>
> static const struct of_device_id iris_dt_match[] = {
> + {
> + .compatible = "qcom,glymur-iris",
> + .data = &glymur_data,
> + },
> {
> .compatible = "qcom,qcs8300-iris",
> .data = &qcs8300_data,
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 09/11] media: iris: Add support to select core for dual core platforms
From: Dmitry Baryshkov @ 2026-04-14 16:02 UTC (permalink / raw)
To: Vishnu Reddy
Cc: Bryan O'Donoghue, Vikash Garodia, Dikshita Agarwal,
Abhinav Kumar, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joerg Roedel, Will Deacon,
Robin Murphy, Bjorn Andersson, Konrad Dybcio, Stefan Schmidt,
Hans Verkuil, linux-media, linux-arm-msm, devicetree,
linux-kernel, iommu
In-Reply-To: <20260414-glymur-v1-9-7d3d1cf57b16@oss.qualcomm.com>
On Tue, Apr 14, 2026 at 10:30:05AM +0530, Vishnu Reddy wrote:
> Select the hardware core (vcodec) for a session, based on load when the
> platform supports dual vcodec cores. Assign the session to vcodec if its
> MBPF/MBPS capacity allows it, otherwise assign to vcodec1. Communicate
> the selected vcodec core to firmware using new HFI_PROP_CORE_ID property.
Is it possibly do dynamically control power to those codec cores? Is it
possible to shutdown unused vcodec?
>
> Signed-off-by: Vishnu Reddy <busanna.reddy@oss.qualcomm.com>
> ---
> drivers/media/platform/qcom/iris/iris_common.c | 7 +++
> drivers/media/platform/qcom/iris/iris_hfi_common.h | 1 +
> .../platform/qcom/iris/iris_hfi_gen2_command.c | 19 ++++++
> .../platform/qcom/iris/iris_hfi_gen2_defines.h | 1 +
> drivers/media/platform/qcom/iris/iris_instance.h | 2 +
> .../platform/qcom/iris/iris_platform_common.h | 1 +
> drivers/media/platform/qcom/iris/iris_utils.c | 68 +++++++++++++++++-----
> 7 files changed, 83 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/media/platform/qcom/iris/iris_common.c b/drivers/media/platform/qcom/iris/iris_common.c
> index 7f1c7fe144f7..e31d4c988c55 100644
> --- a/drivers/media/platform/qcom/iris/iris_common.c
> +++ b/drivers/media/platform/qcom/iris/iris_common.c
> @@ -49,11 +49,18 @@ void iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf)
> int iris_process_streamon_input(struct iris_inst *inst)
> {
> const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops;
> + bool dual_core = inst->core->iris_platform_data->dual_core;
inline
> enum iris_inst_sub_state set_sub_state = 0;
> int ret;
>
> iris_scale_power(inst);
>
> + if (dual_core) {
> + ret = hfi_ops->session_set_core_id(inst, inst->core_id);
> + if (ret)
> + return ret;
> + }
> +
> ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
> if (ret)
> return ret;
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h b/drivers/media/platform/qcom/iris/iris_hfi_common.h
> index 3edb5ae582b4..fbaf852a6b99 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_common.h
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h
> @@ -124,6 +124,7 @@ struct iris_hfi_command_ops {
> int (*session_drain)(struct iris_inst *inst, u32 plane);
> int (*session_resume_drain)(struct iris_inst *inst, u32 plane);
> int (*session_close)(struct iris_inst *inst);
> + int (*session_set_core_id)(struct iris_inst *inst, u32 core_id);
> };
>
> struct iris_hfi_response_ops {
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
> index 30bfd90d423b..9d9fae587297 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c
> @@ -1300,6 +1300,24 @@ static int iris_hfi_gen2_session_release_buffer(struct iris_inst *inst, struct i
> inst_hfi_gen2->packet->size);
> }
>
> +static int iris_hfi_gen2_set_core_id(struct iris_inst *inst, u32 core_id)
> +{
> + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst);
> + u32 payload = core_id;
> +
> + iris_hfi_gen2_packet_session_command(inst,
> + HFI_PROP_CORE_ID,
> + HFI_HOST_FLAGS_NONE,
> + HFI_PORT_NONE,
> + inst->session_id,
> + HFI_PAYLOAD_U32,
> + &payload,
> + sizeof(u32));
> +
> + return iris_hfi_queue_cmd_write(inst->core, inst_hfi_gen2->packet,
> + inst_hfi_gen2->packet->size);
> +}
> +
> static const struct iris_hfi_command_ops iris_hfi_gen2_command_ops = {
> .sys_init = iris_hfi_gen2_sys_init,
> .sys_image_version = iris_hfi_gen2_sys_image_version,
> @@ -1317,6 +1335,7 @@ static const struct iris_hfi_command_ops iris_hfi_gen2_command_ops = {
> .session_drain = iris_hfi_gen2_session_drain,
> .session_resume_drain = iris_hfi_gen2_session_resume_drain,
> .session_close = iris_hfi_gen2_session_close,
> + .session_set_core_id = iris_hfi_gen2_set_core_id,
> };
>
> void iris_hfi_gen2_command_ops_init(struct iris_core *core)
> diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
> index cecf771c55dd..1926a5344427 100644
> --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
> +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h
> @@ -56,6 +56,7 @@
> #define HFI_PROP_BUFFER_HOST_MAX_COUNT 0x03000123
> #define HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT 0x03000124
> #define HFI_PROP_PIC_ORDER_CNT_TYPE 0x03000128
> +#define HFI_PROP_CORE_ID 0x030001A9
lowercase hex
>
> enum hfi_rate_control {
> HFI_RC_VBR_CFR = 0x00000000,
> diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h
> index 16965150f427..dd341ca5be57 100644
> --- a/drivers/media/platform/qcom/iris/iris_instance.h
> +++ b/drivers/media/platform/qcom/iris/iris_instance.h
> @@ -37,6 +37,7 @@ struct iris_fmt {
> *
> * @list: used for attach an instance to the core
> * @core: pointer to core structure
> + * @core_id: specifies the hardware core on which the session runs
> * @session_id: id of current video session
> * @ctx_q_lock: lock to serialize queues related ioctls
> * @lock: lock to seralise forward and reverse threads
> @@ -79,6 +80,7 @@ struct iris_fmt {
> struct iris_inst {
> struct list_head list;
> struct iris_core *core;
> + u32 core_id;
> u32 session_id;
> struct mutex ctx_q_lock;/* lock to serialize queues related ioctls */
> struct mutex lock; /* lock to serialize forward and reverse threads */
> diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h
> index e3c1aff770dd..aeb70f54be10 100644
> --- a/drivers/media/platform/qcom/iris/iris_platform_common.h
> +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h
> @@ -258,6 +258,7 @@ struct iris_platform_data {
> const struct tz_cp_config *tz_cp_config_data;
> u32 tz_cp_config_data_size;
> u32 core_arch;
> + bool dual_core;
> u32 hw_response_timeout;
> struct ubwc_config_data *ubwc_config;
> u32 num_vpp_pipe;
> diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c
> index cfc5b576ec56..38ede9f76d0b 100644
> --- a/drivers/media/platform/qcom/iris/iris_utils.c
> +++ b/drivers/media/platform/qcom/iris/iris_utils.c
> @@ -90,18 +90,51 @@ struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id)
> return NULL;
> }
>
> -int iris_check_core_mbpf(struct iris_inst *inst)
> +static u32 iris_get_mbps(struct iris_inst *inst)
> {
> - struct iris_core *core = inst->core;
> - struct iris_inst *instance;
> - u32 total_mbpf = 0;
> + u32 fps = max(inst->frame_rate, inst->operating_rate);
> +
> + return iris_get_mbpf(inst) * fps;
> +}
> +
> +static void iris_get_core_load(struct iris_core *core, u32 *core_load, bool mbpf)
> +{
> + bool dual_core = core->iris_platform_data->dual_core;
> + struct iris_inst *inst;
> + u32 load;
>
> mutex_lock(&core->lock);
> - list_for_each_entry(instance, &core->instances, list)
> - total_mbpf += iris_get_mbpf(instance);
> + list_for_each_entry(inst, &core->instances, list) {
> + if (mbpf)
> + load = iris_get_mbpf(inst);
> + else
> + load = iris_get_mbps(inst);
> +
> + if (inst->core_id == BIT(0))
> + core_load[0] += load;
> + else if (dual_core && inst->core_id == BIT(1))
> + core_load[1] += load;
> + }
> mutex_unlock(&core->lock);
> +}
>
> - if (total_mbpf > core->iris_platform_data->max_core_mbpf)
> +int iris_check_core_mbpf(struct iris_inst *inst)
> +{
> + struct iris_core *core = inst->core;
> + u32 max_core_mbpf = core->iris_platform_data->max_core_mbpf;
> + bool dual_core = core->iris_platform_data->dual_core;
> + u32 core_mbpf[2] = {0, 0}, new_mbpf;
> +
> + inst->core_id = 0;
> + iris_get_core_load(core, core_mbpf, true);
> + new_mbpf = iris_get_mbpf(inst);
> +
> + if (core_mbpf[0] + new_mbpf <= max_core_mbpf)
> + inst->core_id = BIT(0);
> + else if (dual_core && core_mbpf[1] + new_mbpf <= max_core_mbpf)
> + inst->core_id = BIT(1);
> +
> + if (!inst->core_id)
> return -ENOMEM;
>
> return 0;
> @@ -110,17 +143,20 @@ int iris_check_core_mbpf(struct iris_inst *inst)
> int iris_check_core_mbps(struct iris_inst *inst)
> {
> struct iris_core *core = inst->core;
> - struct iris_inst *instance;
> - u32 total_mbps = 0, fps = 0;
> + u32 max_core_mbps = core->iris_platform_data->max_core_mbps;
> + bool dual_core = core->iris_platform_data->dual_core;
> + u32 core_mbps[2] = {0, 0}, new_mbps;
>
> - mutex_lock(&core->lock);
> - list_for_each_entry(instance, &core->instances, list) {
> - fps = max(instance->frame_rate, instance->operating_rate);
> - total_mbps += iris_get_mbpf(instance) * fps;
> - }
> - mutex_unlock(&core->lock);
> + inst->core_id = 0;
> + iris_get_core_load(core, core_mbps, false);
> + new_mbps = iris_get_mbps(inst);
> +
> + if (core_mbps[0] + new_mbps <= max_core_mbps)
> + inst->core_id = BIT(0);
> + else if (dual_core && core_mbps[1] + new_mbps <= max_core_mbps)
> + inst->core_id = BIT(1);
else return -ENOMEM.
But... Which of the checks will be used in the wild? Will it be
iris_check_core_mbpf() or iris_check_core_mbps()? What if they disagree?
>
> - if (total_mbps > core->iris_platform_data->max_core_mbps)
> + if (!inst->core_id)
> return -ENOMEM;
>
> return 0;
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH 2/2] iio: dac: mcp47feb02: add MCP48FEB02 SPI driver to MCP47FEB02 I2C driver
From: David Lechner @ 2026-04-14 15:48 UTC (permalink / raw)
To: Ariana.Lazar, robh, krzk+dt, jic23, nuno.sa, conor+dt, andy
Cc: Jonathan.Cameron, Conor.Dooley, devicetree, linux-iio,
linux-kernel
In-Reply-To: <4b289795ffe7ce3505087446a5f2aee053ace561.camel@microchip.com>
On 4/14/26 10:28 AM, Ariana.Lazar@microchip.com wrote:
> Hi David,
>
>>> --- a/drivers/iio/dac/Makefile
>>> +++ b/drivers/iio/dac/Makefile
>>> @@ -54,6 +54,9 @@ obj-$(CONFIG_MAX5821) += max5821.o
>>> obj-$(CONFIG_MCP4725) += mcp4725.o
>>> obj-$(CONFIG_MCP4728) += mcp4728.o
>>> obj-$(CONFIG_MCP47FEB02) += mcp47feb02.o
>>
>> Shouldn't we be removing this old file?
>>
>> The patch series would be eaiser to understand if it was split into
>> one commit to split the existing driver into two files and then
>> another commit to add support for the new parts.
>>
>>
>>> +mcp47feb02-objs := mcp47feb02-core.o
Ah, I missed this line.
>>> +obj-$(CONFIG_MCP47FEB02_I2C) += mcp47feb02-i2c.o
>>> +obj-$(CONFIG_MCP47FEB02_SPI) += mcp47feb02-spi.o
>>> obj-$(CONFIG_MCP4821) += mcp4821.o
>>> obj-$(CONFIG_MCP4922) += mcp4922.o
>>> obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
>>
>
> Thank you for the review.
>
> I kept that line so the core module would compile as 'mcp47feb02.ko'.
> If you prefer, I can rename the core file to mcp47feb02.c and add just
> the lines for the SPI and I2C modules in the Makefile.
It looks like there is only a few other driver that implement
it the way you have. And only a few others that don't have "core"
in the C file name.
>
> Another option would be to keep the core module named mcp47feb02-core.c
> and compile it as 'mcp47feb02-core.ko'.
It looks like this is the option most other drivers go with. So unless
there is a good reason to do otherwise, I would tend to go with the
most common pattern.
>
> Best regards,
> Ariana
^ permalink raw reply
* Re: [PATCH 1/2] dt-bindings: iio: dac: add support for Microchip MCP48FEB02 to MCP47FEB02
From: Conor Dooley @ 2026-04-14 15:34 UTC (permalink / raw)
To: Ariana.Lazar
Cc: dlechner, nuno.sa, Conor.Dooley, Jonathan.Cameron, robh, jic23,
andy, krzk+dt, linux-iio, conor+dt, linux-kernel, devicetree
In-Reply-To: <dd516b8155d9e782855f5e06e2260d57b596184b.camel@microchip.com>
[-- Attachment #1: Type: text/plain, Size: 973 bytes --]
On Tue, Apr 14, 2026 at 01:39:32PM +0000, Ariana.Lazar@microchip.com wrote:
> Hi Conor,
>
> > >
> > > patternProperties:
> > > @@ -161,8 +222,7 @@ patternProperties:
> > > properties:
> > > reg:
> > > description: The channel number.
> > > - minItems: 1
> > > - maxItems: 8
> > > + maxItems: 1
> >
> > Why is this changing? Was it originally a mistake and what you wanted
> > was a max of 8 but only one entry?
> >
> > >
>
>
> Thank you for the review.
>
> It was a mistake I missed in the devicetree
> binding for the mcp47feb02 driver. The property contains a single
> integer representing the channel number (0-7), as you said.
>
> Should I send a fix for the mcp47feb02 binding first or can I continue
> to rewrite/split mcp47feb02 driver into the core module with I2C
> protocol file and include this binding fix there too?
Do it separately please with a fixes tag and all that jazz.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* [PATCH v22 7/7] remoteproc: stm32: add OP-TEE backend support
From: Arnaud Pouliquen @ 2026-04-14 15:29 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
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
Integrate OP-TEE-controlled firmware loading into stm32_rproc
adding support for the st,rproc-tee devicetree property.
When st,rproc-tee is present, the driver:
- parses the backend phandle + ID from DT and validates it
- uses the remoteproc_tee operation set and registration path
- keeps reset/holdboot handling only for the non-TEE case
- uses a TEE-specific flow.
Notice that the attach/detach is not yet supported and should be part
of a separate patchset.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
V21 updates:
- reapply the V19 patch as the stm32_rproc-tee driver can no more
be used.
- update v19 patch to support the st,rproc-tee phandle.
- rework the commit message.
---
drivers/remoteproc/stm32_rproc.c | 167 +++++++++++++++++++++++--------
1 file changed, 123 insertions(+), 44 deletions(-)
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 4bcd6a784935..61d89f3a78b1 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -18,6 +18,7 @@
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
#include <linux/remoteproc.h>
+#include <linux/remoteproc_tee.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
@@ -89,6 +90,7 @@ struct stm32_rproc {
struct stm32_rproc_mem *rmems;
struct stm32_mbox mb[MBOX_NB_MBX];
struct workqueue_struct *workqueue;
+ struct of_phandle_args tee_phandle;
bool hold_boot_smc;
void __iomem *rsc_va;
};
@@ -255,6 +257,19 @@ static int stm32_rproc_release(struct rproc *rproc)
return 0;
}
+static int stm32_rproc_tee_stop(struct rproc *rproc)
+{
+ int err;
+
+ stm32_rproc_request_shutdown(rproc);
+
+ err = rproc_tee_stop(rproc);
+ if (err)
+ return err;
+
+ return stm32_rproc_release(rproc);
+}
+
static int stm32_rproc_prepare(struct rproc *rproc)
{
struct device *dev = rproc->dev.parent;
@@ -683,6 +698,17 @@ static const struct rproc_ops st_rproc_ops = {
.get_boot_addr = rproc_elf_get_boot_addr,
};
+static const struct rproc_ops st_rproc_tee_ops = {
+ .prepare = stm32_rproc_prepare,
+ .start = rproc_tee_start,
+ .stop = stm32_rproc_tee_stop,
+ .kick = stm32_rproc_kick,
+ .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,
+};
+
static const struct of_device_id stm32_rproc_match[] = {
{ .compatible = "st,stm32mp1-m4" },
{},
@@ -716,6 +742,7 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
+ struct of_phandle_args tee_phandle;
struct stm32_syscon tz;
unsigned int tzen;
int err, irq;
@@ -741,51 +768,69 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev,
dev_info(dev, "wdg irq registered\n");
}
- ddata->rst = devm_reset_control_get_optional(dev, "mcu_rst");
- if (!ddata->rst) {
- /* Try legacy fallback method: get it by index */
- ddata->rst = devm_reset_control_get_by_index(dev, 0);
+ if (of_find_property(np, "st,rproc-tee", NULL)) {
+ err = of_parse_phandle_with_fixed_args(np, "st,rproc-tee",
+ 1, 0, &tee_phandle);
+ if (err)
+ return dev_err_probe(dev, err,
+ "failed to parse st,rproc-tee\n");
+
+ if (!IS_ENABLED(CONFIG_REMOTEPROC_TEE)) {
+ of_node_put(tee_phandle.np);
+ return dev_err_probe(dev, -ENODEV,
+ "st,rproc-tee requires REMOTEPROC_TEE support\n");
+ }
+
+ ddata->tee_phandle = tee_phandle;
}
- if (IS_ERR(ddata->rst))
- return dev_err_probe(dev, PTR_ERR(ddata->rst),
- "failed to get mcu_reset\n");
- /*
- * Three ways to manage the hold boot
- * - using SCMI: the hold boot is managed as a reset
- * The DT "reset-mames" property should be defined with 2 items:
- * reset-names = "mcu_rst", "hold_boot";
- * - using SMC call (deprecated): use SMC reset interface
- * The DT "reset-mames" property is optional, "st,syscfg-tz" is required
- * - default(no SCMI, no SMC): the hold boot is managed as a syscon register
- * The DT "reset-mames" property is optional, "st,syscfg-holdboot" is required
- */
+ if (!ddata->tee_phandle.np) {
+ ddata->rst = devm_reset_control_get_optional(dev, "mcu_rst");
+ if (!ddata->rst) {
+ /* Try legacy fallback method: get it by index */
+ ddata->rst = devm_reset_control_get_by_index(dev, 0);
+ }
+ if (IS_ERR(ddata->rst))
+ return dev_err_probe(dev, PTR_ERR(ddata->rst),
+ "failed to get mcu_reset\n");
- ddata->hold_boot_rst = devm_reset_control_get_optional(dev, "hold_boot");
- if (IS_ERR(ddata->hold_boot_rst))
- return dev_err_probe(dev, PTR_ERR(ddata->hold_boot_rst),
- "failed to get hold_boot reset\n");
+ /*
+ * Three ways to manage the hold boot
+ * - using SCMI: the hold boot is managed as a reset
+ * The DT "reset-mames" property should be defined with 2 items:
+ * reset-names = "mcu_rst", "hold_boot";
+ * - using SMC call (deprecated): use SMC reset interface
+ * The DT "reset-mames" property is optional, "st,syscfg-tz" is required
+ * - default(no SCMI, no SMC): the hold boot is managed as a syscon register
+ * The DT "reset-mames" property is optional, "st,syscfg-holdboot" is required
+ */
- if (!ddata->hold_boot_rst && IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)) {
- /* Manage the MCU_BOOT using SMC call */
- err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
- if (!err) {
- err = regmap_read(tz.map, tz.reg, &tzen);
- if (err) {
- dev_err(dev, "failed to read tzen\n");
- return err;
+ ddata->hold_boot_rst = devm_reset_control_get_optional(dev, "hold_boot");
+ if (IS_ERR(ddata->hold_boot_rst))
+ return dev_err_probe(dev, PTR_ERR(ddata->hold_boot_rst),
+ "failed to get hold_boot reset\n");
+
+ if (!ddata->hold_boot_rst && IS_ENABLED(CONFIG_HAVE_ARM_SMCCC)) {
+ /* Manage the MCU_BOOT using SMC call */
+ err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz);
+ if (!err) {
+ err = regmap_read(tz.map, tz.reg, &tzen);
+ if (err) {
+ dev_err(dev, "failed to read tzen\n");
+ return err;
+ }
+ ddata->hold_boot_smc = tzen & tz.mask;
}
- ddata->hold_boot_smc = tzen & tz.mask;
}
- }
- if (!ddata->hold_boot_rst && !ddata->hold_boot_smc) {
- /* Default: hold boot manage it through the syscon controller */
- err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
- &ddata->hold_boot);
- if (err) {
- dev_err(dev, "failed to get hold boot\n");
- return err;
+ if (!ddata->hold_boot_rst && !ddata->hold_boot_smc) {
+ /* Default: hold boot manage it through the syscon controller */
+ err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot",
+ &ddata->hold_boot);
+ if (err) {
+ dev_err(dev, "failed to get hold boot\n");
+ return err;
+ }
}
}
@@ -857,18 +902,31 @@ static int stm32_rproc_probe(struct platform_device *pdev)
if (ret < 0 && ret != -EINVAL)
return ret;
- rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, fw_name, sizeof(*ddata));
+ if (of_find_property(np, "st,rproc-tee", NULL))
+ rproc = devm_rproc_alloc(dev, np->name, &st_rproc_tee_ops, fw_name,
+ sizeof(*ddata));
+ else
+ rproc = devm_rproc_alloc(dev, np->name, &st_rproc_ops, fw_name,
+ sizeof(*ddata));
+
if (!rproc)
return -ENOMEM;
ddata = rproc->priv;
-
rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE);
ret = stm32_rproc_parse_dt(pdev, ddata, &rproc->auto_boot);
if (ret)
goto free_rproc;
+ if (ddata->tee_phandle.np &&
+ !of_device_is_available(ddata->tee_phandle.np)) {
+ of_node_put(ddata->tee_phandle.np);
+ ddata->tee_phandle.np = NULL;
+ ret = -EPROBE_DEFER;
+ goto free_rproc;
+ }
+
ret = stm32_rproc_of_memory_translations(pdev, ddata);
if (ret)
goto free_rproc;
@@ -877,8 +935,14 @@ static int stm32_rproc_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;
- if (state == M4_STATE_CRUN)
+ if (state == M4_STATE_CRUN) {
+ if (ddata->tee_phandle.np) {
+ dev_err(dev, "TEE support not yet compatible with attached state\n");
+ ret = -EINVAL;
+ goto free_rproc;
+ }
rproc->state = RPROC_DETACHED;
+ }
rproc->has_iommu = false;
ddata->workqueue = create_workqueue(dev_name(dev));
@@ -894,10 +958,12 @@ static int stm32_rproc_probe(struct platform_device *pdev)
if (ret)
goto free_wkq;
- ret = rproc_add(rproc);
+ if (ddata->tee_phandle.np)
+ ret = rproc_tee_register(dev, rproc, &ddata->tee_phandle);
+ else
+ ret = rproc_add(rproc);
if (ret)
goto free_mb;
-
return 0;
free_mb:
@@ -911,6 +977,11 @@ static int stm32_rproc_probe(struct platform_device *pdev)
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
}
+ if (ddata->tee_phandle.np) {
+ of_node_put(ddata->tee_phandle.np);
+ ddata->tee_phandle.np = NULL;
+ }
+
return ret;
}
@@ -919,11 +990,11 @@ static void stm32_rproc_remove(struct platform_device *pdev)
struct rproc *rproc = platform_get_drvdata(pdev);
struct stm32_rproc *ddata = rproc->priv;
struct device *dev = &pdev->dev;
+ struct device_node *tee_np = ddata->tee_phandle.np;
if (atomic_read(&rproc->power) > 0)
rproc_shutdown(rproc);
- rproc_del(rproc);
stm32_rproc_free_mbox(rproc);
destroy_workqueue(ddata->workqueue);
@@ -931,6 +1002,14 @@ static void stm32_rproc_remove(struct platform_device *pdev)
dev_pm_clear_wake_irq(dev);
device_init_wakeup(dev, false);
}
+
+ if (tee_np) {
+ ddata->tee_phandle.np = NULL;
+ rproc_tee_unregister(dev, rproc);
+ of_node_put(tee_np);
+ } else {
+ rproc_del(rproc);
+ }
}
static int stm32_rproc_suspend(struct device *dev)
--
2.43.0
^ permalink raw reply related
* [PATCH v22 5/7] remoteproc: Add TEE support
From: Arnaud Pouliquen @ 2026-04-14 15:29 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
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
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 22 updates:
- Revert to version 19, as the st,stm32-rproc-tee compatible has been
rejected. As a consequence, we cannot have a rproc_stm32-tee.c driver
and must reuse the rproc_stm32.c driver.
- Protect rproc_to_trproc() with lockdep_assert_held().
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 | 789 ++++++++++++++++++++++++++++
include/linux/remoteproc_tee.h | 98 ++++
4 files changed, 898 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..b4e01ad84010
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_tee.c
@@ -0,0 +1,789 @@
+// 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;
+
+ lockdep_assert_held(&ctx_lock);
+
+ 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;
+
+ /* A missing resource table is valid for some firmware images. */
+ if (!table_sz) {
+ rproc->table_ptr = NULL;
+ rproc->table_sz = 0;
+ return 0;
+ }
+
+ /*
+ * 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);
+
+/**
+ * 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)
+ *
+ * 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)
+{
+ 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 tee_client_device *tee_device;
+ struct device_link *link;
+ struct rproc_tee *trproc;
+ 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;
+ }
+
+ 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_trproc;
+ }
+
+ trproc->rproc_id = rproc_id;
+ trproc->session_id = sess_arg.session;
+
+ ret = rproc_add(rproc);
+ if (ret)
+ goto close_tee;
+
+ trproc->rproc = 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_rcu(&trproc->node, &rproc_tee_ctx.rproc_list);
+
+ mutex_unlock(&ctx_lock);
+
+ return 0;
+
+del_rproc:
+ rproc_del(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_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(),
+ * 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);
+
+ 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..8cf805f3b65e
--- /dev/null
+++ b/include/linux/remoteproc_tee.h
@@ -0,0 +1,98 @@
+/* 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);
+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)
+{
+ 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 int rproc_tee_pa_to_da(struct rproc *rproc, phys_addr_t pa,
+ size_t size, u64 *da)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+
+ return -EINVAL;
+}
+
+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
* [PATCH v22 3/7] remoteproc: core: Introduce rproc_pa_to_va helper
From: Arnaud Pouliquen @ 2026-04-14 15:28 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
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
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>
---
V22 updates:
- use size_t for offset and remove its comparaison with 0
---
drivers/remoteproc/remoteproc_core.c | 50 ++++++++++++++++++++++++++++
include/linux/remoteproc.h | 1 +
2 files changed, 51 insertions(+)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index b087ed21858a..ec1860e1cfa9 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -225,6 +225,56 @@ 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 @pa 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;
+ size_t offset;
+
+ list_for_each_entry(carveout, &rproc->carveouts, node) {
+ /* Verify that carveout is allocated */
+ if (!carveout->va)
+ continue;
+
+ /* try next carveout if pa is too small */
+ if (pa < carveout->dma)
+ continue;
+
+ offset = pa - carveout->dma;
+
+ /* try next carveout if pa is too large */
+ if (offset > carveout->len)
+ continue;
+
+ if (len > carveout->len - offset)
+ 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
* [PATCH v22 6/7] remoteproc: stm32: Create sub-functions to request shutdown and release
From: Arnaud Pouliquen @ 2026-04-14 15:29 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
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
To prepare for the support of TEE remoteproc, create sub-functions
that can be used in both cases, with and without remoteproc TEE support.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
drivers/remoteproc/stm32_rproc.c | 82 +++++++++++++++++++-------------
1 file changed, 49 insertions(+), 33 deletions(-)
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index 632614013dc6..4bcd6a784935 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -209,6 +209,52 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name)
return -EINVAL;
}
+static void stm32_rproc_request_shutdown(struct rproc *rproc)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ int err, idx;
+
+ /* Request shutdown of the remote processor */
+ if (rproc->state != RPROC_OFFLINE && rproc->state != RPROC_CRASHED) {
+ idx = stm32_rproc_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_release(struct rproc *rproc)
+{
+ struct stm32_rproc *ddata = rproc->priv;
+ int err = 0;
+
+ /* To allow platform Standby power mode, set remote proc Deep Sleep */
+ if (ddata->pdds.map) {
+ err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg,
+ ddata->pdds.mask, 1);
+ if (err) {
+ dev_err(&rproc->dev, "failed to set pdds\n");
+ return err;
+ }
+ }
+
+ /* Update coprocessor state to OFF if available */
+ if (ddata->m4_state.map) {
+ err = regmap_update_bits(ddata->m4_state.map,
+ ddata->m4_state.reg,
+ ddata->m4_state.mask,
+ M4_STATE_OFF);
+ if (err) {
+ dev_err(&rproc->dev, "failed to set copro state\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
static int stm32_rproc_prepare(struct rproc *rproc)
{
struct device *dev = rproc->dev.parent;
@@ -511,17 +557,9 @@ static int stm32_rproc_detach(struct rproc *rproc)
static int stm32_rproc_stop(struct rproc *rproc)
{
struct stm32_rproc *ddata = rproc->priv;
- int err, idx;
+ int err;
- /* request shutdown of the remote processor */
- if (rproc->state != RPROC_OFFLINE && rproc->state != RPROC_CRASHED) {
- idx = stm32_rproc_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");
- }
- }
+ stm32_rproc_request_shutdown(rproc);
err = stm32_rproc_set_hold_boot(rproc, true);
if (err)
@@ -533,29 +571,7 @@ static int stm32_rproc_stop(struct rproc *rproc)
return err;
}
- /* to allow platform Standby power mode, set remote proc Deep Sleep */
- if (ddata->pdds.map) {
- err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg,
- ddata->pdds.mask, 1);
- if (err) {
- dev_err(&rproc->dev, "failed to set pdds\n");
- return err;
- }
- }
-
- /* update coprocessor state to OFF if available */
- if (ddata->m4_state.map) {
- err = regmap_update_bits(ddata->m4_state.map,
- ddata->m4_state.reg,
- ddata->m4_state.mask,
- M4_STATE_OFF);
- if (err) {
- dev_err(&rproc->dev, "failed to set copro state\n");
- return err;
- }
- }
-
- return 0;
+ return stm32_rproc_release(rproc);
}
static void stm32_rproc_kick(struct rproc *rproc, int vqid)
--
2.43.0
^ permalink raw reply related
* [PATCH v22 4/7] remoteproc: Introduce optional release_fw operation
From: Arnaud Pouliquen @ 2026-04-14 15:28 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
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
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 ec1860e1cfa9..93ab505ff014 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1856,6 +1856,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);
@@ -1997,6 +1999,8 @@ int rproc_boot(struct rproc *rproc)
}
ret = rproc_fw_boot(rproc, firmware_p);
+ if (ret)
+ rproc_release_fw(rproc);
release_firmware(firmware_p);
}
@@ -2066,6 +2070,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
* [PATCH v22 2/7] dt-bindings: remoteproc: st,stm32-rproc: add st,rproc-tee
From: Arnaud Pouliquen @ 2026-04-14 15:28 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
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
Add st,rproc-tee to describe the remoteprocessor control through the TEE
remoteproc backend.
The property is a phandle to the TEE remoteproc node with one argument
cell carrying the remote processor identifier.
When st,rproc-tee is present, Linux must not manage MCU reset/holdboot
directly. Update schema conditionals accordingly:
- do not require resets unconditionally
- forbid resets, reset-names and st,syscfg-holdboot when st,rproc-tee
is present
- keep legacy holdboot checks for non-TEE configurations
Also add a DT example showing the TEE-based configuration.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>
---
.../bindings/remoteproc/st,stm32-rproc.yaml | 55 ++++++++++++++++---
1 file changed, 46 insertions(+), 9 deletions(-)
diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml
index 843679c557e7..7fe54d529e04 100644
--- a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml
+++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml
@@ -143,24 +143,45 @@ properties:
maxItems: 1
description: Default name of the remote processor firmware.
+ st,rproc-tee:
+ description:
+ Reference the remote processor node on TEE bus. The value is a phandle
+ reference to the remote processor node, followed by a cell specifying
+ the remote processor device identifier used by the TEE.
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ - items:
+ - description: Phandle of the remote processor node on the TEE bus
+ - description: Remote processor device identifier used by the TEE
+
required:
- compatible
- reg
- - resets
allOf:
- if:
- properties:
- reset-names:
- not:
- contains:
- const: hold_boot
- then:
required:
- - st,syscfg-holdboot
- else:
+ - st,rproc-tee
+ then:
properties:
+ resets: false
+ reset-names: false
st,syscfg-holdboot: false
+ else:
+ required:
+ - resets
+ if:
+ properties:
+ reset-names:
+ not:
+ contains:
+ const: hold_boot
+ then:
+ required:
+ - st,syscfg-holdboot
+ else:
+ properties:
+ st,syscfg-holdboot: false
additionalProperties: false
@@ -192,5 +213,21 @@ examples:
st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>;
st,syscfg-m4-state = <&tamp 0x148 0xFFFFFFFF>;
};
+ - |
+ firmware {
+ tee_rproc: optee-rproc {
+ compatible = "80a4c275-0a47-4905-8285-1486a9771a08";
+ };
+ };
+
+ m4@10000000 {
+ compatible = "st,stm32mp1-m4";
+ reg = <0x10000000 0x40000>,
+ <0x30000000 0x40000>,
+ <0x38000000 0x10000>;
+ st,rproc-tee = <&tee_rproc 0>;
+ st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>;
+ st,syscfg-m4-state = <&tamp 0x148 0xFFFFFFFF>;
+ };
...
--
2.43.0
^ permalink raw reply related
* [PATCH v22 1/7] dt-bindings: firmware: Add TEE remoteproc service binding
From: Arnaud Pouliquen @ 2026-04-14 15:28 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
In-Reply-To: <20260414152904.1679724-1-arnaud.pouliquen@foss.st.com>
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 updates:
- 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..498a7e590905
--- /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
* [PATCH v22 0/7] Introduction of a remoteproc tee to load signed firmware
From: Arnaud Pouliquen @ 2026-04-14 15:28 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 V21[1]:
--------------------------------
This version removes the st,stm32mp1-m4-tee compatibility string,
which no longer seems to be accepted by the Devicetree maintainers.
As a consequence, the stm32-rproc-tee driver, introduced to simplify
the code, is removed. The STM32 integration reuses the existing
stm32_rproc driver implemented in V19.
The devicetree is now structured as follows:
firmware {
tee_rproc: optee-rproc {
compatible = "80a4c275-0a47-4905-8285-1486a9771a08";
};
};
m4: m4@10000000 {
compatible = "st,stm32mp1-m4";
reg = <0x10000000 0x40000>,
<0x30000000 0x40000>,
<0x38000000 0x10000>;
mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>, <&ipcc 3>;
mbox-names = "vq0", "vq1", "shutdown", "detach";
memory-region = <&vdev0vring0>, <&m_ipc_shm>, <&mcuram2>,
<&vdev0vring1>, <&vdev0buffer>, <&retram>;
interrupt-parent = <&exti>;
interrupts = <68 1>;
st,rproc-tee = <&tee_rproc 0>;
status = "okay";
};
As a consequence, this version:
- reintroduce v19 commits for stm32_rproc.c driver , adding the support
of the st,rproc-tee binding.
- drops the dedicated remoteproc-tee.yaml and st,stm32-rproc-tee.yaml
bindings from the series.
- extends st,stm32-rproc.yaml with st,rproc-tee to describe the link to
the TEE remoteproc backend.
- removes the dedicated stm32_rproc_tee.c driver and reuses stm32_rproc.c
for both native and TEE-controlled cases.
- keeps remoteproc_tee.c aligned with the phandle-based lookup introduced
in v21 and uses a device_link between the STM32 remoteproc instance and
the TEE backend device.
More details are available in each patch commit message.
Main updates from version V20[3]:
--------------------------------
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[4]:
--------------------------------
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.
More details are available in each patch commit message.
[1] https://lore.kernel.org/linux-remoteproc/20260317180329.1207625-1-arnaud.pouliquen@foss.st.com/
[2] https://lore.kernel.org/linux-remoteproc/20251217153917.3998544-1-arnaud.pouliquen@foss.st.com/
[3] https://lore.kernel.org/linux-devicetree/20250625094028.758016-1-arnaud.pouliquen@foss.st.com/
Tested-on:
---------
commit 591cd656a1bf ("Linux 7.0-rc7")
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 (7):
dt-bindings: firmware: Add TEE remoteproc service binding
dt-bindings: remoteproc: st,stm32-rproc: add st,rproc-tee
remoteproc: core: Introduce rproc_pa_to_va helper
remoteproc: Introduce optional release_fw operation
remoteproc: Add TEE support
remoteproc: stm32: Create sub-functions to request shutdown and
release
remoteproc: stm32: Add support of an OP-TEE TA to load the firmware
.../bindings/remoteproc/remoteproc-tee.yaml | 36 +
.../bindings/remoteproc/st,stm32-rproc.yaml | 55 +-
drivers/remoteproc/Kconfig | 10 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/remoteproc_core.c | 56 ++
drivers/remoteproc/remoteproc_internal.h | 6 +
drivers/remoteproc/remoteproc_tee.c | 789 ++++++++++++++++++
drivers/remoteproc/stm32_rproc.c | 249 ++++--
include/linux/remoteproc.h | 6 +
include/linux/remoteproc_tee.h | 98 +++
10 files changed, 1220 insertions(+), 86 deletions(-)
create mode 100644 Documentation/devicetree/bindings/remoteproc/remoteproc-tee.yaml
create mode 100644 drivers/remoteproc/remoteproc_tee.c
create mode 100644 include/linux/remoteproc_tee.h
base-commit: 591cd656a1bf5ea94a222af5ef2ee76df029c1d2
--
2.43.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox