* [PATCH v26 6/7] arm64: dts: imx8ulp: add secure enclave node
From: pankaj.gupta @ 2026-06-29 12:22 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Pankaj Gupta
Cc: linux-doc, linux-kernel, devicetree, imx, linux-arm-kernel
In-Reply-To: <20260629-imx-se-if-v26-0-146446285744@nxp.com>
From: Pankaj Gupta <pankaj.gupta@nxp.com>
Add support for NXP secure enclave called EdgeLock Enclave firmware (se-fw)
for imx8ulp-evk.
Add label sram0 for sram@2201f000 and add secure-enclave node
Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
---
arch/arm64/boot/dts/freescale/imx8ulp.dtsi | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
index c6d1bb9edf38..933127f870c6 100644
--- a/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8ulp.dtsi
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
- * Copyright 2021 NXP
+ * Copyright 2021, 2025 NXP
*/
#include <dt-bindings/clock/imx8ulp-clock.h>
@@ -153,7 +153,7 @@ sosc: clock-sosc {
#clock-cells = <0>;
};
- sram@2201f000 {
+ sram0: sram@2201f000 {
compatible = "mmio-sram";
reg = <0x0 0x2201f000 0x0 0x1000>;
@@ -185,6 +185,13 @@ scmi_sensor: protocol@15 {
#thermal-sensor-cells = <1>;
};
};
+
+ hsm0: secure-enclave {
+ compatible = "fsl,imx8ulp-se-ele-hsm";
+ mbox-names = "tx", "rx";
+ mboxes = <&s4muap 0 0>, <&s4muap 1 0>;
+ sram = <&sram0>;
+ };
};
cm33: remoteproc-cm33 {
--
2.43.0
^ permalink raw reply related
* [PATCH v2 1/4] dt-bindings: connector: Add fsl,aud-io-slot binding
From: chancel.liu @ 2026-06-29 7:47 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, Frank.Li, s.hauer
Cc: kernel, festevam, devicetree, linux-kernel, imx, linux-arm-kernel
In-Reply-To: <20260629074734.3643227-1-chancel.liu@oss.nxp.com>
From: Chancel Liu <chancel.liu@nxp.com>
The NXP AUD-IO slot represents a physically present I/O connector on
the base board. It acts as a nexus that exposes a constrained set of
I/O resources, such as GPIOs, clocks and interrupts, through fixed
electrical wiring. All actual hardware providers reside on the base
board. The connector node only defines index-based mappings to those
providers.
This connector type is present on i.MX95 19x19 EVK and i.MX952 EVK,
where it is used to attach the IMX-AUD-IO audio expansion card[1]. The
same add-on board can be reused across different base boards that carry
this connector.
[1]https://www.nxp.com/part/IMX-AUD-IO
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
.../bindings/connector/fsl,aud-io-slot.yaml | 113 ++++++++++++++++++
1 file changed, 113 insertions(+)
create mode 100644 Documentation/devicetree/bindings/connector/fsl,aud-io-slot.yaml
diff --git a/Documentation/devicetree/bindings/connector/fsl,aud-io-slot.yaml b/Documentation/devicetree/bindings/connector/fsl,aud-io-slot.yaml
new file mode 100644
index 000000000000..5085574d221b
--- /dev/null
+++ b/Documentation/devicetree/bindings/connector/fsl,aud-io-slot.yaml
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/connector/fsl,aud-io-slot.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP AUD-IO Slot
+
+maintainers:
+ - Frank Li <Frank.li@nxp.com>
+ - Chancel Liu <chancel.liu@nxp.com>
+
+description:
+ The NXP AUD-IO slot represents a physically present I/O connector on
+ the base board. It acts as a nexus that exposes a constrained set of
+ I/O resources, such as GPIOs, clocks and interrupts, through fixed
+ electrical wiring. All actual hardware providers reside on the base
+ board. The connector node only defines index-based mappings to those
+ providers. This connector type is present on i.MX95 19x19 EVK and
+ i.MX952 EVK, where it is used to attach the IMX-AUD-IO expansion card.
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - enum:
+ - fsl,imx952-evk-aud-io
+ - const: fsl,imx95-19x19-evk-aud-io
+ - const: fsl,imx95-19x19-evk-aud-io
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+ gpio-map:
+ minItems: 1
+ maxItems: 32
+
+ gpio-map-mask:
+ items:
+ - const: 0xffff
+ - const: 0x0
+
+ gpio-map-pass-thru:
+ items:
+ - const: 0x0
+ - const: 0x1
+
+ '#clock-cells':
+ const: 1
+
+ clock-map:
+ minItems: 1
+ maxItems: 16
+
+ clock-map-mask:
+ items:
+ - const: 0xff
+
+ clock-map-pass-thru: true
+
+ '#address-cells':
+ const: 0
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 2
+
+ interrupt-map:
+ minItems: 1
+ maxItems: 32
+
+ interrupt-map-mask:
+ items:
+ - const: 0xffff
+ - const: 0x0
+
+allOf:
+ - $ref: /schemas/gpio/gpio-nexus-node.yaml#
+ - $ref: /schemas/clock/clock-nexus-node.yaml#
+
+required:
+ - compatible
+ - gpio-controller
+ - '#gpio-cells'
+ - gpio-map
+ - gpio-map-mask
+ - gpio-map-pass-thru
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ connector {
+ compatible = "fsl,imx95-19x19-evk-aud-io";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-map = <0 0 &gpio1 8 1>;
+ gpio-map-mask = <0xffff 0x0>;
+ gpio-map-pass-thru = <0x0 0x1>;
+ #clock-cells = <1>;
+ clock-map = <0 &clk 1>;
+ clock-map-mask = <0xff>;
+ #address-cells = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-map-mask = <0xffff 0x0>;
+ interrupt-map = <0 0 &gpio2 27 IRQ_TYPE_LEVEL_LOW>;
+ };
--
2.50.1
^ permalink raw reply related
* [PATCH v2 2/4] arm64: dts: freescale: imx95-19x19-evk: Add IMX-AUD-IO board support
From: chancel.liu @ 2026-06-29 7:47 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, Frank.Li, s.hauer
Cc: kernel, festevam, devicetree, linux-kernel, imx, linux-arm-kernel
In-Reply-To: <20260629074734.3643227-1-chancel.liu@oss.nxp.com>
From: Chancel Liu <chancel.liu@nxp.com>
IMX-AUD-IO is an add-on board which can be connected to i.MX95 19x19
EVK through a physical connector. This connector is described as a
fsl,aud-io-slot connector to expose a constrained subset of GPIO and
clock resources to the add-on board using fixed electrical wiring.
Also add required regulator, sound CPU DAI and I2C bus configuration to
support IMX-AUD-IO on this base board.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
.../boot/dts/freescale/imx95-19x19-evk.dts | 55 ++++++++++++++++++-
1 file changed, 53 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts
index 2e463bc7c601..f5ca8edf74af 100644
--- a/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx95-19x19-evk.dts
@@ -43,6 +43,19 @@ aliases {
serial4 = &lpuart5;
};
+ aud_io_slot: connector {
+ compatible = "fsl,imx95-19x19-evk-aud-io";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-map = <0 0 &i2c6_pcal6416 8 1>;
+ gpio-map-mask = <0xffff 0x0>;
+ /* Only pass through GPIO polarity flag bit 0. */
+ gpio-map-pass-thru = <0x0 0x1>;
+ #clock-cells = <1>;
+ clock-map = <0 &scmi_clk IMX95_CLK_SAI2>;
+ clock-map-mask = <0xff>;
+ };
+
bt_sco_codec: audio-codec-bt-sco {
#sound-dai-cells = <1>;
compatible = "linux,bt-sco";
@@ -94,7 +107,7 @@ flexcan2_phy: can-phy1 {
standby-gpios = <&i2c4_gpio_expander_21 3 GPIO_ACTIVE_LOW>;
};
- reg_vref_1v8: regulator-1p8v {
+ aud_io_reg_1v8: reg_vref_1v8: regulator-1p8v {
compatible = "regulator-fixed";
regulator-max-microvolt = <1800000>;
regulator-min-microvolt = <1800000>;
@@ -108,6 +121,22 @@ reg_3p3v: regulator-3p3v {
regulator-name = "+V3.3_SW";
};
+ aud_io_reg_3v3: regulator-aud-io-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "aud-io-3v3";
+ regulator-max-microvolt = <3300000>;
+ regulator-min-microvolt = <3300000>;
+ gpio = <&i2c6_pcal6416 11 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ aud_io_reg_5v: regulator-aud-io-5v {
+ compatible = "regulator-fixed";
+ regulator-name = "aud-io-5v";
+ regulator-max-microvolt = <5000000>;
+ regulator-min-microvolt = <5000000>;
+ };
+
reg_audio_pwr: regulator-audio-pwr {
compatible = "regulator-fixed";
regulator-name = "audio-pwr";
@@ -382,7 +411,7 @@ i2c5_pcal6408: gpio@21 {
};
};
-&lpi2c6 {
+aud_io_i2c: &lpi2c6 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpi2c6>;
@@ -598,6 +627,28 @@ &sai1 {
status = "okay";
};
+aud_io_cpu: &sai2 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai2>;
+ clocks = <&scmi_clk IMX95_CLK_BUSNETCMIX>, <&dummy>,
+ <&scmi_clk IMX95_CLK_SAI2>, <&dummy>,
+ <&dummy>, <&scmi_clk IMX95_CLK_AUDIOPLL1>,
+ <&scmi_clk IMX95_CLK_AUDIOPLL2>;
+ clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k", "pll11k";
+ assigned-clocks = <&scmi_clk IMX95_CLK_AUDIOPLL1_VCO>,
+ <&scmi_clk IMX95_CLK_AUDIOPLL2_VCO>,
+ <&scmi_clk IMX95_CLK_AUDIOPLL1>,
+ <&scmi_clk IMX95_CLK_AUDIOPLL2>,
+ <&scmi_clk IMX95_CLK_SAI2>;
+ assigned-clock-parents = <0>, <0>, <0>, <0>,
+ <&scmi_clk IMX95_CLK_AUDIOPLL1>;
+ assigned-clock-rates = <3932160000>, <3612672000>,
+ <393216000>, <361267200>, <12288000>;
+ fsl,sai-mclk-direction-output;
+ fsl,sai-asynchronous;
+};
+
&sai3 {
#sound-dai-cells = <0>;
pinctrl-names = "default";
--
2.50.1
^ permalink raw reply related
* [PATCH v2 3/4] arm64: dts: freescale: imx952-evk: Add IMX-AUD-IO board support
From: chancel.liu @ 2026-06-29 7:47 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, Frank.Li, s.hauer
Cc: kernel, festevam, devicetree, linux-kernel, imx, linux-arm-kernel
In-Reply-To: <20260629074734.3643227-1-chancel.liu@oss.nxp.com>
From: Chancel Liu <chancel.liu@nxp.com>
IMX-AUD-IO is an add-on board which can be connected to i.MX952 EVK
through a physical connector. This connector is described as a
fsl,aud-io-slot connector to expose a constrained subset of GPIO and
clock resources to the add-on board using fixed electrical wiring.
Also add required regulator, sound CPU DAI and I2C bus configuration to
support IMX-AUD-IO on this base board.
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
arch/arm64/boot/dts/freescale/imx952-evk.dts | 70 +++++++++++++++++++-
1 file changed, 68 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx952-evk.dts b/arch/arm64/boot/dts/freescale/imx952-evk.dts
index 62d1c1c7c501..80480c802f19 100644
--- a/arch/arm64/boot/dts/freescale/imx952-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx952-evk.dts
@@ -43,6 +43,19 @@ aliases {
spi6 = &lpspi7;
};
+ aud_io_slot: connector {
+ compatible = "fsl,imx952-evk-aud-io", "fsl,imx95-19x19-evk-aud-io";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-map = <0 0 &pcal6416 8 1>;
+ gpio-map-mask = <0xffff 0x0>;
+ /* Only pass through GPIO polarity flag bit 0. */
+ gpio-map-pass-thru = <0x0 0x1>;
+ #clock-cells = <1>;
+ clock-map = <0 &scmi_clk IMX952_CLK_SAI2>;
+ clock-map-mask = <0xff>;
+ };
+
bt_sco_codec: audio-codec-bt-sco {
#sound-dai-cells = <1>;
compatible = "linux,bt-sco";
@@ -114,13 +127,29 @@ reg_1p8v: regulator-1p8v {
regulator-name = "+V1.8_SW";
};
- reg_vref_1v8: regulator-adc-vref {
+ aud_io_reg_1v8: reg_vref_1v8: regulator-adc-vref {
compatible = "regulator-fixed";
regulator-name = "vref_1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
+ aud_io_reg_3v3: regulator-aud-io-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "aud-io-3v3";
+ regulator-max-microvolt = <3300000>;
+ regulator-min-microvolt = <3300000>;
+ gpio = <&pcal6416 11 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ aud_io_reg_5v: regulator-aud-io-5v {
+ compatible = "regulator-fixed";
+ regulator-name = "aud-io-5v";
+ regulator-max-microvolt = <5000000>;
+ regulator-min-microvolt = <5000000>;
+ };
+
reg_audio_pwr: regulator-audio-pwr {
compatible = "regulator-fixed";
regulator-name = "audio-pwr";
@@ -323,7 +352,7 @@ i2c4_pcal6408: gpio@21 {
};
};
-&lpi2c6 {
+aud_io_i2c: &lpi2c6 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpi2c6>;
@@ -468,6 +497,27 @@ &sai1 {
status = "okay";
};
+aud_io_cpu: &sai2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai2>;
+ clocks = <&scmi_clk IMX952_CLK_BUSNETCMIX>, <&clk_dummy>,
+ <&scmi_clk IMX952_CLK_SAI2>, <&clk_dummy>,
+ <&clk_dummy>, <&scmi_clk IMX952_CLK_AUDIOPLL1>,
+ <&scmi_clk IMX952_CLK_AUDIOPLL2>;
+ clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k", "pll11k";
+ assigned-clocks = <&scmi_clk IMX952_CLK_AUDIOPLL1_VCO>,
+ <&scmi_clk IMX952_CLK_AUDIOPLL2_VCO>,
+ <&scmi_clk IMX952_CLK_AUDIOPLL1>,
+ <&scmi_clk IMX952_CLK_AUDIOPLL2>,
+ <&scmi_clk IMX952_CLK_SAI2>;
+ assigned-clock-parents = <0>, <0>, <0>, <0>,
+ <&scmi_clk IMX952_CLK_AUDIOPLL1>;
+ assigned-clock-rates = <3932160000>, <3612672000>,
+ <393216000>, <361267200>, <12288000>;
+ fsl,sai-mclk-direction-output;
+ fsl,sai-asynchronous;
+};
+
&sai3 {
assigned-clocks = <&scmi_clk IMX952_CLK_AUDIOPLL1_VCO>,
<&scmi_clk IMX952_CLK_AUDIOPLL2_VCO>,
@@ -688,6 +738,22 @@ IMX952_PAD_SAI1_TXD0__AONMIX_TOP_GPIO1_IO_13 0x51e
>;
};
+ pinctrl_sai2: sai2grp {
+ fsl,pins = <
+ IMX952_PAD_ENET2_MDIO__NETCMIX_TOP_SAI2_RX_BCLK 0x31e
+ IMX952_PAD_ENET2_MDC__NETCMIX_TOP_SAI2_RX_SYNC 0x31e
+ IMX952_PAD_ENET2_TD3__NETCMIX_TOP_SAI2_RX_DATA_0 0x31e
+ IMX952_PAD_ENET2_TD2__NETCMIX_TOP_SAI2_RX_DATA_1 0x31e
+ IMX952_PAD_ENET2_TXC__NETCMIX_TOP_SAI2_TX_BCLK 0x31e
+ IMX952_PAD_ENET2_TX_CTL__NETCMIX_TOP_SAI2_TX_SYNC 0x31e
+ IMX952_PAD_ENET2_RX_CTL__NETCMIX_TOP_SAI2_TX_DATA_0 0x31e
+ IMX952_PAD_ENET2_RXC__NETCMIX_TOP_SAI2_TX_DATA_1 0x31e
+ IMX952_PAD_ENET2_RD0__NETCMIX_TOP_SAI2_TX_DATA_2 0x31e
+ IMX952_PAD_ENET2_RD1__NETCMIX_TOP_SAI2_TX_DATA_3 0x31e
+ IMX952_PAD_ENET2_RD2__NETCMIX_TOP_SAI2_MCLK 0x31e
+ >;
+ };
+
pinctrl_sai3: sai3grp {
fsl,pins = <
IMX952_PAD_GPIO_IO17__WAKEUPMIX_TOP_SAI3_MCLK 0x31e
--
2.50.1
^ permalink raw reply related
* [PATCH v2 4/4] arm64: dts: freescale: Add common DTS overlay for IMX-AUD-IO add-on board
From: chancel.liu @ 2026-06-29 7:47 UTC (permalink / raw)
To: robh, krzk+dt, conor+dt, Frank.Li, s.hauer
Cc: kernel, festevam, devicetree, linux-kernel, imx, linux-arm-kernel
In-Reply-To: <20260629074734.3643227-1-chancel.liu@oss.nxp.com>
From: Chancel Liu <chancel.liu@nxp.com>
Add common DTS overlay for the IMX-AUD-IO add-on board[1] which
connects to the base board through a fsl,aud-io-slot connector.
This board features a CS42888 codec providing 2 microphone inputs, 2
line inputs and 6 channels audio output capability.
[1]https://www.nxp.com/part/IMX-AUD-IO
Signed-off-by: Chancel Liu <chancel.liu@nxp.com>
---
arch/arm64/boot/dts/freescale/Makefile | 4 ++
arch/arm64/boot/dts/freescale/imx-aud-io.dtso | 57 +++++++++++++++++++
2 files changed, 61 insertions(+)
create mode 100644 arch/arm64/boot/dts/freescale/imx-aud-io.dtso
diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 8ddaab127ab9..f2417c20300c 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -672,11 +672,15 @@ dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-pcie0-ep.dtb
imx95-19x19-evk-pcie0-ep-dtbs += imx95-19x19-evk.dtb imx-pcie0-ep.dtbo
imx95-19x19-evk-pcie1-ep-dtbs += imx95-19x19-evk.dtb imx-pcie1-ep.dtbo
dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk-pcie0-ep.dtb imx95-19x19-evk-pcie1-ep.dtb
+imx95-19x19-evk-aud-io-dtbs += imx95-19x19-evk.dtb imx-aud-io.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk-aud-io.dtb
dtb-$(CONFIG_ARCH_MXC) += imx95-libra-rdk-fpsc.dtb
dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-verdin-evk.dtb
dtb-$(CONFIG_ARCH_MXC) += imx952-evk.dtb
+imx952-evk-aud-io-dtbs += imx952-evk.dtb imx-aud-io.dtbo
+dtb-$(CONFIG_ARCH_MXC) += imx952-evk-aud-io.dtb
imx8mm-kontron-dl-dtbs := imx8mm-kontron-bl.dtb imx8mm-kontron-dl.dtbo
imx8mm-kontron-bl-lte-dtbs := imx8mm-kontron-bl.dtb imx8mm-kontron-bl-lte.dtbo
diff --git a/arch/arm64/boot/dts/freescale/imx-aud-io.dtso b/arch/arm64/boot/dts/freescale/imx-aud-io.dtso
new file mode 100644
index 000000000000..311b7f984576
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx-aud-io.dtso
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Common Device Tree for the IMX-AUD-IO add-on board[1].
+ * It connects to the base board through an AUD-IO slot.
+ *
+ * [1]https://www.nxp.com/part/IMX-AUD-IO
+ *
+ * Copyright 2026 NXP
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&{/} {
+ aud-io-sound-cs42888 {
+ compatible = "fsl,imx-audio-card";
+ model = "imx-cs42888";
+
+ pri-dai-link {
+ link-name = "cs42888";
+ format = "i2s";
+ fsl,mclk-equal-bclk;
+
+ codec {
+ sound-dai = <&audio_io_codec>;
+ };
+
+ cpu {
+ sound-dai = <&aud_io_cpu>;
+ };
+ };
+ };
+};
+
+&aud_io_i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ audio_io_codec: codec@48 {
+ compatible = "cirrus,cs42888";
+ reg = <0x48>;
+ clocks = <&aud_io_slot 0>;
+ clock-names = "mclk";
+ VA-supply = <&aud_io_reg_5v>;
+ VD-supply = <&aud_io_reg_3v3>;
+ VLS-supply = <&aud_io_reg_1v8>;
+ VLC-supply = <&aud_io_reg_1v8>;
+ #sound-dai-cells = <0>;
+ reset-gpios = <&aud_io_slot 0 GPIO_ACTIVE_LOW>;
+ };
+};
+
+&aud_io_cpu {
+ status = "okay";
+};
--
2.50.1
^ permalink raw reply related
* Re: [PATCH v26 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
From: Lothar Waßmann @ 2026-06-29 7:50 UTC (permalink / raw)
To: pankaj.gupta
Cc: Jonathan Corbet, Shuah Khan, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Pankaj Gupta, linux-doc, linux-kernel, devicetree,
imx, linux-arm-kernel, Frieder Schrempf, kernel test robot,
sashiko-bot
In-Reply-To: <20260629-imx-se-if-v26-3-146446285744@nxp.com>
Hi,
On Mon, 29 Jun 2026 17:51:59 +0530 pankaj.gupta@oss.nxp.com wrote:
> From: Pankaj Gupta <pankaj.gupta@nxp.com>
>
> Add MU-based communication interface for secure enclave.
>
> NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE), are
> embedded in the SoC to support the features like HSM, SHE & V2X, using
> message based communication interface.
>
> The secure enclave FW communicates with Linux over single or multiple
> dedicated messaging unit(MU) based interface(s).
> Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.
>
> For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
> world - Linux(one or more) and OPTEE-OS (one or more).
>
[...]
> + ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
> + ELE_GET_INFO_REQ, ELE_GET_INFO_REQ_MSG_SZ,
> + true);
> + if (ret)
> + goto exit;
[...]
> +/* Fill a command message header with a given command ID and length in bytes. */
> +static inline int se_fill_cmd_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *hdr,
> + u8 cmd, u32 len, bool is_base_api)
> +{
> + hdr->tag = priv->if_defs->cmd_tag;
> + hdr->ver = (is_base_api) ? priv->if_defs->base_api_ver : priv->if_defs->fw_api_ver;
> + hdr->command = cmd;
> + hdr->size = len >> 2;
> +
> + return 0;
> +}
>
I don't see a point in having a function always return zero and
implement error checks that will never be used.
[...]
> +static const struct of_device_id se_match[] = {
> + { .compatible = "fsl,imx8ulp-se-ele-hsm", .data = &imx8ulp_se_ele_hsm},
> + { .compatible = "fsl,imx93-se-ele-hsm", .data = &imx93_se_ele_hsm},
> + {},
>
Since the last entry in this array must be a NULL entry, there should be
no comma after the {}. This will generate a compile error if (e.g. by
patch conflict resolution) an entry is added after the end marker.
Lothar Waßmann
^ permalink raw reply
* [PATCH v2] arm64: dts: amlogic: add some device nodes for A9
From: Xianwei Zhao via B4 Relay @ 2026-06-29 7:52 UTC (permalink / raw)
To: Neil Armstrong, Kevin Hilman, Jerome Brunet, Martin Blumenstingl,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-arm-kernel, linux-amlogic, devicetree, linux-kernel,
Xianwei Zhao
From: Xianwei Zhao <xianwei.zhao@amlogic.com>
Add pinctrl and irqchip-gpio device nodes for A9 SoC.
Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com>
---
Add pinctrl and irqchip-gpio device node for A9.
---
Changes in v2:
- Reorder device node by address.
- Link to v1: https://lore.kernel.org/r/20260629-a9-node-v1-1-42ff6a0c16ab@amlogic.com
---
arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi | 140 ++++++++++++++++++++++++++++
1 file changed, 140 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi
index 660c8556a864..b0e0fadeed82 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-a9.dtsi
@@ -6,6 +6,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/amlogic,pinctrl.h>
/ {
interrupt-parent = <&gic>;
@@ -97,6 +98,95 @@ soc {
#size-cells = <2>;
ranges;
+ apb: bus@fe000000 {
+ compatible = "simple-bus";
+ reg = <0x0 0xfe000000 0x0 0x480000>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x0 0x0 0x0 0xfe000000 0x0 0x480000>;
+
+ periphs_pinctrl: pinctrl@4000 {
+ compatible = "amlogic,pinctrl-a9";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x0 0x0 0x0 0x4000 0x0 0x340>;
+
+ gpioz: gpio@c0 {
+ reg = <0 0xc0 0 0x20>, <0 0x18 0 0x8>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&periphs_pinctrl 0 (AMLOGIC_GPIO_Z<<8) 16>;
+ };
+
+ gpiox: gpio@100 {
+ reg = <0 0x100 0 0x24>, <0 0xc 0 0x8>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&periphs_pinctrl 0 (AMLOGIC_GPIO_X<<8) 18>;
+ };
+
+ gpioh: gpio@140 {
+ reg = <0 0x140 0 0x20>, <0 0x2c 0 0x4>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&periphs_pinctrl 0 (AMLOGIC_GPIO_H<<8) 8>;
+ };
+
+ gpiom: gpio@1a0 {
+ reg = <0 0x1a0 0 0x20>, <0 0x20 0 0x4>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&periphs_pinctrl 0 (AMLOGIC_GPIO_M<<8) 8>;
+ };
+
+ gpiob: gpio@240 {
+ reg = <0 0x240 0 0x20>, <0 0x0 0 0x8>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&periphs_pinctrl 0 (AMLOGIC_GPIO_B<<8) 14>;
+ };
+
+ gpioa: gpio@280 {
+ reg = <0 0x280 0 0x24>, <0 0x40 0 0xc>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&periphs_pinctrl 0 (AMLOGIC_GPIO_A<<8) 20>;
+ };
+
+ gpioy: gpio@2c0 {
+ reg = <0 0x2c0 0 0x20>, <0 0x30 0 0x8>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&periphs_pinctrl 0 (AMLOGIC_GPIO_Y<<8) 10>;
+ };
+
+ gpiocc: gpio@300 {
+ reg = <0 0x300 0 0x20>, <0 0x14 0 0x4>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&periphs_pinctrl 0 (AMLOGIC_GPIO_CC<<8) 2>;
+ };
+ };
+
+ gpio_intc: interrupt-controller@4080 {
+ compatible = "amlogic,a9-gpio-intc",
+ "amlogic,meson-gpio-intc";
+ reg = <0x0 0x4080 0x0 0x20>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ amlogic,channel-interrupts =
+ <10 11 12 13 14 15 16 17 18 19 20 21>;
+ };
+ };
+
gic: interrupt-controller@ff800000 {
compatible = "arm,gic-v3";
#interrupt-cells = <3>;
@@ -114,6 +204,56 @@ aobus: bus@ffa00000 {
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xffa00000 0x0 0x100000>;
+ aobus_pinctrl: pinctrl@4000 {
+ compatible = "amlogic,pinctrl-a9";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges = <0x0 0x0 0x0 0x4000 0x0 0x0e0>;
+
+ gpioao: gpio@1c {
+ reg = <0 0x1c 0 0x20>, <0 0x0 0 0x8>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&aobus_pinctrl 0 (AMLOGIC_GPIO_AO<<8) 13>;
+ };
+
+ gpioc: gpio@3c {
+ reg = <0 0x3c 0 0x20>, <0 0x10 0 0x4>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&aobus_pinctrl 0 (AMLOGIC_GPIO_C<<8) 7>;
+ };
+
+ gpiod: gpio@5c {
+ reg = <0 0x5c 0 0x24>, <0 0x8 0 0x8>;
+ reg-names = "gpio", "mux";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&aobus_pinctrl 0 (AMLOGIC_GPIO_D<<8) 18>;
+ };
+
+ test_n: gpio@c0 {
+ reg = <0 0xc0 0 0x20>;
+ reg-names = "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&aobus_pinctrl 0 (AMLOGIC_GPIO_TEST_N<<8) 1>;
+ };
+ };
+
+ gpio_ao_intc: interrupt-controller@4080 {
+ compatible = "amlogic,a9-gpio-ao-intc",
+ "amlogic,meson-gpio-intc";
+ reg = <0x0 0x4080 0x0 0x34>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ amlogic,channel-interrupts =
+ <384 385 386 387 388 389 390 391 392 393
+ 394 395 396 397 398 399 400 401 402 403>;
+ };
+
uart_b: serial@1e000 {
compatible = "amlogic,a9-uart",
"amlogic,meson-s4-uart";
---
base-commit: 3d5670d672ae08b8c534b7beed6f57c8b44e7b43
change-id: 20260629-a9-node-3e6fceba7c90
Best regards,
--
Xianwei Zhao <xianwei.zhao@amlogic.com>
^ permalink raw reply related
* Re: [PATCH] ARM: enable interrupts when arm_notify_die() is handling user mode errors
From: Sebastian Andrzej Siewior @ 2026-06-29 7:57 UTC (permalink / raw)
To: Xie Yuanbin
Cc: linux, rmk+kernel, clrkwllms, rostedt, linusw, arnd,
linux-arm-kernel, linux-kernel, linux-rt-devel, liaohua4,
lilinjie8
In-Reply-To: <20260626082953.47503-1-xieyuanbin1@huawei.com>
On 2026-06-26 16:29:53 [+0800], Xie Yuanbin wrote:
> My personal view is as follows: First, an Unhandled kernel fault indicates
> that the kernel has encountered an error, which is different from an
> Unhandled user fault. An Unhandled user fault can be artificially
> constructed by user programs, whereas a healthy kernel, in theory, should
> not trigger an Unhandled kernel fault.
correct.
> When a kernel has already encountered a fault, I think that printing fault
> information is more meaningful than improving the kernel's real-time
> performance. Imagine this: The interrupts enable here, and at the same
> time an interrupt arrives, and then another kernel error is triggered
> within the interrupt context. The log would be a disaster.
The problem is actually hitting that "error" spot before oops_enter().
In oops_enter() not only interrupts are disabled but also the emergency
mode of the console is enabled. That means all console output is written
via the atomic_write interface to the console as it the output happens.
At this point, your real-time guarantees are gone. There is no need to
worry about anything here since everything is lost.
> But no matter what, the above are merely my personal views,
> and I respect the maintainer's opinions.
Restricting it to user context is reasonable: Here you kill the task and
need enabled interrupts in order to send the signal.
For kernel threads it is not needed because the "printing" happens with
disabled interrupts anyway and without any buffering. Should this event
not end with panic() then it will kill the kernel thread and enable
interrupts before doing so.
Sebastian
^ permalink raw reply
* [PATCH v26 3/7] firmware: imx: add driver for NXP EdgeLock Enclave
From: pankaj.gupta @ 2026-06-29 12:21 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Pankaj Gupta
Cc: linux-doc, linux-kernel, devicetree, imx, linux-arm-kernel,
Frieder Schrempf, kernel test robot, sashiko-bot
In-Reply-To: <20260629-imx-se-if-v26-0-146446285744@nxp.com>
From: Pankaj Gupta <pankaj.gupta@nxp.com>
Add MU-based communication interface for secure enclave.
NXP hardware IP(s) for secure-enclaves like Edgelock Enclave(ELE), are
embedded in the SoC to support the features like HSM, SHE & V2X, using
message based communication interface.
The secure enclave FW communicates with Linux over single or multiple
dedicated messaging unit(MU) based interface(s).
Exists on i.MX SoC(s) like i.MX8ULP, i.MX93, i.MX95 etc.
For i.MX9x SoC(s) there is at least one dedicated ELE MU(s) for each
world - Linux(one or more) and OPTEE-OS (one or more).
Other dependent kernel drivers will be:
- NVMEM: that supports non-volatile devices like EFUSES,
managed by NXP's secure-enclave.
Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Tested-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
Changes v25 to v26:
1. imx: depend on MAILBOX for EdgeLock Enclave driver
The EdgeLock Enclave driver uses mailbox core APIs such as
mbox_request_channel_byname(), mbox_free_channel(), and
mbox_send_message(). The current Kconfig allows the driver to be built
with COMPILE_TEST even when MAILBOX is disabled, which leads to linker
failures from unresolved mailbox symbols.
Require MAILBOX explicitly so COMPILE_TEST builds still include the
mailbox core when this driver is selected.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202605270101.2FFpzoFg-lkp@intel.com/
2. ele_common: harden response waiter timeout handling
The synchronous command/response path stores the caller-owned response
buffer in waiting_rsp_clbk_hdl.rx_msg until se_if_rx_callback() copies
the firmware response and completes the waiter.
That breaks down when the response wait times out: the caller can return
and free the response buffer while a delayed firmware response is still
in flight. If the callback later copies into the stale rx_msg pointer,
it can corrupt freed memory.
Fix this by protecting the response-waiter buffer handoff with a
dedicated spinlock. On timeout, clear waiting_rsp_clbk_hdl.rx_msg under
that lock before returning. In the RX callback, check rx_msg under the
same lock and drop late rsp_tag messages instead of copying into a stale
buffer. Use a small "firmware busy" circuit breaker to reject new
command/response transactions after timeout until the delayed response is
observed.
Also avoid a livelock in ele_msg_rcv(): if a signal interrupts the wait
after a command has already been sent, record the interruption and
continue waiting non-interruptibly for the remaining timeout budget.
This preserves firmware/kernel synchronization while avoiding an
infinite loop of repeated -ERESTARTSYS returns.
The main lifetime fix applies to the synchronous response-waiter path
(waiting_rsp_clbk_hdl / rsp_tag). The command-receiver path is also
hardened with basic state validation and bounded copy handling.
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260514090457.2186933-1-pankaj.gupta@nxp.com?part=1
3. se_ctrl: Move priv to explicit lifetime management.
Allocating priv via devm, will lead to UAF while teardown with active
misc devices & dev_ctx.
---
drivers/firmware/imx/Kconfig | 13 ++
drivers/firmware/imx/Makefile | 2 +
drivers/firmware/imx/ele_base_msg.c | 277 +++++++++++++++++++++++
drivers/firmware/imx/ele_base_msg.h | 98 ++++++++
drivers/firmware/imx/ele_common.c | 435 ++++++++++++++++++++++++++++++++++++
drivers/firmware/imx/ele_common.h | 45 ++++
drivers/firmware/imx/se_ctrl.c | 418 ++++++++++++++++++++++++++++++++++
drivers/firmware/imx/se_ctrl.h | 95 ++++++++
include/linux/firmware/imx/se_api.h | 14 ++
9 files changed, 1397 insertions(+)
diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
index 127ad752acf8..e3cb7f965e70 100644
--- a/drivers/firmware/imx/Kconfig
+++ b/drivers/firmware/imx/Kconfig
@@ -55,3 +55,16 @@ config IMX_SCMI_MISC_DRV
core that could provide misc functions such as board control.
This driver can also be built as a module.
+
+config IMX_SEC_ENCLAVE
+ tristate "i.MX Embedded Secure Enclave - EdgeLock Enclave Firmware driver."
+ depends on MAILBOX && ((IMX_MBOX && ARCH_MXC && ARM64) || COMPILE_TEST)
+ select FW_LOADER
+ default m if ARCH_MXC
+
+ help
+ Exposes APIs supported by the iMX Secure Enclave HW IP called:
+ - EdgeLock Enclave Firmware (for i.MX8ULP, i.MX93),
+ like base, HSM, V2X & SHE using the SAB protocol via the shared Messaging
+ Unit. This driver exposes these interfaces via a set of file descriptors
+ allowing to configure shared memory, send and receive messages.
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
index 3bbaffa6e347..4412b15846b1 100644
--- a/drivers/firmware/imx/Makefile
+++ b/drivers/firmware/imx/Makefile
@@ -4,3 +4,5 @@ obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
obj-${CONFIG_IMX_SCMI_CPU_DRV} += sm-cpu.o
obj-${CONFIG_IMX_SCMI_MISC_DRV} += sm-misc.o
obj-${CONFIG_IMX_SCMI_LMM_DRV} += sm-lmm.o
+sec_enclave-objs = se_ctrl.o ele_common.o ele_base_msg.o
+obj-${CONFIG_IMX_SEC_ENCLAVE} += sec_enclave.o
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
new file mode 100644
index 000000000000..54d79c3d75af
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/types.h>
+
+#include <linux/cleanup.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/genalloc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+#define FW_DBG_DUMP_FIXED_STR "ELE"
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
+{
+ dma_addr_t get_info_addr = 0;
+ u32 *get_info_data = NULL;
+ int ret = 0;
+
+ if (!priv)
+ return -EINVAL;
+
+ memset(s_info, 0x0, sizeof(*s_info));
+
+ struct se_api_msg *tx_msg __free(kfree) =
+ kzalloc(ELE_GET_INFO_REQ_MSG_SZ, GFP_KERNEL);
+ if (!tx_msg)
+ return -ENOMEM;
+
+ struct se_api_msg *rx_msg __free(kfree) =
+ kzalloc(ELE_GET_INFO_RSP_MSG_SZ, GFP_KERNEL);
+ if (!rx_msg)
+ return -ENOMEM;
+
+ if (priv->mem_pool)
+ get_info_data = gen_pool_dma_alloc(priv->mem_pool,
+ ELE_GET_INFO_BUFF_SZ,
+ &get_info_addr);
+ else
+ get_info_data = dma_alloc_coherent(priv->dev,
+ ELE_GET_INFO_BUFF_SZ,
+ &get_info_addr,
+ GFP_KERNEL);
+ if (!get_info_data) {
+ dev_err(priv->dev,
+ "%s: Failed to allocate get_info_addr.", __func__);
+ return -ENOMEM;
+ }
+
+ ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+ ELE_GET_INFO_REQ, ELE_GET_INFO_REQ_MSG_SZ,
+ true);
+ if (ret)
+ goto exit;
+
+ tx_msg->data[0] = upper_32_bits(get_info_addr);
+ tx_msg->data[1] = lower_32_bits(get_info_addr);
+ tx_msg->data[2] = sizeof(*s_info);
+ ret = ele_msg_send_rcv(priv, tx_msg, ELE_GET_INFO_REQ_MSG_SZ, rx_msg,
+ ELE_GET_INFO_RSP_MSG_SZ);
+ if (ret < 0)
+ goto exit;
+
+ ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_GET_INFO_REQ,
+ ELE_GET_INFO_RSP_MSG_SZ, true);
+ if (ret < 0)
+ goto exit;
+
+ memcpy(s_info, get_info_data, sizeof(*s_info));
+exit:
+ if (priv->mem_pool)
+ gen_pool_free(priv->mem_pool, (unsigned long)get_info_data,
+ ELE_GET_INFO_BUFF_SZ);
+ else
+ dma_free_coherent(priv->dev, ELE_GET_INFO_BUFF_SZ,
+ get_info_data, get_info_addr);
+
+ return ret;
+}
+
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data)
+{
+ return ele_get_info(priv, data);
+}
+
+int ele_ping(struct se_if_priv *priv)
+{
+ int ret = 0;
+
+ if (!priv)
+ return -EINVAL;
+
+ struct se_api_msg *tx_msg __free(kfree) = kzalloc(ELE_PING_REQ_SZ,
+ GFP_KERNEL);
+ if (!tx_msg)
+ return -ENOMEM;
+
+ struct se_api_msg *rx_msg __free(kfree) = kzalloc(ELE_PING_RSP_SZ,
+ GFP_KERNEL);
+ if (!rx_msg)
+ return -ENOMEM;
+
+ ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+ ELE_PING_REQ, ELE_PING_REQ_SZ, true);
+ if (ret) {
+ dev_err(priv->dev, "Error: se_fill_cmd_msg_hdr failed.");
+ return ret;
+ }
+
+ ret = ele_msg_send_rcv(priv, tx_msg, ELE_PING_REQ_SZ, rx_msg,
+ ELE_PING_RSP_SZ);
+ if (ret < 0)
+ return ret;
+
+ ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
+ ELE_PING_RSP_SZ, true);
+
+ return ret;
+}
+
+int ele_service_swap(struct se_if_priv *priv,
+ phys_addr_t addr,
+ u32 addr_size, u16 flag)
+{
+ int ret = 0;
+
+ if (!priv)
+ return -EINVAL;
+
+ struct se_api_msg *tx_msg __free(kfree) =
+ kzalloc(ELE_SERVICE_SWAP_REQ_MSG_SZ, GFP_KERNEL);
+ if (!tx_msg)
+ return -ENOMEM;
+
+ struct se_api_msg *rx_msg __free(kfree) =
+ kzalloc(ELE_SERVICE_SWAP_RSP_MSG_SZ, GFP_KERNEL);
+ if (!rx_msg)
+ return -ENOMEM;
+
+ ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+ ELE_SERVICE_SWAP_REQ,
+ ELE_SERVICE_SWAP_REQ_MSG_SZ, true);
+ if (ret)
+ return ret;
+
+ tx_msg->data[0] = flag;
+ tx_msg->data[1] = addr_size;
+ tx_msg->data[2] = ELE_NONE_VAL;
+ tx_msg->data[3] = lower_32_bits(addr);
+ tx_msg->data[4] = se_get_msg_chksum((u32 *)&tx_msg[0],
+ ELE_SERVICE_SWAP_REQ_MSG_SZ);
+ if (!tx_msg->data[4])
+ return -EINVAL;
+
+ ret = ele_msg_send_rcv(priv, tx_msg, ELE_SERVICE_SWAP_REQ_MSG_SZ,
+ rx_msg, ELE_SERVICE_SWAP_RSP_MSG_SZ);
+ if (ret < 0)
+ return ret;
+
+ ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_SERVICE_SWAP_REQ,
+ ELE_SERVICE_SWAP_RSP_MSG_SZ, true);
+ if (ret)
+ return ret;
+
+ if (flag == ELE_IMEM_EXPORT)
+ ret = rx_msg->data[1];
+ else
+ ret = 0;
+
+ return ret;
+}
+
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+ phys_addr_t img_addr)
+{
+ int ret = 0;
+
+ if (!priv)
+ return -EINVAL;
+
+ if (upper_32_bits(contnr_addr) || upper_32_bits(img_addr)) {
+ dev_err(priv->dev, "Wrong address: %pap %pap\n", &contnr_addr, &img_addr);
+ return -EINVAL;
+ }
+
+ struct se_api_msg *tx_msg __free(kfree) =
+ kzalloc(ELE_FW_AUTH_REQ_SZ, GFP_KERNEL);
+ if (!tx_msg)
+ return -ENOMEM;
+
+ struct se_api_msg *rx_msg __free(kfree) =
+ kzalloc(ELE_FW_AUTH_RSP_MSG_SZ, GFP_KERNEL);
+ if (!rx_msg)
+ return -ENOMEM;
+
+ ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+ ELE_FW_AUTH_REQ, ELE_FW_AUTH_REQ_SZ, true);
+ if (ret)
+ return ret;
+
+ tx_msg->data[0] = lower_32_bits(contnr_addr);
+ tx_msg->data[1] = 0;
+ tx_msg->data[2] = lower_32_bits(img_addr);
+
+ ret = ele_msg_send_rcv(priv, tx_msg, ELE_FW_AUTH_REQ_SZ, rx_msg,
+ ELE_FW_AUTH_RSP_MSG_SZ);
+ if (ret < 0)
+ return ret;
+
+ ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_FW_AUTH_REQ,
+ ELE_FW_AUTH_RSP_MSG_SZ, true);
+
+ return ret;
+}
+
+int ele_debug_dump(struct se_if_priv *priv)
+{
+ bool keep_logging;
+ int msg_ex_cnt;
+ int ret = 0;
+ int i;
+
+ if (!priv)
+ return -EINVAL;
+
+ struct se_api_msg *tx_msg __free(kfree) = kzalloc(ELE_DEBUG_DUMP_REQ_SZ,
+ GFP_KERNEL);
+ if (!tx_msg)
+ return -ENOMEM;
+
+ struct se_api_msg *rx_msg __free(kfree) = kzalloc(ELE_DEBUG_DUMP_RSP_SZ,
+ GFP_KERNEL);
+ if (!rx_msg)
+ return -ENOMEM;
+
+ ret = se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
+ ELE_DEBUG_DUMP_REQ_SZ, true);
+ if (ret)
+ return ret;
+
+ msg_ex_cnt = 0;
+ do {
+ memset(rx_msg, 0x0, ELE_DEBUG_DUMP_RSP_SZ);
+
+ ret = ele_msg_send_rcv(priv, tx_msg, ELE_DEBUG_DUMP_REQ_SZ,
+ rx_msg, ELE_DEBUG_DUMP_RSP_SZ);
+ if (ret < 0)
+ return ret;
+
+ ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_DEBUG_DUMP_REQ,
+ ELE_DEBUG_DUMP_RSP_SZ, true);
+ if (ret) {
+ dev_err(priv->dev, "Dump_Debug_Buffer Error: %x.", ret);
+ break;
+ }
+ keep_logging = (rx_msg->header.size >= (ELE_DEBUG_DUMP_RSP_SZ >> 2) &&
+ msg_ex_cnt < ELE_MAX_DBG_DMP_PKT);
+
+ rx_msg->header.size -= 2;
+
+ if (rx_msg->header.size > 2)
+ rx_msg->header.size--;
+
+ for (i = 0; i < rx_msg->header.size; i += 2)
+ dev_info(priv->dev, "%s%02x_%02x: 0x%08x 0x%08x",
+ FW_DBG_DUMP_FIXED_STR, msg_ex_cnt, i,
+ rx_msg->data[i + 1], rx_msg->data[i + 2]);
+
+ msg_ex_cnt++;
+ } while (keep_logging);
+
+ return ret;
+}
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
new file mode 100644
index 000000000000..74f87f57d96b
--- /dev/null
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ *
+ * Header file for the EdgeLock Enclave Base API(s).
+ */
+
+#ifndef ELE_BASE_MSG_H
+#define ELE_BASE_MSG_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+#include "se_ctrl.h"
+
+#define ELE_NONE_VAL 0x0
+
+#define ELE_GET_INFO_REQ 0xda
+#define ELE_GET_INFO_REQ_MSG_SZ 0x10
+#define ELE_GET_INFO_RSP_MSG_SZ 0x08
+
+#define MAX_UID_SIZE (16)
+#define DEV_GETINFO_ROM_PATCH_SHA_SZ (32)
+#define DEV_GETINFO_FW_SHA_SZ (32)
+#define DEV_GETINFO_OEM_SRKH_SZ (64)
+#define DEV_GETINFO_MIN_VER_MASK 0xff
+#define DEV_GETINFO_MAJ_VER_MASK 0xff00
+#define ELE_DEV_INFO_EXTRA_SZ 0x60
+
+struct dev_info {
+ u8 cmd;
+ u8 ver;
+ u16 length;
+ u16 soc_id;
+ u16 soc_rev;
+ u16 lmda_val;
+ u8 ssm_state;
+ u8 dev_atts_api_ver;
+ u8 uid[MAX_UID_SIZE];
+ u8 sha_rom_patch[DEV_GETINFO_ROM_PATCH_SHA_SZ];
+ u8 sha_fw[DEV_GETINFO_FW_SHA_SZ];
+};
+
+struct dev_addn_info {
+ u8 oem_srkh[DEV_GETINFO_OEM_SRKH_SZ];
+ u8 trng_state;
+ u8 csal_state;
+ u8 imem_state;
+ u8 reserved2;
+};
+
+struct ele_dev_info {
+ struct dev_info d_info;
+ struct dev_addn_info d_addn_info;
+};
+
+#define ELE_GET_INFO_BUFF_SZ (sizeof(struct ele_dev_info) \
+ + ELE_DEV_INFO_EXTRA_SZ)
+
+#define GET_SERIAL_NUM_FROM_UID(x, uid_word_sz) ({\
+ const u32 *__x = (const u32 *)(x); \
+ size_t __sz = (uid_word_sz); \
+ ((u64)__x[__sz - 1] << 32) | __x[0]; \
+ })
+
+#define ELE_MAX_DBG_DMP_PKT 50
+#define ELE_DEBUG_DUMP_REQ 0x21
+#define ELE_DEBUG_DUMP_REQ_SZ 0x4
+#define ELE_DEBUG_DUMP_RSP_SZ 0x5c
+
+#define ELE_PING_REQ 0x01
+#define ELE_PING_REQ_SZ 0x04
+#define ELE_PING_RSP_SZ 0x08
+
+#define ELE_SERVICE_SWAP_REQ 0xdf
+#define ELE_SERVICE_SWAP_REQ_MSG_SZ 0x18
+#define ELE_SERVICE_SWAP_RSP_MSG_SZ 0x0c
+#define ELE_IMEM_SIZE 0x10000
+#define ELE_IMEM_STATE_OK 0xca
+#define ELE_IMEM_STATE_BAD 0xfe
+#define ELE_IMEM_STATE_WORD 0x27
+#define ELE_IMEM_STATE_MASK 0x00ff0000
+#define ELE_IMEM_EXPORT 0x1
+#define ELE_IMEM_IMPORT 0x2
+
+#define ELE_FW_AUTH_REQ 0x02
+#define ELE_FW_AUTH_REQ_SZ 0x10
+#define ELE_FW_AUTH_RSP_MSG_SZ 0x08
+
+int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info);
+int ele_fetch_soc_info(struct se_if_priv *priv, void *data);
+int ele_ping(struct se_if_priv *priv);
+int ele_service_swap(struct se_if_priv *priv, phys_addr_t addr,
+ u32 addr_size, u16 flag);
+int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
+ phys_addr_t img_addr);
+int ele_debug_dump(struct se_if_priv *priv);
+#endif
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
new file mode 100644
index 000000000000..ba606f4e8be8
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.c
@@ -0,0 +1,435 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2025 NXP
+ */
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+
+/*
+ * se_get_msg_chksum() - to calculate checksum word by word.
+ *
+ * @msg : reference to the input msg-data.
+ * @msg_len : reference to the input msg-data length in bytes.
+ * Includes extra 4 bytes (or 1 words) chksum.
+ *
+ * This function returns the checksum calculated by ORing word by word.
+ *
+ * Return:
+ * 0: if the input length is not 4 byte aligned, or num of words < 5.
+ * chksum: calculated word by word.
+ */
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len)
+{
+ u32 nb_words = msg_len / (u32)sizeof(u32);
+ u32 chksum = 0;
+ u32 i;
+
+ if (nb_words < 5)
+ return chksum;
+
+ if (msg_len % SE_MSG_WORD_SZ) {
+ pr_err("Msg-len is not 4-byte aligned.");
+ return chksum;
+ }
+
+ /* nb_words include one checksum word, so skip it. */
+ nb_words--;
+
+ for (i = 0; i < nb_words; i++)
+ chksum ^= *(msg + i);
+
+ return chksum;
+}
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl)
+{
+ bool wait_uninterruptible = false;
+ unsigned long remaining_jiffies;
+ unsigned long flags;
+ int ret;
+
+ remaining_jiffies = MAX_SCHEDULE_TIMEOUT;
+ do {
+ if (wait_uninterruptible)
+ ret = wait_for_completion_timeout(&se_clbk_hdl->done,
+ remaining_jiffies);
+ else
+ ret = wait_for_completion_interruptible_timeout(&se_clbk_hdl->done,
+ remaining_jiffies);
+ if (ret == -ERESTARTSYS) {
+ /*
+ * Record that a signal was observed, then continue waiting non-
+ * interruptibly until the response arrives or the timeout
+ * expires. The caller can surface the interruption to userspace
+ * after the protocol transaction is brought back to a
+ * synchronized state.
+ */
+ if (priv->waiting_rsp_clbk_hdl.rx_msg) {
+ priv->waiting_rsp_clbk_hdl.signal_rcvd = true;
+ wait_uninterruptible = true;
+ continue;
+ }
+ ret = -EINTR;
+ break;
+ }
+
+ if (ret == 0) {
+ /*
+ * The response buffer belongs to the caller of ele_msg_send_rcv()
+ * and may be freed as soon as this function returns. Clear rx_msg
+ * under clbk_rx_lock so that a late se_if_rx_callback() can
+ * observe that the waiter has timed out and must not copy into
+ * the stale buffer.
+ *
+ * If the completion has not yet been signaled, mark the firmware
+ * path busy. This acts as a circuit breaker: reject new
+ * command/response transactions until the delayed response
+ * arrives and the callback closes the breaker.
+ */
+
+ spin_lock_irqsave(&se_clbk_hdl->clbk_rx_lock, flags);
+ se_clbk_hdl->rx_msg = NULL;
+ if (!completion_done(&se_clbk_hdl->done))
+ atomic_set(&priv->fw_busy, 1);
+
+ spin_unlock_irqrestore(&se_clbk_hdl->clbk_rx_lock, flags);
+ ret = -ETIMEDOUT;
+ dev_err(priv->dev,
+ "Fatal Error: SE interface: %s0, hangs indefinitely.\n",
+ get_se_if_name(priv->if_defs->se_if_type));
+ break;
+ }
+ ret = se_clbk_hdl->rx_msg_sz;
+ break;
+ } while (ret < 0);
+
+ return ret;
+}
+
+int ele_msg_send(struct se_if_priv *priv,
+ void *tx_msg,
+ int tx_msg_sz)
+{
+ struct se_msg_hdr *header = tx_msg;
+ int err;
+
+ /*
+ * Check that the size passed as argument matches the size
+ * carried in the message.
+ */
+ if (header->size << 2 != tx_msg_sz) {
+ dev_err(priv->dev,
+ "User buf hdr: 0x%x, sz mismatced with input-sz (%d != %d).",
+ *(u32 *)header, header->size << 2, tx_msg_sz);
+ return -EINVAL;
+ }
+
+ err = mbox_send_message(priv->tx_chan, tx_msg);
+ if (err < 0) {
+ dev_err(priv->dev, "Error: mbox_send_message failure.\n");
+ return err;
+ }
+
+ return tx_msg_sz;
+}
+
+/* API used for send/receive blocking call. */
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+ void *rx_msg, int exp_rx_msg_sz)
+{
+ int err;
+
+ guard(mutex)(&priv->se_if_cmd_lock);
+
+ if (atomic_read(&priv->fw_busy)) {
+ dev_dbg(priv->dev, "ELE became unresponsive.\n");
+ return -EBUSY;
+ }
+ reinit_completion(&priv->waiting_rsp_clbk_hdl.done);
+ priv->waiting_rsp_clbk_hdl.rx_msg_sz = exp_rx_msg_sz;
+ priv->waiting_rsp_clbk_hdl.rx_msg = rx_msg;
+
+ err = ele_msg_send(priv, tx_msg, tx_msg_sz);
+ if (err < 0)
+ return err;
+
+ err = ele_msg_rcv(priv, &priv->waiting_rsp_clbk_hdl);
+
+ if (priv->waiting_rsp_clbk_hdl.signal_rcvd) {
+ err = -EINTR;
+ priv->waiting_rsp_clbk_hdl.signal_rcvd = false;
+ dev_err(priv->dev, "Err[0x%x]:Interrupted by signal.", err);
+ }
+ priv->waiting_rsp_clbk_hdl.rx_msg = NULL;
+
+ return err;
+}
+
+static bool check_hdr_exception_for_sz(struct se_if_priv *priv,
+ struct se_msg_hdr *header)
+{
+ /*
+ * List of API(s) header that can be accepte variable length
+ * response buffer.
+ */
+ if (header->command == ELE_DEBUG_DUMP_REQ &&
+ header->ver == priv->if_defs->base_api_ver &&
+ header->size >= 2 && header->size <= (ELE_DEBUG_DUMP_RSP_SZ / 4))
+ return true;
+
+ return false;
+}
+
+/*
+ * Callback called by mailbox FW, when data is received.
+ */
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
+{
+ struct se_clbk_handle *se_clbk_hdl;
+ struct device *dev = mbox_cl->dev;
+ struct se_msg_hdr *header;
+ bool sz_mismatch = false;
+ struct se_if_priv *priv;
+ unsigned long flags;
+ u32 rx_msg_sz;
+
+ priv = dev_get_drvdata(dev);
+
+ /* The function can be called with NULL msg */
+ if (!msg) {
+ dev_err(dev, "Message is invalid\n");
+ return;
+ }
+
+ header = msg;
+ rx_msg_sz = header->size << 2;
+
+ /* Incoming command: wake up the receiver if any. */
+ if (header->tag == priv->if_defs->cmd_tag) {
+ se_clbk_hdl = &priv->cmd_receiver_clbk_hdl;
+ spin_lock_irqsave(&se_clbk_hdl->clbk_rx_lock, flags);
+ if (!se_clbk_hdl->rx_msg) {
+ spin_unlock_irqrestore(&se_clbk_hdl->clbk_rx_lock, flags);
+ dev_warn(dev, "No command receiver registered for message: %.8x\n",
+ *((u32 *)header));
+ return;
+ }
+
+ /*
+ * cmd_tag messages are delivered only to the explicitly registered
+ * command receiver. Unlike the synchronous response waiter path, the
+ * command receiver uses a dedicated long-lived buffer installed by
+ * SE_IOCTL_ENABLE_CMD_RCV and is not subject to the timeout/circuit-
+ * breaker handling used for rsp_tag messages.
+ */
+ dev_dbg(dev, "Selecting cmd receiver: for mesg header:0x%x.",
+ *(u32 *)header);
+
+ /*
+ * Pre-allocated buffer of MAX_NVM_MSG_LEN
+ * as the NVM command are initiated by FW.
+ * Size is revealed as part of this call function.
+ */
+
+ if (rx_msg_sz > MAX_NVM_MSG_LEN) {
+ /* Store the response buffer maxsize in local variable.*/
+ rx_msg_sz = MAX_NVM_MSG_LEN;
+ sz_mismatch = true;
+ }
+
+ se_clbk_hdl->rx_msg_sz = rx_msg_sz;
+ memcpy(se_clbk_hdl->rx_msg, msg, se_clbk_hdl->rx_msg_sz);
+ complete(&se_clbk_hdl->done);
+ spin_unlock_irqrestore(&se_clbk_hdl->clbk_rx_lock, flags);
+ if (sz_mismatch)
+ dev_err(dev,
+ "CMD-RCVER NVM: hdr(0x%x) with different sz(%d != %d).\n",
+ *(u32 *)header,
+ (header->size << 2), rx_msg_sz);
+ } else if (header->tag == priv->if_defs->rsp_tag) {
+ bool exception_for_sz_mismatch = check_hdr_exception_for_sz(priv, header);
+ u32 exp_rx_msg_sz = 0;
+
+ /*
+ * waiting_rsp_clbk_hdl.rx_msg is owned by the synchronous sender in
+ * ele_msg_send_rcv(). After timeout or error, that path clears rx_msg
+ * under clbk_rx_lock before returning to its caller, which may then free
+ * the buffer. Check rx_msg under the same lock here so a delayed response
+ * can be detected and dropped instead of copying into freed memory.
+ *
+ * A late response also closes the firmware-busy circuit breaker, allowing
+ * future command/response transactions to proceed again.
+ */
+ se_clbk_hdl = &priv->waiting_rsp_clbk_hdl;
+ exp_rx_msg_sz = se_clbk_hdl->rx_msg_sz;
+ spin_lock_irqsave(&se_clbk_hdl->clbk_rx_lock, flags);
+ if (!se_clbk_hdl->rx_msg) {
+ /* Close circuit breaker on spinlock race */
+ atomic_set(&priv->fw_busy, 0);
+ spin_unlock_irqrestore(&se_clbk_hdl->clbk_rx_lock, flags);
+ dev_info(dev, "ELE responded (late), recovery FW available.");
+ return;
+ }
+ dev_dbg(dev, "Selecting resp waiter: for mesg header:0x%x.",
+ *(u32 *)header);
+
+ /*
+ * For rsp_tag traffic, the sender provides the expected response
+ * buffer size. If firmware returns a different size, clamp the copy
+ * length to the caller's buffer capacity before memcpy() and report the
+ * mismatch after dropping the spinlock.
+ */
+ if (rx_msg_sz != exp_rx_msg_sz) {
+ if (!exception_for_sz_mismatch)
+ sz_mismatch = true;
+
+ se_clbk_hdl->rx_msg_sz = min(rx_msg_sz, exp_rx_msg_sz);
+ }
+ memcpy(se_clbk_hdl->rx_msg, msg, se_clbk_hdl->rx_msg_sz);
+ complete(&se_clbk_hdl->done);
+ spin_unlock_irqrestore(&se_clbk_hdl->clbk_rx_lock, flags);
+
+ if (sz_mismatch)
+ dev_err(dev,
+ "Rsp to CMD: hdr(0x%x) with different sz(%d != %d).\n",
+ *(u32 *)header,
+ (header->size << 2), exp_rx_msg_sz);
+ } else {
+ dev_err(dev, "Failed to select a device for message: %.8x\n",
+ *((u32 *)header));
+ }
+}
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+ u8 msg_id, u8 sz, bool is_base_api)
+{
+ struct se_msg_hdr *header = &msg->header;
+ u32 status;
+
+ if (header->tag != priv->if_defs->rsp_tag) {
+ dev_err(priv->dev, "MSG[0x%x] Hdr: Resp tag mismatch. (0x%x != 0x%x)",
+ msg_id, header->tag, priv->if_defs->rsp_tag);
+ return -EINVAL;
+ }
+
+ if (header->command != msg_id) {
+ dev_err(priv->dev, "MSG Header: Cmd id mismatch. (0x%x != 0x%x)",
+ header->command, msg_id);
+ return -EINVAL;
+ }
+
+ if ((sz % 4) || (header->size != (sz >> 2) &&
+ !check_hdr_exception_for_sz(priv, header))) {
+ dev_err(priv->dev, "MSG[0x%x] Hdr: Cmd size mismatch. (0x%x != 0x%x)",
+ msg_id, header->size, (sz >> 2));
+ return -EINVAL;
+ }
+
+ if (is_base_api && header->ver != priv->if_defs->base_api_ver) {
+ dev_err(priv->dev,
+ "MSG[0x%x] Hdr: Base API Vers mismatch. (0x%x != 0x%x)",
+ msg_id, header->ver, priv->if_defs->base_api_ver);
+ return -EINVAL;
+ } else if (!is_base_api && header->ver != priv->if_defs->fw_api_ver) {
+ dev_err(priv->dev,
+ "MSG[0x%x] Hdr: FW API Vers mismatch. (0x%x != 0x%x)",
+ msg_id, header->ver, priv->if_defs->fw_api_ver);
+ return -EINVAL;
+ }
+
+ status = RES_STATUS(msg->data[0]);
+ if (status != priv->if_defs->success_tag) {
+ dev_err(priv->dev, "Command Id[%x], Response Failure = 0x%x",
+ header->command, status);
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+ struct ele_dev_info s_info = {0};
+ int ret;
+
+ ret = ele_get_info(priv, &s_info);
+ if (ret) {
+ dev_err(priv->dev, "Failed to get info from ELE.\n");
+ return ret;
+ }
+
+ /* Check for the imem-state before continue to save imem state. */
+ if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_BAD)
+ return -EIO;
+
+ /*
+ * EXPORT command will save encrypted IMEM to given address,
+ * so later in resume, IMEM can be restored from the given
+ * address.
+ *
+ * Size must be at least 64 kB.
+ */
+ ret = ele_service_swap(priv, imem->phyaddr, ELE_IMEM_SIZE, ELE_IMEM_EXPORT);
+ if (ret < 0) {
+ dev_err(priv->dev, "Failed to export IMEM.");
+ imem->size = 0;
+ } else {
+ dev_dbg(priv->dev,
+ "Exported %d bytes of encrypted IMEM.",
+ ret);
+ imem->size = ret;
+ }
+
+ return ret > 0 ? 0 : ret;
+}
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
+{
+ struct ele_dev_info s_info;
+ int ret;
+
+ /* get info from ELE */
+ ret = ele_get_info(priv, &s_info);
+ if (ret) {
+ dev_err(priv->dev, "Failed to get info from ELE.");
+ return ret;
+ }
+ imem->state = s_info.d_addn_info.imem_state;
+
+ /* Check for the imem-state and imem-size before continue to
+ * restore imem state.
+ */
+ if (s_info.d_addn_info.imem_state != ELE_IMEM_STATE_BAD || !imem->size)
+ return -EIO;
+
+ /*
+ * IMPORT command will restore IMEM from the given
+ * address, here size is the actual size returned by ELE
+ * during the export operation
+ */
+ ret = ele_service_swap(priv, imem->phyaddr, imem->size, ELE_IMEM_IMPORT);
+ if (ret) {
+ dev_err(priv->dev, "Failed to import IMEM");
+ return ret;
+ }
+
+ /*
+ * After importing IMEM, check if IMEM state is equal to 0xCA
+ * to ensure IMEM is fully loaded and
+ * ELE functionality can be used.
+ */
+ ret = ele_get_info(priv, &s_info);
+ if (ret) {
+ dev_err(priv->dev, "Failed to get info from ELE.");
+ return ret;
+ }
+ imem->state = s_info.d_addn_info.imem_state;
+
+ if (s_info.d_addn_info.imem_state == ELE_IMEM_STATE_OK)
+ dev_dbg(priv->dev, "Successfully restored IMEM.");
+ else
+ dev_err(priv->dev, "Failed to restore IMEM.");
+
+ return ret;
+}
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
new file mode 100644
index 000000000000..96e987ef6f88
--- /dev/null
+++ b/drivers/firmware/imx/ele_common.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __ELE_COMMON_H__
+#define __ELE_COMMON_H__
+
+#include "se_ctrl.h"
+
+#define ELE_SUCCESS_IND 0xD6
+
+#define IMX_ELE_FW_DIR "imx/ele/"
+
+u32 se_get_msg_chksum(u32 *msg, u32 msg_len);
+
+int ele_msg_rcv(struct se_if_priv *priv, struct se_clbk_handle *se_clbk_hdl);
+
+int ele_msg_send(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz);
+
+int ele_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+ void *rx_msg, int exp_rx_msg_sz);
+
+void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
+
+int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
+ u8 msg_id, u8 sz, bool is_base_api);
+
+/* Fill a command message header with a given command ID and length in bytes. */
+static inline int se_fill_cmd_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *hdr,
+ u8 cmd, u32 len, bool is_base_api)
+{
+ hdr->tag = priv->if_defs->cmd_tag;
+ hdr->ver = (is_base_api) ? priv->if_defs->base_api_ver : priv->if_defs->fw_api_ver;
+ hdr->command = cmd;
+ hdr->size = len >> 2;
+
+ return 0;
+}
+
+int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+int se_restore_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem);
+
+#endif /*__ELE_COMMON_H__ */
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
new file mode 100644
index 000000000000..9a2c3c611146
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -0,0 +1,418 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2026 NXP
+ */
+
+#include <linux/bitfield.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/dma-direct.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/firmware.h>
+#include <linux/firmware/imx/se_api.h>
+#include <linux/genalloc.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+
+#include "ele_base_msg.h"
+#include "ele_common.h"
+#include "se_ctrl.h"
+
+#define MAX_SOC_INFO_DATA_SZ 256
+#define MBOX_TX_NAME "tx"
+#define MBOX_RX_NAME "rx"
+
+#define SE_TYPE_STR_DBG "dbg"
+#define SE_TYPE_STR_HSM "hsm"
+
+#define SE_TYPE_ID_DBG 0x1
+
+#define SE_TYPE_ID_HSM 0x2
+
+struct se_fw_img_name {
+ const u8 *prim_fw_nm_in_rfs;
+ const u8 *seco_fw_nm_in_rfs;
+};
+
+struct se_fw_load_info {
+ const struct se_fw_img_name *se_fw_img_nm;
+ bool is_fw_tobe_loaded;
+ bool imem_mgmt;
+ struct se_imem_buf imem;
+};
+
+struct se_var_info {
+ u16 soc_rev;
+ struct se_fw_load_info load_fw;
+};
+
+/* contains fixed information */
+struct se_soc_info {
+ const u16 soc_id;
+ const char *soc_name;
+ const struct se_fw_img_name se_fw_img_nm;
+};
+
+struct se_if_node {
+ struct se_soc_info *se_info;
+ u8 *pool_name;
+ bool reserved_dma_ranges;
+ struct se_if_defines if_defs;
+};
+
+/* common for all the SoC. */
+static struct se_var_info var_se_info;
+
+static struct se_soc_info se_imx8ulp_info = {
+ .soc_id = SOC_ID_OF_IMX8ULP,
+ .soc_name = "i.MX8ULP",
+ .se_fw_img_nm = {
+ .prim_fw_nm_in_rfs = IMX_ELE_FW_DIR
+ "mx8ulpa2-ahab-container.img",
+ .seco_fw_nm_in_rfs = IMX_ELE_FW_DIR
+ "mx8ulpa2ext-ahab-container.img",
+ },
+};
+
+static struct se_if_node imx8ulp_se_ele_hsm = {
+ .se_info = &se_imx8ulp_info,
+ .pool_name = "sram",
+ .reserved_dma_ranges = true,
+ .if_defs = {
+ .se_if_type = SE_TYPE_ID_HSM,
+ .cmd_tag = 0x17,
+ .rsp_tag = 0xe1,
+ .success_tag = ELE_SUCCESS_IND,
+ .base_api_ver = MESSAGING_VERSION_6,
+ .fw_api_ver = MESSAGING_VERSION_7,
+ },
+};
+
+static struct se_soc_info se_imx93_info = {
+ .soc_id = SOC_ID_OF_IMX93,
+};
+
+static struct se_if_node imx93_se_ele_hsm = {
+ .se_info = &se_imx93_info,
+ .reserved_dma_ranges = true,
+ .if_defs = {
+ .se_if_type = SE_TYPE_ID_HSM,
+ .cmd_tag = 0x17,
+ .rsp_tag = 0xe1,
+ .success_tag = ELE_SUCCESS_IND,
+ .base_api_ver = MESSAGING_VERSION_6,
+ .fw_api_ver = MESSAGING_VERSION_7,
+ },
+};
+
+static const struct of_device_id se_match[] = {
+ { .compatible = "fsl,imx8ulp-se-ele-hsm", .data = &imx8ulp_se_ele_hsm},
+ { .compatible = "fsl,imx93-se-ele-hsm", .data = &imx93_se_ele_hsm},
+ {},
+};
+
+char *get_se_if_name(u8 se_if_id)
+{
+ switch (se_if_id) {
+ case SE_TYPE_ID_DBG: return SE_TYPE_STR_DBG;
+ case SE_TYPE_ID_HSM: return SE_TYPE_STR_HSM;
+ }
+
+ return NULL;
+}
+
+static struct se_fw_load_info *get_load_fw_instance(struct se_if_priv *priv)
+{
+ return &var_se_info.load_fw;
+}
+
+static int get_se_soc_info(struct se_if_priv *priv, const struct se_soc_info *se_info)
+{
+ struct se_fw_load_info *load_fw = get_load_fw_instance(priv);
+ struct soc_device_attribute *attr;
+ u8 data[MAX_SOC_INFO_DATA_SZ];
+ struct ele_dev_info *s_info;
+ struct soc_device *sdev;
+ int err = 0;
+
+ /*
+ * This function should be called once.
+ * Check if the se_soc_rev is zero to continue.
+ */
+ if (var_se_info.soc_rev)
+ return err;
+
+ err = ele_fetch_soc_info(priv, &data);
+ if (err < 0)
+ return dev_err_probe(priv->dev, err, "Failed to fetch SoC Info.");
+ s_info = (void *)data;
+ var_se_info.soc_rev = s_info->d_info.soc_rev;
+ load_fw->imem.state = s_info->d_addn_info.imem_state;
+
+ if (!se_info->soc_name)
+ return 0;
+
+ attr = devm_kzalloc(priv->dev, sizeof(*attr), GFP_KERNEL);
+ if (!attr)
+ return -ENOMEM;
+
+ if (FIELD_GET(DEV_GETINFO_MIN_VER_MASK, var_se_info.soc_rev))
+ attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x.%x",
+ FIELD_GET(DEV_GETINFO_MIN_VER_MASK,
+ var_se_info.soc_rev),
+ FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+ var_se_info.soc_rev));
+ else
+ attr->revision = devm_kasprintf(priv->dev, GFP_KERNEL, "%x",
+ FIELD_GET(DEV_GETINFO_MAJ_VER_MASK,
+ var_se_info.soc_rev));
+
+ attr->soc_id = se_info->soc_name;
+
+ err = of_property_read_string(of_root, "model", &attr->machine);
+ if (err)
+ return -EINVAL;
+
+ attr->family = "Freescale i.MX";
+
+ attr->serial_number = devm_kasprintf(priv->dev,
+ GFP_KERNEL, "%016llX",
+ GET_SERIAL_NUM_FROM_UID(s_info->d_info.uid,
+ MAX_UID_SIZE >> 2));
+
+ sdev = soc_device_register(attr);
+ if (IS_ERR(sdev))
+ return PTR_ERR(sdev);
+
+ return 0;
+}
+
+/* interface for managed res to free a mailbox channel */
+static void if_mbox_free_channel(void *mbox_chan)
+{
+ mbox_free_channel(mbox_chan);
+}
+
+static int se_if_request_channel(struct device *dev, struct mbox_chan **chan,
+ struct mbox_client *cl, const char *name)
+{
+ struct mbox_chan *t_chan;
+ int ret = 0;
+
+ t_chan = mbox_request_channel_byname(cl, name);
+ if (IS_ERR(t_chan))
+ return dev_err_probe(dev, PTR_ERR(t_chan),
+ "Failed to request %s channel.", name);
+
+ ret = devm_add_action_or_reset(dev, if_mbox_free_channel, t_chan);
+ if (ret)
+ return dev_err_probe(dev, -EPERM,
+ "Failed to add-action for removal of mbox: %s.",
+ name);
+ *chan = t_chan;
+
+ return ret;
+}
+
+static void se_if_probe_cleanup(void *plat_dev)
+{
+ struct platform_device *pdev = plat_dev;
+ struct se_fw_load_info *load_fw;
+ struct device *dev = &pdev->dev;
+ struct se_if_priv *priv;
+
+ priv = dev_get_drvdata(dev);
+ if (!priv)
+ return;
+
+ load_fw = get_load_fw_instance(priv);
+
+ /*
+ * In se_if_request_channel(), passed the clean-up functional
+ * pointer reference as action to devm_add_action_or_reset().
+ * No need to free the mbox channels here.
+ */
+
+ /*
+ * free the buffer in se remove, previously allocated
+ * in se probe to store encrypted IMEM
+ */
+ if (load_fw && load_fw->imem.buf) {
+ dmam_free_coherent(dev, ELE_IMEM_SIZE, load_fw->imem.buf,
+ load_fw->imem.phyaddr);
+ load_fw->imem.buf = NULL;
+ }
+
+ /*
+ * No need to check, if reserved memory is allocated
+ * before calling for its release. Or clearing the
+ * un-set bit.
+ */
+ of_reserved_mem_device_release(dev);
+ dev_set_drvdata(dev, NULL);
+ kfree(priv);
+}
+
+static int se_if_probe(struct platform_device *pdev)
+{
+ const struct se_soc_info *se_info;
+ const struct se_if_node *if_node;
+ struct se_fw_load_info *load_fw;
+ struct device *dev = &pdev->dev;
+ struct se_if_priv *priv;
+ dma_addr_t imem_dma_addr;
+ int ret;
+
+ if_node = device_get_match_data(dev);
+ if (!if_node)
+ return -EINVAL;
+
+ se_info = if_node->se_info;
+
+ priv = kzalloc_obj(*priv, GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->if_defs = &if_node->if_defs;
+ dev_set_drvdata(dev, priv);
+
+ mutex_init(&priv->se_if_cmd_lock);
+ spin_lock_init(&priv->cmd_receiver_clbk_hdl.clbk_rx_lock);
+ spin_lock_init(&priv->waiting_rsp_clbk_hdl.clbk_rx_lock);
+ atomic_set(&priv->fw_busy, 0);
+ init_completion(&priv->waiting_rsp_clbk_hdl.done);
+ init_completion(&priv->cmd_receiver_clbk_hdl.done);
+
+ ret = devm_add_action_or_reset(dev, se_if_probe_cleanup, pdev);
+ if (ret)
+ return ret;
+
+ /* Mailbox client configuration */
+ priv->se_mb_cl.dev = dev;
+ priv->se_mb_cl.tx_block = false;
+ priv->se_mb_cl.knows_txdone = true;
+ priv->se_mb_cl.rx_callback = se_if_rx_callback;
+
+ ret = se_if_request_channel(dev, &priv->tx_chan, &priv->se_mb_cl, MBOX_TX_NAME);
+ if (ret)
+ return ret;
+
+ ret = se_if_request_channel(dev, &priv->rx_chan, &priv->se_mb_cl, MBOX_RX_NAME);
+ if (ret)
+ return ret;
+
+ if (if_node->pool_name) {
+ priv->mem_pool = of_gen_pool_get(dev->of_node, if_node->pool_name, 0);
+ if (!priv->mem_pool)
+ return dev_err_probe(dev, -ENOMEM,
+ "Unable to get sram pool = %s.",
+ if_node->pool_name);
+ }
+
+ if (if_node->reserved_dma_ranges) {
+ ret = of_reserved_mem_device_init(dev);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to init reserved memory region.");
+ }
+
+ if (if_node->if_defs.se_if_type == SE_TYPE_ID_HSM) {
+ ret = get_se_soc_info(priv, se_info);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to fetch SoC Info.");
+ }
+
+ /* By default, there is no pending FW to be loaded.*/
+ if (se_info->se_fw_img_nm.seco_fw_nm_in_rfs) {
+ load_fw = get_load_fw_instance(priv);
+ load_fw->se_fw_img_nm = &se_info->se_fw_img_nm;
+ load_fw->is_fw_tobe_loaded = true;
+
+ if (load_fw->se_fw_img_nm->prim_fw_nm_in_rfs) {
+ /* allocate buffer where SE store encrypted IMEM */
+ imem_dma_addr = phys_to_dma(priv->dev, load_fw->imem.phyaddr);
+ load_fw->imem.buf = dmam_alloc_coherent(priv->dev, ELE_IMEM_SIZE,
+ &imem_dma_addr, GFP_KERNEL);
+ if (!load_fw->imem.buf)
+ return dev_err_probe(dev, -ENOMEM,
+ "dmam-alloc-failed: To store encr-IMEM.");
+ load_fw->imem_mgmt = true;
+ }
+ }
+ dev_info(dev, "i.MX secure-enclave: %s0 interface to firmware, configured.",
+ get_se_if_name(priv->if_defs->se_if_type));
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int se_suspend(struct device *dev)
+{
+ struct se_if_priv *priv = dev_get_drvdata(dev);
+ struct se_fw_load_info *load_fw;
+ int ret = 0;
+
+ load_fw = get_load_fw_instance(priv);
+
+ if (load_fw->imem_mgmt) {
+ ret = se_save_imem_state(priv, &load_fw->imem);
+ if (ret)
+ dev_err(dev, "Failure saving IMEM state[0x%x]", ret);
+ }
+
+ return 0;
+}
+
+static int se_resume(struct device *dev)
+{
+ struct se_if_priv *priv = dev_get_drvdata(dev);
+ struct se_fw_load_info *load_fw;
+ int ret = 0;
+
+ load_fw = get_load_fw_instance(priv);
+
+ if (load_fw->imem_mgmt) {
+ se_restore_imem_state(priv, &load_fw->imem);
+ if (ret)
+ dev_err(dev, "Failure restoring IMEM state[0x%x]", ret);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops se_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(se_suspend, se_resume)
+};
+
+#define SE_PM_OPS (&se_pm)
+#else
+#define SE_PM_OPS NULL
+#endif
+
+static struct platform_driver se_driver = {
+ .driver = {
+ .name = "fsl-se",
+ .of_match_table = se_match,
+ .pm = SE_PM_OPS,
+ },
+ .probe = se_if_probe,
+};
+MODULE_DEVICE_TABLE(of, se_match);
+
+module_platform_driver(se_driver);
+MODULE_AUTHOR("Pankaj Gupta <pankaj.gupta@nxp.com>");
+MODULE_DESCRIPTION("iMX Secure Enclave Driver.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
new file mode 100644
index 000000000000..ef834a845e30
--- /dev/null
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2026 NXP
+ */
+
+#ifndef SE_MU_H
+#define SE_MU_H
+
+#include <linux/bitfield.h>
+#include <linux/miscdevice.h>
+#include <linux/semaphore.h>
+#include <linux/mailbox_client.h>
+
+#define MAX_FW_LOAD_RETRIES 50
+#define SE_MSG_WORD_SZ 0x4
+
+#define RES_STATUS(x) FIELD_GET(0x000000ff, x)
+#define MAX_NVM_MSG_LEN (256)
+#define MESSAGING_VERSION_6 0x6
+#define MESSAGING_VERSION_7 0x7
+
+struct se_clbk_handle {
+ struct completion done;
+ bool signal_rcvd;
+ u32 rx_msg_sz;
+ /*
+ * Assignment of the rx_msg buffer to held till the
+ * received content as part callback function, is copied.
+ */
+ struct se_api_msg *rx_msg;
+ /*
+ * Serialise the timeout path in ele_msg_rcv() against
+ * se_if_rx_callback() so that the callback can never
+ * memcpy into a buffer that the timeout path has already
+ * freed.
+ */
+ spinlock_t clbk_rx_lock;
+};
+
+struct se_imem_buf {
+ u8 *buf;
+ phys_addr_t phyaddr;
+ u32 size;
+ u32 state;
+};
+
+/* Header of the messages exchange with the EdgeLock Enclave */
+struct se_msg_hdr {
+ u8 ver;
+ u8 size;
+ u8 command;
+ u8 tag;
+} __packed;
+
+#define SE_MU_HDR_SZ 4
+
+struct se_api_msg {
+ struct se_msg_hdr header;
+ u32 data[];
+};
+
+struct se_if_defines {
+ const u8 se_if_type;
+ u8 cmd_tag;
+ u8 rsp_tag;
+ u8 success_tag;
+ u8 base_api_ver;
+ u8 fw_api_ver;
+};
+
+struct se_if_priv {
+ struct device *dev;
+
+ struct se_clbk_handle cmd_receiver_clbk_hdl;
+ /*
+ * Update to the waiting_rsp_dev, to be protected
+ * under se_if_cmd_lock.
+ */
+ struct se_clbk_handle waiting_rsp_clbk_hdl;
+ /*
+ * prevent new command to be sent on the se interface while previous
+ * command is still processing. (response is awaited)
+ */
+ struct mutex se_if_cmd_lock;
+
+ struct mbox_client se_mb_cl;
+ struct mbox_chan *tx_chan, *rx_chan;
+
+ struct gen_pool *mem_pool;
+ const struct se_if_defines *if_defs;
+ atomic_t fw_busy;
+};
+
+char *get_se_if_name(u8 se_if_id);
+#endif
diff --git a/include/linux/firmware/imx/se_api.h b/include/linux/firmware/imx/se_api.h
new file mode 100644
index 000000000000..b1c4c9115d7b
--- /dev/null
+++ b/include/linux/firmware/imx/se_api.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2025 NXP
+ */
+
+#ifndef __SE_API_H__
+#define __SE_API_H__
+
+#include <linux/types.h>
+
+#define SOC_ID_OF_IMX8ULP 0x084d
+#define SOC_ID_OF_IMX93 0x9300
+
+#endif /* __SE_API_H__ */
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 0/3] arm64: dts: rockchip: Add Youyeetoo YY3588
From: Daniele Briguglio @ 2026-06-29 7:59 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner
Cc: devicetree, linux-kernel, linux-arm-kernel, linux-rockchip
In-Reply-To: <20260610-yy3588-board-v1-0-4bb7176b6826@superkali.me>
On Wed, Jun 10, 2026 at 03:58:57PM +0200, Daniele Briguglio wrote:
> This series adds support for the Youyeetoo YY3588, a single board
> computer built around the Rockchip RK3588.
> [...]
Hi Heiko,
Gentle ping on this one, it's been about three weeks. Conor acked the
vendor-prefixes and rockchip.yaml patches (1/3 and 2/3). The dts in 3/3
hasn't had any comments yet, and I'd hate for it to slip through.
I know the dts queue is long, so no rush. Anything you'd want changed, or
is it OK to queue for the next cycle? Happy to respin if there's something
to fix.
Thanks,
Daniele
^ permalink raw reply
* RE: [PATCH 5/7] soc: aspeed: Add eSPI flash channel support
From: YH Chung @ 2026-06-29 8:10 UTC (permalink / raw)
To: Markus Elfring, linux-aspeed@lists.ozlabs.org,
openbmc@lists.ozlabs.org, linux-arm-kernel@lists.infradead.org,
devicetree@vger.kernel.org, Andrew Jeffery, Conor Dooley,
Joel Stanley, Krzysztof Kozlowski, Philipp Zabel, Rob Herring,
Ryan Chen
Cc: LKML, Maciej Lawniczak
In-Reply-To: <e78c2122-d10b-41ce-af94-45f573306c43@web.de>
Hi Markus,
> > +++ b/drivers/soc/aspeed/espi/aspeed-espi-comm.h
> > @@ -0,0 +1,62 @@
> …
> > +/*
> > + * eSPI cycle type encoding
> > + *
> > + * Section 5.1 Cycle Types and Packet Format,
> > + * Intel eSPI Interface Base Specification, Rev 1.0, Jan. 2016.
> > + */
> > +#define ESPI_FLASH_READ 0x00
> > +#define ESPI_FLASH_WRITE 0x01
> > +#define ESPI_FLASH_ERASE 0x02
> …
>
> How do you think about to use an enumeration for such data?
> https://en.wikipedia.org/wiki/Enumerated_type#C_and_syntactically_similar_lan
> guages
Thanks for the feedback. Yes, these values are related cycle type encodings,
so using an enum makes sense. I will update them, as well as other
specification-defined encodings, to enums in the next revision, while still
using fixed-width types such as `u8` for the actual packet/register fields.
Thanks,
Yun-Hsuan
^ permalink raw reply
* RE: [PATCH] misc: xilinx_sdfec: validate LDPC code register offsets
From: Cvetic, Dragan @ 2026-06-29 8:14 UTC (permalink / raw)
To: Yousef Alhouseen, Kiernan, Derek
Cc: Arnd Bergmann, Greg Kroah-Hartman, Simek, Michal,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20260624190812.3075-1-alhouseenyousef@gmail.com>
AMD General
> -----Original Message-----
> From: Yousef Alhouseen <alhouseenyousef@gmail.com>
> Sent: Wednesday 24 June 2026 20:08
> To: Kiernan, Derek <derek.kiernan@amd.com>; Cvetic, Dragan
> <dragan.cvetic@amd.com>
> Cc: Arnd Bergmann <arnd@arndb.de>; Greg Kroah-Hartman
> <gregkh@linuxfoundation.org>; Simek, Michal <michal.simek@amd.com>;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; Yousef
> Alhouseen <alhouseenyousef@gmail.com>
> Subject: [PATCH] misc: xilinx_sdfec: validate LDPC code register offsets
>
> The LDPC code register helpers check the target MMIO address after adding
> code_id * XSDFEC_LDPC_REG_JUMP to the register base. code_id is supplied
> through the ioctl path, so the multiplication and addition can wrap before
> the bounds check.
>
> Validate the code_id against the register window size before computing
> the final address, then write using the checked address.
>
> Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
> ---
> drivers/misc/xilinx_sdfec.c | 72 +++++++++++++++++--------------------
> 1 file changed, 32 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
> index 3135ba3a5..63f0eb2bd 100644
> --- a/drivers/misc/xilinx_sdfec.c
> +++ b/drivers/misc/xilinx_sdfec.c
> @@ -456,10 +456,23 @@ static int xsdfec_get_turbo(struct xsdfec_dev
> *xsdfec, void __user *arg)
> return err;
> }
>
> +static int xsdfec_ldpc_reg_addr(struct xsdfec_dev *xsdfec, u32 base, u32
> high,
> + u32 offset, u32 *addr)
> +{
> + if (offset > (high - base) / XSDFEC_LDPC_REG_JUMP) {
If someone accidentally passes swapped high, base constants in the future, this underflows because they're unsigned.
Check if (high-base) >=0
> + dev_dbg(xsdfec->dev, "Writing outside of LDPC register
> space");
> + return -EINVAL;
> + }
> +
> + *addr = base + offset * XSDFEC_LDPC_REG_JUMP;
> + return 0;
> +}
> +
> static int xsdfec_reg0_write(struct xsdfec_dev *xsdfec, u32 n, u32 k, u32
> psize,
> u32 offset)
> {
> u32 wdata;
> + u32 addr;
>
> if (n < XSDFEC_REG0_N_MIN || n > XSDFEC_REG0_N_MAX || psize ==
> 0 ||
> (n > XSDFEC_REG0_N_MUL_P * psize) || n <= k || ((n % psize) != 0))
> {
> @@ -476,17 +489,11 @@ static int xsdfec_reg0_write(struct xsdfec_dev
> *xsdfec, u32 n, u32 k, u32 psize,
> k = k << XSDFEC_REG0_K_LSB;
> wdata = k | n;
>
> - if (XSDFEC_LDPC_CODE_REG0_ADDR_BASE + (offset *
> XSDFEC_LDPC_REG_JUMP) >
> - XSDFEC_LDPC_CODE_REG0_ADDR_HIGH) {
> - dev_dbg(xsdfec->dev, "Writing outside of LDPC reg0 space
> 0x%x",
> - XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP));
> + if (xsdfec_ldpc_reg_addr(xsdfec,
> XSDFEC_LDPC_CODE_REG0_ADDR_BASE,
> + XSDFEC_LDPC_CODE_REG0_ADDR_HIGH,
> offset,
> + &addr))
Put debug message, previous code had debug message.
> return -EINVAL;
> - }
> - xsdfec_regwrite(xsdfec,
> - XSDFEC_LDPC_CODE_REG0_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP),
> - wdata);
> + xsdfec_regwrite(xsdfec, addr, wdata);
> return 0;
> }
>
> @@ -494,6 +501,7 @@ static int xsdfec_reg1_write(struct xsdfec_dev
> *xsdfec, u32 psize,
> u32 no_packing, u32 nm, u32 offset)
> {
> u32 wdata;
> + u32 addr;
>
> if (psize < XSDFEC_REG1_PSIZE_MIN || psize >
> XSDFEC_REG1_PSIZE_MAX) {
> dev_dbg(xsdfec->dev, "Psize is not in range");
> @@ -510,17 +518,11 @@ static int xsdfec_reg1_write(struct xsdfec_dev
> *xsdfec, u32 psize,
> nm = (nm << XSDFEC_REG1_NM_LSB) & XSDFEC_REG1_NM_MASK;
>
> wdata = nm | no_packing | psize;
> - if (XSDFEC_LDPC_CODE_REG1_ADDR_BASE + (offset *
> XSDFEC_LDPC_REG_JUMP) >
> - XSDFEC_LDPC_CODE_REG1_ADDR_HIGH) {
> - dev_dbg(xsdfec->dev, "Writing outside of LDPC reg1 space
> 0x%x",
> - XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP));
> + if (xsdfec_ldpc_reg_addr(xsdfec,
> XSDFEC_LDPC_CODE_REG1_ADDR_BASE,
> + XSDFEC_LDPC_CODE_REG1_ADDR_HIGH,
> offset,
> + &addr))
Put debug message, previous code had debug message.
> return -EINVAL;
> - }
> - xsdfec_regwrite(xsdfec,
> - XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP),
> - wdata);
> + xsdfec_regwrite(xsdfec, addr, wdata);
> return 0;
> }
>
> @@ -529,6 +531,7 @@ static int xsdfec_reg2_write(struct xsdfec_dev
> *xsdfec, u32 nlayers, u32 nmqc,
> u32 max_schedule, u32 offset)
> {
> u32 wdata;
> + u32 addr;
>
> if (nlayers < XSDFEC_REG2_NLAYERS_MIN ||
> nlayers > XSDFEC_REG2_NLAYERS_MAX) {
> @@ -563,17 +566,11 @@ static int xsdfec_reg2_write(struct xsdfec_dev
> *xsdfec, u32 nlayers, u32 nmqc,
> wdata = (max_schedule | no_final_parity | special_qc | norm_type |
> nmqc | nlayers);
>
> - if (XSDFEC_LDPC_CODE_REG2_ADDR_BASE + (offset *
> XSDFEC_LDPC_REG_JUMP) >
> - XSDFEC_LDPC_CODE_REG2_ADDR_HIGH) {
> - dev_dbg(xsdfec->dev, "Writing outside of LDPC reg2 space
> 0x%x",
> - XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP));
> + if (xsdfec_ldpc_reg_addr(xsdfec,
> XSDFEC_LDPC_CODE_REG2_ADDR_BASE,
> + XSDFEC_LDPC_CODE_REG2_ADDR_HIGH,
> offset,
> + &addr))
Put debug message, previous code had debug message.
> return -EINVAL;
> - }
> - xsdfec_regwrite(xsdfec,
> - XSDFEC_LDPC_CODE_REG2_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP),
> - wdata);
> + xsdfec_regwrite(xsdfec, addr, wdata);
> return 0;
> }
>
> @@ -581,20 +578,15 @@ static int xsdfec_reg3_write(struct xsdfec_dev
> *xsdfec, u8 sc_off, u8 la_off,
> u16 qc_off, u32 offset)
> {
> u32 wdata;
> + u32 addr;
>
> wdata = ((qc_off << XSDFEC_REG3_QC_OFF_LSB) |
> (la_off << XSDFEC_REG3_LA_OFF_LSB) | sc_off);
> - if (XSDFEC_LDPC_CODE_REG3_ADDR_BASE + (offset *
> XSDFEC_LDPC_REG_JUMP) >
> - XSDFEC_LDPC_CODE_REG3_ADDR_HIGH) {
> - dev_dbg(xsdfec->dev, "Writing outside of LDPC reg3 space
> 0x%x",
> - XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP));
> + if (xsdfec_ldpc_reg_addr(xsdfec,
> XSDFEC_LDPC_CODE_REG3_ADDR_BASE,
> + XSDFEC_LDPC_CODE_REG3_ADDR_HIGH,
> offset,
> + &addr))
Put debug message, previous code had debug message.
> return -EINVAL;
> - }
> - xsdfec_regwrite(xsdfec,
> - XSDFEC_LDPC_CODE_REG3_ADDR_BASE +
> - (offset * XSDFEC_LDPC_REG_JUMP),
> - wdata);
> + xsdfec_regwrite(xsdfec, addr, wdata);
> return 0;
> }
>
> --
> 2.54.0
Dragan
Regards
^ permalink raw reply
* RE: [PATCH 5/7] soc: aspeed: Add eSPI flash channel support
From: YH Chung @ 2026-06-29 8:15 UTC (permalink / raw)
To: Markus Elfring, linux-aspeed@lists.ozlabs.org,
openbmc@lists.ozlabs.org, linux-arm-kernel@lists.infradead.org,
devicetree@vger.kernel.org, Andrew Jeffery, Conor Dooley,
Joel Stanley, Krzysztof Kozlowski, Philipp Zabel, Rob Herring,
Ryan Chen
Cc: LKML, Maciej Lawniczak
In-Reply-To: <3ab543eb-ca09-4d75-b75c-b8a4c71b2173@web.de>
Hi Markus,
> > +++ b/drivers/soc/aspeed/espi/aspeed-espi.c
> …
> > +static void aspeed_espi_flash_rx_work(struct work_struct *work) {
> > + struct aspeed_espi_flash *flash = container_of(work, struct
> aspeed_espi_flash, rx_work);
> > + struct aspeed_espi *espi = container_of(flash, struct aspeed_espi,
> > +flash);
> > +
> > + mutex_lock(&flash->tx_mtx);
> > + aspeed_espi_flash_handle_lun(espi);
> > + mutex_unlock(&flash->tx_mtx);
> > +}
> …
>
> Under which circumstances would you become interested to apply a statement
> like “guard(mutex)(&flash->tx_mtx);”?
> https://elixir.bootlin.com/linux/v7.1.1/source/include/linux/mutex.h#L253
>
Thanks for the suggestion. I agree that guard(mutex) is helpful when a locked
section has multiple exit paths. Since this worker currently has a single
simple path, I would prefer to keep the explicit mutex_lock()/mutex_unlock()
pair for readability. I can switch to guard(mutex) if you think it would be
better in this case.
Thanks,
Yun Hsuan
^ permalink raw reply
* Re: [PATCH v4 00/31] Introduce SCMI Telemetry FS support
From: Christian Brauner @ 2026-06-29 8:22 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Cristian Marussi, Christian Brauner, linux-kernel,
linux-arm-kernel, arm-scmi, linux-fsdevel, linux-doc,
sudeep.holla, james.quinlan, f.fainelli, vincent.guittot,
etienne.carriere, peng.fan, michal.simek, d-gole, jic23,
elif.topuz, lukasz.luba, philip.radford, souvik.chakravarty,
leitao, kas, puranjay, usama.arif, kernel-team
In-Reply-To: <eba18827-5ef5-464c-90f0-2444a996acac@kernel.org>
> > Thanks a lot, David !
>
> Let's hope for some guidance regarding the FS side soon.
>
> But yeah, avoiding the in-kernel FS sounds completely reasonable at this point.
Afaiu, David wanted me to add a few comments on the viability of a
character device for this.
I think you usually have at least the following options:
(1) character device
(2) notification pipe
(3) netlink
(4) well-known AF_UNIX socket
You then need to consider your constraints. David added a few:
(i) root can set properties (enable/disable events)
(ii) non-root can only retrieve properties/events
I assume you mean real root, i.e., root on the host system or more
specifically anyone with CAP_SYS_ADMIN or some other relevant
capability.
This is a rather simple model and gets a lot of head-scratching out of
the way.
But root could also mean "root in a users namespace" which makes this
more complicated as it effectively means that an unprivileged container
would be enable/disable events. This makes sense if there's a subset of
events that naturally lends itself to be charged to a container and that
the container might have a genuine use for.
This touches on another design question which decides how complicated
the whole implementation is going to be: What consumer-producer
relationship does this need?
The process subscribing to the telemetry stream might have exclusive
access. IOW, once you have subscribed to the telemetry stream the
connect is busy and no new subscribers are allowed. This is a very
simple model ofc which has advantages.
On the other end you have the uevent model. Uevents are broadcast to all
subscribers who have a uevent netlink socket open (glossing over some
namespacing details that are irrelevant here).
You need to figure out what you really need here. The choice of
transport also has quality of life implications.
(1):
A character device is somewhat simple but it means it's all inherently
tied to devtmpfs and namespacing it retroactively is not possible. If
you ever want to namespace it, i.e., delegate it to unprivileged
sandboxes, userspace needs to bind-mount the character device into the
container at container startup or have a mechanism to inject said
character devices later via the new mount api. It's all possible I'm
just pointing out that you're tied to a rather rigid kernel object. But
I think in general it is ok.
(2):
A while ago David Howells extended pipes with the concept of a
watchqueue. A watchqueue is just a pipe with some special properties. It
can be created by passing O_NOTIFICATION to pipe(2) "meticulously
undocumented" as Jon would say...) into which the kernel splices small,
fixed-format notification records:
int fds[2];
pipe2(fds, O_NOTIFICATION_PIPE);
ioctl(fds[0], IOC_WATCH_QUEUE_SET_SIZE, nr_notes); /* preallocate, 1..512 */
ioctl(fds[0], IOC_WATCH_QUEUE_SET_FILTER, &filter); /* optional */
keyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fds[0], 0x01); /* subscribe a source */
If the ring is full or no free note exists, the record is dropped and
PIPE_BUF_FLAG_LOSS is set on the last buffer. So consumers always learn
that they missed something — but not what.
IOC_WATCH_QUEUE_SET_FILTER takes struct watch_notification_filter with
up to 16 watch_notification_type_filter entries. With a filter installed
the default is reject and only the type bit + subtype bit + info match
let a record through. Passing NULL removes all filters (everything
passes).
Kinda like a ringbuffer might be something to consider.
O_NOTIFICATION_PIPE works from all contexts (hence the preallocation).
(3):
No.
(4):
A while ago I added the "coredump socket" to the kernel. Basically,
userspace listens on a well-known AF_UNIX socket address (in this case
configured via /proc/sys/kernel/core_pattern). The kernel connects to it
and sends the coredump data via this socket (with some protocol
negotiation at the beginning).
If you really want to transform the data stream you're receiving into a
FUSE filesystem I think any of the referenced methods is compatible with
that. You just refresh the various files when new events come in and
otherwise show the data that you already have.
In other words, if you allow multiple consumers the following scenario
may happen: Consumer A consumes event E_1 and consumer B consumes E_2,
consumer A now gets E_3. If consumer A is what funnels the data into a
filesystem then consumer A misses data. That might be fine or might not
be.
^ permalink raw reply
* [PATCH v26 1/7] Documentation/firmware: add imx/se to other_interfaces
From: pankaj.gupta @ 2026-06-29 12:21 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Pankaj Gupta
Cc: linux-doc, linux-kernel, devicetree, imx, linux-arm-kernel
In-Reply-To: <20260629-imx-se-if-v26-0-146446285744@nxp.com>
From: Pankaj Gupta <pankaj.gupta@nxp.com>
Documents i.MX SoC's Service layer and C_DEV driver for selected SoC(s)
that contains the NXP hardware IP(s) for Secure Enclaves(se) like:
- NXP EdgeLock Enclave on i.MX93 & i.MX8ULP
Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
.../driver-api/firmware/other_interfaces.rst | 133 +++++++++++++++++++++
1 file changed, 133 insertions(+)
diff --git a/Documentation/driver-api/firmware/other_interfaces.rst b/Documentation/driver-api/firmware/other_interfaces.rst
index 06ac89adaafb..6c6fa9a0ba1d 100644
--- a/Documentation/driver-api/firmware/other_interfaces.rst
+++ b/Documentation/driver-api/firmware/other_interfaces.rst
@@ -49,3 +49,136 @@ of the requests on to a secure monitor (EL3).
.. kernel-doc:: drivers/firmware/stratix10-svc.c
:export:
+
+NXP Secure Enclave Firmware Interface
+=====================================
+
+Introduction
+------------
+The NXP's i.MX HW IP like EdgeLock Enclave, V2X etc., creates an embedded secure
+enclave within the SoC boundary to enable features like:
+
+- Hardware Security Module (HSM)
+- Security Hardware Extension (SHE)
+- Vehicular to Anything (V2X)
+
+Each of the above features is enabled through dedicated NXP H/W IP on the SoC.
+On a single SoC, multiple hardware IP (or can say more than one secure enclave)
+can exist.
+
+NXP SoCs enabled with the such secure enclaves(SEs) IPs are:
+i.MX93, i.MX8ULP
+
+To communicate with one or more co-existing SE(s) on SoC, there is/are dedicated
+messaging units(MU) per SE. Each co-existing SE can have one or multiple exclusive
+MUs, dedicated to itself. None of the MU is shared between two SEs. Communication
+of the MU is realized using the mailbox driver. Each secure enclave can cater to
+multiple clients by virtue of these exclusive MUs. Also, they can distinguish
+transactions originating from these clients based on the MU used and core security
+state. The communication between the clients and secure enclaves is in the form of
+a command/response mechanism. Each client could expose a specific set of secure enclave
+features to the higher layers, based on the commands supported by that client. For
+example, the secure enclave could simultaneously support an OPTEE TA and Linux
+middleware as clients. Each of these clients can expose a specific set of secure
+enclave features based on the command set supported by them.
+
+NXP Secure Enclave(SE) Interface
+--------------------------------
+MU(s) is/are not shared between SE(s). But for an SoC like i.MX95 which has
+multiple SE(s) like HSM, V2X-HSM, V2X-SHE, all the SE(s) and their interfaces 'se-if'
+that is/are dedicated to a particular SE will be enumerated and provisioned using the
+single compatible node("fsl,imx95-se").
+
+Each 'se-if' comprises two layers:
+
+- (C_DEV Layer) User-Space software-access interface.
+- (Service Layer) OS-level software-access interface.
+
+::
+
+ +--------------------------------------------+
+ | Character Device(C_DEV) |
+ | |
+ | +---------+ +---------+ +---------+ |
+ | | misc #1 | | misc #2 | ... | misc #n | |
+ | | dev | | dev | | dev | |
+ | +---------+ +---------+ +---------+ |
+ | +-------------------------+ |
+ | | Misc. Dev Synchr. Logic | |
+ | +-------------------------+ |
+ | |
+ +--------------------------------------------+
+
+ +--------------------------------------------+
+ | Service Layer |
+ | |
+ | +-----------------------------+ |
+ | | Message Serialization Logic | |
+ | +-----------------------------+ |
+ | +---------------+ |
+ | | imx-mailbox | |
+ | | mailbox.c | |
+ | +---------------+ |
+ | |
+ +--------------------------------------------+
+
+- service layer:
+ This layer is responsible for ensuring the communication protocol that is defined
+ for communication with firmware.
+
+ FW Communication protocol ensures two things:
+
+ - Serializing the messages to be sent over an MU.
+ - FW can handle one command message at a time.
+
+- c_dev:
+ This layer offers character device contexts, created as '/dev/<se>_mux_chx'.
+ Using these multiple device contexts that are multiplexed over a single MU,
+ userspace application(s) can call fops like write/read to send the command message,
+ and read back the command response message to/from Firmware.
+ fops like read & write use the above defined service layer API(s) to communicate with
+ Firmware.
+
+ Misc-device(/dev/<se>_mux_chn) synchronization protocol::
+
+ Non-Secure + Secure
+ |
+ |
+ +-----------+ +-------------+ |
+ | se_ctrl.c +<---->+imx-mailbox.c| |
+ | | | mailbox.c +<-->+------+ +------+
+ +-----+-----+ +-------------+ | MU X +<-->+ ELE |
+ | +------+ +------+
+ +----------------+ |
+ | | |
+ v v |
+ logical logical |
+ receiver waiter |
+ + + |
+ | | |
+ | | |
+ | +----+------+ |
+ | | | |
+ | | | |
+ device_ctx device_ctx device_ctx |
+ |
+ User 0 User 1 User Y |
+ +------+ +------+ +------+ |
+ |misc.c| |misc.c| |misc.c| |
+ kernel space +------+ +------+ +------+ |
+ |
+ +---------------------------------------------------- |
+ | | | |
+ userspace /dev/ele_muXch0 | | |
+ /dev/ele_muXch1 | |
+ /dev/ele_muXchY |
+ |
+
+When a user sends a command to the firmware, it registers its device_ctx
+as waiter of a response from firmware.
+
+Enclave's Firmware owns the storage management over a Linux filesystem.
+For this c_dev provisions a dedicated slave device called "receiver".
+
+.. kernel-doc:: drivers/firmware/imx/se_ctrl.c
+ :export:
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v15 1/9] drm/bridge: Implement generic USB Type-C DP HPD bridge
From: Xu Yang @ 2026-06-29 8:26 UTC (permalink / raw)
To: Chaoyi Chen
Cc: Heikki Krogerus, Chaoyi Chen, Greg Kroah-Hartman,
Dmitry Baryshkov, Peter Chen, Luca Ceresoli, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul,
Kishon Vijay Abraham I, Heiko Stuebner, Sandy Huang, Andy Yan,
Yubing Zhang, Frank Wang, Andrzej Hajda, Neil Armstrong,
Robert Foss, Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Amit Sunil Dhamne, Dragan Simic, Johan Jonker,
Diederik de Haas, Peter Robinson, Hugh Cole-Baker, linux-usb,
devicetree, linux-kernel, linux-phy, linux-arm-kernel,
linux-rockchip, dri-devel
In-Reply-To: <56c6abb8-c127-449f-9368-12f94620c2bc@rock-chips.com>
On Mon, Jun 29, 2026 at 09:29:08AM +0800, Chaoyi Chen wrote:
> Hello Xu Yang,
>
> On 6/26/2026 7:15 PM, Xu Yang wrote:
> > On Wed, Mar 04, 2026 at 05:41:44PM +0800, Chaoyi Chen wrote:
> >> From: Chaoyi Chen <chaoyi.chen@rock-chips.com>
> >>
> >> The HPD function of Type-C DP is implemented through
> >> drm_connector_oob_hotplug_event(). For embedded DP, it is required
> >> that the DRM connector fwnode corresponds to the Type-C port fwnode.
> >>
> >> To describe the relationship between the DP controller and the Type-C
> >> port device, we usually using drm_bridge to build a bridge chain.
> >>
> >> Now several USB-C controller drivers have already implemented the DP
> >> HPD bridge function provided by aux-hpd-bridge.c, it will build a DP
> >> HPD bridge on USB-C connector port device.
> >>
> >> But this requires the USB-C controller driver to manually register the
> >> HPD bridge. If the driver does not implement this feature, the bridge
> >> will not be create.
> >>
> >> So this patch implements a generic DP HPD bridge based on
> >> aux-hpd-bridge.c. It will monitor Type-C bus events, and when a
> >> Type-C port device containing the DP svid is registered, it will
> >> create an HPD bridge for it without the need for the USB-C controller
> >> driver to implement it.
> >>
> >> Signed-off-by: Chaoyi Chen <chaoyi.chen@rock-chips.com>
> >> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> >> ---
> >>
> >> (no changes since v14)
> >>
> >> Changes in v13:
> >> - Only register drm dp hpd bridge for typec port altmode device.
> >>
> >> (no changes since v12)
> >>
> >> Changes in v11:
> >> - Switch to using typec bus notifiers.
> >>
> >> (no changes since v10)
> >>
> >> Changes in v9:
> >> - Remove the exposed DRM_AUX_HPD_BRIDGE option, and select
> >> DRM_AUX_HPD_TYPEC_BRIDGE when it is available.
> >> - Add more commit comment about problem background.
> >>
> >> Changes in v8:
> >> - Merge generic DP HPD bridge into one module.
> >> ---
> >>
> >> drivers/gpu/drm/bridge/Kconfig | 10 ++++
> >> drivers/gpu/drm/bridge/Makefile | 1 +
> >> .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c | 49 +++++++++++++++++++
> >> 3 files changed, 60 insertions(+)
> >> create mode 100644 drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
> >>
> >> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
> >> index a250afd8d662..559487aa09a9 100644
> >> --- a/drivers/gpu/drm/bridge/Kconfig
> >> +++ b/drivers/gpu/drm/bridge/Kconfig
> >> @@ -30,6 +30,16 @@ config DRM_AUX_HPD_BRIDGE
> >> Simple bridge that terminates the bridge chain and provides HPD
> >> support.
> >>
> >> +if DRM_AUX_HPD_BRIDGE
> >> +config DRM_AUX_HPD_TYPEC_BRIDGE
> >> + tristate
> >> + depends on TYPEC || !TYPEC
> >> + default TYPEC
> >> + help
> >> + Simple bridge that terminates the bridge chain and provides HPD
> >> + support. It build bridge on each USB-C connector device node.
> >> +endif
> >> +
> >
> > Should CONFIG_TYPEC_DP_ALTMODE select this one? Otherwise, we need to do it
> > manually.
> >
> > $ grep -nr --include=Kconfig "select DRM_AUX_HPD_BRIDGE" .
> > ./drivers/soc/qcom/Kconfig:118: select DRM_AUX_HPD_BRIDGE
> > ./drivers/usb/typec/ucsi/Kconfig:88: select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
> > ./drivers/usb/typec/ucsi/Kconfig:99: select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
> > ./drivers/usb/typec/tcpm/Kconfig:62: select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
> > ./drivers/usb/typec/tcpm/Kconfig:85: select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
> >
>
> That's a fair point. But based on the previous discussion, Heikki
> point out that configurations in the TYPEC subsystem should not
> select configurations from DRM.
I have just reviewed your previous patchsets but I did't find such opinion from
Heikki. Otherwise, why are tcpm.c/ucsi.c already allowed to add the above select
condition in their configs?
I think Heikki means that the DRM_AUX_HPD_BRIDGE shouldn't been selected at the
top level of Type-C subsystem. Because not all Type-C devices support the DP function.
As a generic Type-C DP HPD bridge, displayport.c will likely need to use it in
the future. Therefore, allowing displayport.c to select DRM_AUX_HPD_BRIDGE makes sense.
According to my testing, it's impossible to build this driver in unless TYPEC_FUSB302
or a relevant CONFIG is built in to select DRM_AUX_HPD_BRIDGE, or the defconfig is modified.
Thanks,
Xu Yang
^ permalink raw reply
* Re: [PATCH 2/3] dt-bindings: arm: rockchip: Add Graperain G3568 series
From: Coia Prant @ 2026-06-29 8:29 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Heiko Stuebner,
Dragan Simic, Jonas Karlman, devicetree, linux-arm-kernel,
linux-rockchip, linux-kernel
In-Reply-To: <20260629-fabulous-muskrat-of-romance-cd1bef@quoll>
On Mon, Jun 29, 2026 at 03:12:XXPM +0800, Krzysztof Kozlowski wrote:
> On Sun, Jun 28, 2026 at 06:57:56AM +0800, Coia Prant wrote:
> > This documents Graperain G3568 v2 which is a development board based on RK3568 SoC.
>
> "Document"
>
> Please do not use "This commit/patch/change", but imperative mood. See
> longer explanation here:
> https://elixir.bootlin.com/linux/v6.16/source/Documentation/process/submitting-patches.rst#L94
Thank you for pointing this out. I have revised the commit message to
use imperative mood and split the overlong line to stay within 75
characters.
> > This series also have an SBC series with the suffix "box".
> >
> > This board is development board series, not SBC series.
>
> Remember to also address Sashiko review.
Okay.
> > Link: ...
> > Signed-off-by: ...
> > ---
> > ...
> > +
>
> Looks like you just added bunch of format-patch and check-patch
> warnings...
I have re‑run checkpatch on the entire series and fixed all trailing
whitespace and other formatting issues. The patch set should now be
clean (except for a hardware‑list line in the third patch which I kept
intact for readability).
Apologies for the oversight – it was late night work.
I will send a v2 with all fixes shortly.
Best,
Coia
^ permalink raw reply
* Re: [PATCH 1/2] arm64: dts: xilinx: drop bias-high-impedance on SDIO CD/WP pins
From: Michal Simek @ 2026-06-29 8:33 UTC (permalink / raw)
To: linux-kernel, monstr, git
Cc: mikko.rapeli, Conor Dooley, Krzysztof Kozlowski, Rob Herring,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
moderated list:ARM/ZYNQ ARCHITECTURE
In-Reply-To: <e01c8e60e1d9ed68c347f1a3741f89149109d8b7.1780496388.git.michal.simek@amd.com>
On 6/3/26 16:19, Michal Simek wrote:
> Since commit 9c105255108b ("pinctrl: pinconf-generic: perform basic
> checks on pincfg properties"), the generic pinconf parser logs an error
> when a pin configuration node specifies more than one bias mode.
> Several ZynqMP boards described SDIO card-detect and write-protect pins
> with both bias-high-impedance and bias-pull-up, which triggers at
> pinctrl probe:
>
> generic pinconfig core: /firmware/zynqmp-firmware/pinctrl/.../conf-cd:
> cannot have multiple bias configurations
>
> On ZynqMP, bias-high-impedance enables tri-state while bias-pull-up
> enables the internal pull resistor; these are mutually exclusive bias
> settings and only pull-up is needed for CD/WP inputs. Drop the redundant
> bias-high-impedance property and keep bias-pull-up.
>
> Reported-by: Mikko Rapeli (Linaro) <mikko.rapeli@linaro.org>
> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221586
> Signed-off-by: Michal Simek <michal.simek@amd.com>
> ---
>
> arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso | 1 -
> arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso | 1 -
> arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts | 4 ----
> arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts | 2 --
> arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts | 1 -
> arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts | 2 --
> arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts | 1 -
> arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts | 1 -
> arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts | 2 --
> arch/arm64/boot/dts/xilinx/zynqmp-zcu111-revA.dts | 1 -
> 10 files changed, 16 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso
> index 923a70d750bf..44834bf1c19c 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revA.dtso
> @@ -374,7 +374,6 @@ conf {
>
> conf-cd {
> groups = "sdio1_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso
> index 563e750b0e08..49732de5fa4b 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-sck-kv-g-revB.dtso
> @@ -365,7 +365,6 @@ conf {
>
> conf-cd {
> groups = "sdio1_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts
> index 6aff22d43361..f57987dad50f 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm015-dc1.dts
> @@ -270,7 +270,6 @@ mux-cd {
>
> conf-cd {
> groups = "sdio0_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> @@ -283,7 +282,6 @@ mux-wp {
>
> conf-wp {
> groups = "sdio0_wp_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> @@ -310,7 +308,6 @@ mux-cd {
>
> conf-cd {
> groups = "sdio1_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> @@ -323,7 +320,6 @@ mux-wp {
>
> conf-wp {
> groups = "sdio1_wp_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts
> index 53aa3dca1dca..737d445dc16b 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zc1751-xm019-dc5.dts
> @@ -270,7 +270,6 @@ mux-cd {
>
> conf-cd {
> groups = "sdio0_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> @@ -283,7 +282,6 @@ mux-wp {
>
> conf-wp {
> groups = "sdio0_wp_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts
> index 4ec8a400494e..41f312a82bb4 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu100-revC.dts
> @@ -320,7 +320,6 @@ mux-cd {
>
> conf-cd {
> groups = "sdio0_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts
> index e172a30e7b21..a5bc521ab679 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu102-revA.dts
> @@ -896,7 +896,6 @@ mux-cd {
>
> conf-cd {
> groups = "sdio1_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> @@ -909,7 +908,6 @@ mux-wp {
>
> conf-wp {
> groups = "sdio1_wp_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts
> index fe8f151ed706..32509083e54f 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revA.dts
> @@ -359,7 +359,6 @@ mux-cd {
>
> conf-cd {
> groups = "sdio1_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts
> index 3ee8ab224722..96699be8430f 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu104-revC.dts
> @@ -371,7 +371,6 @@ mux-cd {
>
> conf-cd {
> groups = "sdio1_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts
> index 7f6c87d4d77e..52441e5c8739 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu106-revA.dts
> @@ -895,7 +895,6 @@ mux-cd {
>
> conf-cd {
> groups = "sdio1_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> @@ -908,7 +907,6 @@ mux-wp {
>
> conf-wp {
> groups = "sdio1_wp_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
> diff --git a/arch/arm64/boot/dts/xilinx/zynqmp-zcu111-revA.dts b/arch/arm64/boot/dts/xilinx/zynqmp-zcu111-revA.dts
> index 428b5558fbba..b34e4c93d249 100644
> --- a/arch/arm64/boot/dts/xilinx/zynqmp-zcu111-revA.dts
> +++ b/arch/arm64/boot/dts/xilinx/zynqmp-zcu111-revA.dts
> @@ -750,7 +750,6 @@ mux-cd {
>
> conf-cd {
> groups = "sdio1_cd_0_grp";
> - bias-high-impedance;
> bias-pull-up;
> slew-rate = <SLEW_RATE_SLOW>;
> power-source = <IO_STANDARD_LVCMOS18>;
Applied.
M
^ permalink raw reply
* Re: [PATCH] ARM: enable interrupts when arm_notify_die() is handling user mode errors
From: Xie Yuanbin @ 2026-06-29 8:31 UTC (permalink / raw)
To: bigeasy, linux, rmk+kernel
Cc: arnd, clrkwllms, liaohua4, lilinjie8, linusw, linux-arm-kernel,
linux-kernel, linux-rt-devel, rostedt, xieyuanbin1
In-Reply-To: <20260629075726.McX9yWi1@linutronix.de>
On Mon, 29 Jun 2026 09:57:26 +0200, Sebastian Andrzej Siewior wrote:
> In oops_enter() not only interrupts are disabled but also the emergency
> mode of the console is enabled. That means all console output is written
> via the atomic_write interface to the console as it the output happens.
> At this point, your real-time guarantees are gone. There is no need to
> worry about anything here since everything is lost.
>
> Restricting it to user context is reasonable: Here you kill the task and
> need enabled interrupts in order to send the signal.
> For kernel threads it is not needed because the "printing" happens with
> disabled interrupts anyway and without any buffering. Should this event
> not end with panic() then it will kill the kernel thread and enable
> interrupts before doing so.
Thanks. So, can I take it that you agree with the first one?
On Thu, 25 Jun 2026 20:26:12 +0800, Xie Yuanbin wrote:
> ```c
> if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
> return;
>
> if (likely(user_mode(regs)))
> local_irq_enable();
>
> pr_alert("8<--- cut here ---\n");
> ```
> or
> ```c
> if (!inf->fn(addr, ifsr | FSR_LNX_PF, regs))
> return;
>
> if (likely(interrupts_enabled(regs)))
> local_irq_enable();
>
> pr_alert("8<--- cut here ---\n");
> ```
^ permalink raw reply
* RE: [External Mail] Re: [PATCH v3 2/7] net: wwan: t9xx: Add control plane transaction layer
From: Wu. JackBB (GSM) @ 2026-06-29 7:26 UTC (permalink / raw)
To: Andrew Lunn
Cc: Loic Poulain, Sergey Ryazanov, Johannes Berg, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Wen-Zhi Huang, Shi-Wei Yeh, Minano Tseng, Matthias Brugger,
AngeloGioacchino Del Regno, Simon Horman, Jonathan Corbet,
Shuah Khan, linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-mediatek@lists.infradead.org, linux-doc@vger.kernel.org
In-Reply-To: <2a90ae6b-2b6d-4340-b557-915252cc3488@lunn.ch>
Hi Andrew,
> > +static int __init mtk_common_drv_init(void)
> > +{
> > + return 0;
> > +}
> > +module_init(mtk_common_drv_init);
> > +
> > +static void __exit mtk_common_drv_exit(void)
> > +{
> > +}
> > +module_exit(mtk_common_drv_exit);
>
> Since these don't do anything, they should not be needed.
Will move module_init/module_exit to the patch that first adds
content to them in v4.
> > + SET_HW_BITS(hw_bits, chs, MHCCIF_RC2EP_EVT_DEVICE_RESET,
> > + DEV_EVT_H2D_DEVICE_RESET);
> > +
> > + return LE32_TO_U32(cpu_to_le32(hw_bits));
>
> Please don't add white space like this. I assume a previous patch
> added this code, so move this to that patch.
Will remove the extra blank line in v4.
> > - devm_kfree(dev, mdev);
> > + mtk_dev_free(mdev);
>
> Why are you removing devm_ calls?
mtk_dev_alloc/mtk_dev_free are paired wrappers so the caller
doesn't need to know the underlying allocation mechanism.
The devm_kfree is still called inside mtk_dev_free.
Thanks.
Jack Wu.
^ permalink raw reply
* Re: [PATCH v6 1/9] media: mc-entity: Store parsed V4L2 fwnode endpoint in media_pad
From: Laurent Pinchart @ 2026-06-29 8:45 UTC (permalink / raw)
To: Sakari Ailus
Cc: Frank Li, Hans Verkuil, Mauro Carvalho Chehab, Michael Riesch,
Martin Kepplinger-Novakovic, Rui Miguel Silva, Purism Kernel Team,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-media, linux-kernel,
imx, Guoniu Zhou, devicetree, linux-arm-kernel
In-Reply-To: <akGD3ZjW6GPHHI3D@kekkonen.localdomain>
On Sun, Jun 28, 2026 at 11:28:13PM +0300, Sakari Ailus wrote:
> On Wed, Jun 24, 2026 at 04:37:48PM -0400, Frank.Li@oss.nxp.com wrote:
> > From: Frank Li <Frank.Li@nxp.com>
> >
> > Each media pad is associated with a firmware node endpoint. Capture the
> > parsed V4L2 fwnode endpoint information in struct media_pad so it can be
> > reused by consumers.
> >
> > This avoids reparsing firmware node endpoint data every time the endpoint
> > configuration is needed, reduces duplicate code, and provides a common
> > place to store endpoint properties associated with a pad.
> >
> > Signed-off-by: Frank Li <Frank.Li@nxp.com>
> > ---
> > Assume 1 to 1 map between dt's endpoint to medie pad.
> > Change in v6
> > - new patch
> > ---
> > include/media/media-entity.h | 5 ++++-
> > 1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/media/media-entity.h b/include/media/media-entity.h
> > index d9b72cd87d524..4a3785cd9f370 100644
> > --- a/include/media/media-entity.h
> > +++ b/include/media/media-entity.h
> > @@ -20,6 +20,8 @@
> > #include <linux/minmax.h>
> > #include <linux/types.h>
> >
> > +#include <media/v4l2-fwnode.h>
>
> We have dependencies from V4L2 to MC but not the other way around as MC is
> (or was?) intended for wider use then just V4L2. I'm thus more than a bit
> hesitant adding any references to V4L2 in MC.
>
> I wonder what Hans and Laurent think.
I agree. Furthermore, this will significantly increase the size of the
media_pad structure, for all pads. That's not a good design.
> > +
> > /* Enums used internally at the media controller to represent graphs */
> >
> > /**
> > @@ -230,6 +232,7 @@ enum media_pad_signal_type {
> > * @flags: Pad flags, as defined in
> > * :ref:`include/uapi/linux/media.h <media_header>`
> > * (seek for ``MEDIA_PAD_FL_*``)
> > + * @vep: associated fwnode endpoint information
> > * @pipe: Pipeline this pad belongs to. Use media_entity_pipeline() to
> > * access this field.
> > */
> > @@ -240,7 +243,7 @@ struct media_pad {
> > u16 num_links;
> > enum media_pad_signal_type sig_type;
> > unsigned long flags;
> > -
> > + struct v4l2_fwnode_endpoint vep;
> > /*
> > * The fields below are private, and should only be accessed via
> > * appropriate functions.
> >
>
> --
> Regards,
>
> Sakari Ailus
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH v6 3/9] media: subdev: Add media_async_register_subdev() helper
From: Laurent Pinchart @ 2026-06-29 8:46 UTC (permalink / raw)
To: Frank.Li
Cc: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch, Frank Li,
Martin Kepplinger-Novakovic, Rui Miguel Silva, Purism Kernel Team,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-media, linux-kernel,
imx, Guoniu Zhou, devicetree, linux-arm-kernel
In-Reply-To: <20260624-imx8qxp_pcam-v6-3-4b3f45920d2f@nxp.com>
On Wed, Jun 24, 2026 at 04:37:50PM -0400, Frank.Li@oss.nxp.com wrote:
> From: Frank Li <Frank.Li@nxp.com>
>
> Add media_async_register_subdev(), a helper to register a V4L2 sub-device
> with the asynchronous sub-device framework.
For the reason stated by Sakari in patch 1/9 (dependency from MC to
V4L2), I don't think a "media_async_register_subdev()" function is a
good idea.
> The helper assumes a 1:1 mapping between firmware endpoints and media pads.
> During registration it parses the firmware graph, creates media pads for
> all endpoints, and registers common asynchronous notifiers for sink
> endpoints. These notifiers automatically create media links when the
> corresponding remote source devices become available.
>
> The set_pad_by_ep() callback allows drivers to determine the media pad
> associated with a firmware endpoint and identify whether the endpoint
> represents a sink pad.
>
> By centralizing firmware graph parsing, media pad creation, notifier
> registration, and link creation, this helper reduces duplicated code and
> simplifies error handling in V4L2 sub-device drivers.
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
> ---
> change in v6
> - new patch
> ---
> drivers/media/v4l2-core/v4l2-fwnode.c | 155 ++++++++++++++++++++++++++++++++++
> include/media/v4l2-async.h | 39 +++++++++
> 2 files changed, 194 insertions(+)
>
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 62a3a452f7884..169059654478f 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -26,6 +26,7 @@
>
> #include <media/v4l2-async.h>
> #include <media/v4l2-fwnode.h>
> +#include <media/v4l2-mc.h>
> #include <media/v4l2-subdev.h>
>
> #include "v4l2-subdev-priv.h"
> @@ -1302,6 +1303,160 @@ int __v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd, struct module *m
> }
> EXPORT_SYMBOL_GPL(__v4l2_async_register_subdev_sensor);
>
> +static int v4l2_common_notifier_bound(struct v4l2_async_notifier *notifier,
> + struct v4l2_subdev *sd,
> + struct v4l2_async_connection *asd)
> +{
> + struct media_pad *pad = NULL;
> + int ret;
> +
> + if (asd->match.type != V4L2_ASYNC_MATCH_TYPE_FWNODE)
> + return -EINVAL;
> +
> + if (!asd->match.fwnode)
> + return -EINVAL;
> +
> + struct fwnode_handle *remote __free(fwnode_handle) =
> + fwnode_graph_get_remote_endpoint(asd->match.fwnode);
> +
> + for (int i = 0; i < notifier->sd->entity.num_pads; i++) {
> + if (notifier->sd->entity.pads[i].vep.base.local_fwnode == remote) {
> + pad = ¬ifier->sd->entity.pads[i];
> + break;
> + }
> + }
> +
> + if (!pad) {
> + dev_err(notifier->sd->dev, "failed to find sink pad\n");
> + return -EINVAL;
> + }
> +
> + ret = v4l2_create_fwnode_links_to_pad(sd, pad, MEDIA_LNK_FL_ENABLED);
> + if (ret) {
> + dev_err(sd->dev, "failed to link source pad\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct v4l2_async_notifier_operations v4l2_common_notifier_ops = {
> + .bound = v4l2_common_notifier_bound,
> +};
> +
> +static int
> +v4l2_async_nf_parse_fwnode(struct device *dev, struct media_pad *pads,
> + struct v4l2_async_notifier *notifier)
> +{
> + struct v4l2_subdev *sd = notifier->sd;
> + struct v4l2_async_connection *asd;
> + struct media_pad *pad;
> + int ret;
> +
> + if (!sd->internal_ops->set_pad_by_ep)
> + return dev_err_probe(dev, -EINVAL,
> + "Missed valiate_endpoint() callback\n");
> + pad = pads;
> +
> + fwnode_graph_for_each_endpoint_scoped(dev_fwnode(dev), ep) {
> + u32 flags;
> +
> + ret = v4l2_fwnode_endpoint_parse(ep, &pad->vep);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to parse endpoint\n");
> +
> + ret = sd->internal_ops->set_pad_by_ep(sd, pad);
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "Can support endponit\n");
> +
> + flags = pad->flags;
> +
> + pad++;
> +
> + if (flags & MEDIA_PAD_FL_SOURCE)
> + continue; /* Bypass source port */
> +
> + notifier->ops = &v4l2_common_notifier_ops;
> +
> + asd = v4l2_async_nf_add_fwnode_remote(notifier, ep,
> + struct v4l2_async_connection);
> + if (IS_ERR(asd))
> + return dev_err_probe(dev, PTR_ERR(asd),
> + "failed to add notifier\n");
> + }
> +
> + return 0;
> +}
> +
> +void media_async_subdev_cleanup(struct v4l2_subdev *sd)
> +{
> + v4l2_async_unregister_subdev(sd);
> + v4l2_subdev_cleanup(sd);
> + media_entity_cleanup(&sd->entity);
> + v4l2_async_nf_unregister(sd->subdev_notifier);
> + v4l2_async_nf_cleanup(sd->subdev_notifier);
> + kfree(sd->entity.pads);
> +}
> +EXPORT_SYMBOL_GPL(media_async_subdev_cleanup);
> +
> +int __media_async_register_subdev(struct v4l2_subdev *sd, struct module *module)
> +{
> + struct device *dev = sd->dev;
> + u32 ep_count;
> + int ret;
> +
> + if (WARN_ON(!sd->dev))
> + return -ENODEV;
> +
> + struct v4l2_async_notifier *notifier __free(kfree) = kzalloc_obj(*notifier);
> + if (!notifier)
> + return -ENOMEM;
> +
> + v4l2_async_subdev_nf_init(notifier, sd);
> +
> + ep_count = fwnode_graph_get_endpoint_count(dev_fwnode(dev), 0);
> + if (!ep_count)
> + return dev_err_probe(dev, -EINVAL, "No connected endpoints\n");
> +
> + struct media_pad *pads __free(kfree) = kzalloc_objs(struct media_pad, ep_count);
> + if (!pads)
> + return -ENOMEM;
> +
> + ret = v4l2_async_nf_parse_fwnode(dev, pads, notifier);
> + if (ret < 0)
> + return ret;
> +
> + ret = media_entity_pads_init(&sd->entity, ep_count, pads);
> + if (ret)
> + goto out_cleanup;
> +
> + ret = v4l2_async_nf_register(notifier);
> + if (ret < 0)
> + goto out_cleanup;
> +
> + ret = v4l2_subdev_init_finalize(sd);
> + if (ret)
> + goto out_unregister;
> +
> + ret = __v4l2_async_register_subdev(sd, module);
> + if (ret < 0)
> + goto out_unregister;
> +
> + sd->subdev_notifier = no_free_ptr(notifier);
> + retain_and_null_ptr(pads);
> +
> + return 0;
> +
> +out_unregister:
> + v4l2_async_nf_unregister(notifier);
> +
> +out_cleanup:
> + v4l2_async_nf_cleanup(notifier);
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(__media_async_register_subdev);
> +
> MODULE_DESCRIPTION("V4L2 fwnode binding parsing library");
> MODULE_LICENSE("GPL");
> MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 54a2d9620ed5b..ca41820f776c5 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -345,4 +345,43 @@ __v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd, struct module *modul
> * @sd: pointer to &struct v4l2_subdev
> */
> void v4l2_async_unregister_subdev(struct v4l2_subdev *sd);
> +
> +enum v4l2_subdev_1to1_pads {
> + V4L2_SUBDEV_1TO1_PADS_SINK,
> + V4L2_SUBDEV_1TO1_PADS_SOURCE,
> + V4L2_SUBDEV_1TO1_PADS_TOTAL,
> +};
> +
> +/**
> + * media_async_register_subdev - registers a sub-device to the asynchronous
> + * sub-device framework and parse set up common
> + * related devices
> + *
> + * @sd: pointer to struct &v4l2_subdev
> + *
> + * Register a V4L2 sub-device with the asynchronous sub-device framework.
> + * In addition to v4l2_async_register_subdev(), this function parses the
> + * firmware graph, creates media pads for the endpoints, and registers common
> + * notifiers to create media links between connected devices.
> + *
> + * This function also init media_pads.
> + *
> + * The sub-device is unregistered and cleanup by media_async_subdev_cleanup()
> + *
> + * While registered, the subdev module is marked as in-use.
> + *
> + * An error is returned if the module is no longer loaded on any attempts
> + * to register it.
> + */
> +#define media_async_register_subdev(sd_1to1) \
> + __media_async_register_subdev(sd_1to1, THIS_MODULE)
> +
> +int __media_async_register_subdev(struct v4l2_subdev *sd_1to1, struct module *module);
> +
> +/**
> + * media_async_subdev_cleanup - unregistered and cleanup subdev and media pads
> + * @sd_1to1: pointer to struct &v4l2_subdev_1to1
> + */
> +void media_async_subdev_cleanup(struct v4l2_subdev *sd_1to1);
> +
> #endif
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH v3 4/8] arm64: dts: qcom: shikra: Add Adreno SMMU node
From: Konrad Dybcio @ 2026-06-29 8:46 UTC (permalink / raw)
To: Akhil P Oommen, Rob Clark, Sean Paul, Konrad Dybcio,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Will Deacon, Robin Murphy, Joerg Roedel (AMD), Bjorn Andersson
Cc: Bibek Kumar Patro, linux-arm-msm, dri-devel, freedreno,
devicetree, linux-kernel, linux-arm-kernel, iommu, Imran Shaik,
Komal Bajaj
In-Reply-To: <20260628-shikra-gpu-v3-4-9b28a3b167e1@oss.qualcomm.com>
On 6/28/26 8:23 PM, Akhil P Oommen wrote:
> From: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
>
> Add the Adreno GPU IOMMU (adreno_smmu) node for the Shikra SoC.
>
> Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
> Signed-off-by: Imran Shaik <imran.shaik@oss.qualcomm.com>
> Signed-off-by: Komal Bajaj <komal.bajaj@oss.qualcomm.com>
Drop the sign-offs that don't apply (presumably applied as part
of shuffling around the handlers of the patch in the in-flight
tree OR missing c-d-b)
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Konrad
^ permalink raw reply
* Re: [PATCH rc v6 3/7] iommu/arm-smmu-v3: Do not enable EVTQ/PRIQ interrupts in kdump kernel
From: Pranjal Shrivastava @ 2026-06-29 8:48 UTC (permalink / raw)
To: Nicolin Chen
Cc: will, robin.murphy, jgg, joro, kees, baolu.lu, kevin.tian,
miko.lenczewski, smostafa, linux-arm-kernel, iommu, linux-kernel,
stable, jamien
In-Reply-To: <e643786d849d274c1d8dcfc03795f572aef812bd.1779265413.git.nicolinc@nvidia.com>
On Wed, May 20, 2026 at 10:03:20AM -0700, Nicolin Chen wrote:
> In kdump cases, the crashed kernel's CDs and page tables can be corrupted,
> which could trigger event spamming. Also, we cannot serve page requests.
>
> Skip the IRQ setup for EVTQ/PRIQ in arm_smmu_setup_irqs().
>
> Skip their IRQ handler registration in unique-IRQ and combined-IRQ cases.
>
> Fixes: b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions if SMMU is enabled in kdump kernel")
> Cc: stable@vger.kernel.org # v6.12+
> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
> ---
> drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 58 ++++++++++++++-------
> 1 file changed, 39 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index 2d7eb42449eaf..e00b28e36f9c4 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2464,7 +2464,11 @@ static irqreturn_t arm_smmu_combined_irq_thread(int irq, void *dev)
>
> static irqreturn_t arm_smmu_combined_irq_handler(int irq, void *dev)
> {
> - arm_smmu_gerror_handler(irq, dev);
> + irqreturn_t ret = arm_smmu_gerror_handler(irq, dev);
> +
> + /* In kdump, EVTQ/PRIQ are disabled and there is no thread to wake */
> + if (is_kdump_kernel())
> + return ret;
> return IRQ_WAKE_THREAD;
> }
>
> @@ -4963,6 +4967,21 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
> arm_smmu_setup_msis(smmu);
>
> /* Request interrupt lines */
> + irq = smmu->gerr_irq;
> + if (irq) {
> + ret = devm_request_irq(smmu->dev, irq, arm_smmu_gerror_handler,
> + 0, "arm-smmu-v3-gerror", smmu);
> + if (ret < 0)
> + dev_warn(smmu->dev, "failed to enable gerror irq\n");
> + } else {
> + dev_warn(smmu->dev,
> + "no gerr irq - errors will not be reported!\n");
> + }
> +
> + /* No EVTQ/PRIQ interrupts in kdump -- queues are disabled */
> + if (is_kdump_kernel())
> + return;
> +
> irq = smmu->evtq.q.irq;
> if (irq) {
> ret = devm_request_threaded_irq(smmu->dev, irq, NULL,
> @@ -4975,16 +4994,6 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
> dev_warn(smmu->dev, "no evtq irq - events will not be reported!\n");
> }
>
> - irq = smmu->gerr_irq;
> - if (irq) {
> - ret = devm_request_irq(smmu->dev, irq, arm_smmu_gerror_handler,
> - 0, "arm-smmu-v3-gerror", smmu);
> - if (ret < 0)
> - dev_warn(smmu->dev, "failed to enable gerror irq\n");
> - } else {
> - dev_warn(smmu->dev, "no gerr irq - errors will not be reported!\n");
> - }
> -
> if (smmu->features & ARM_SMMU_FEAT_PRI) {
> irq = smmu->priq.q.irq;
> if (irq) {
> @@ -5005,7 +5014,7 @@ static void arm_smmu_setup_unique_irqs(struct arm_smmu_device *smmu)
> static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
> {
> int ret, irq;
> - u32 irqen_flags = IRQ_CTRL_EVTQ_IRQEN | IRQ_CTRL_GERROR_IRQEN;
> + u32 irqen_flags = IRQ_CTRL_GERROR_IRQEN;
>
> /* Disable IRQs first */
> ret = arm_smmu_write_reg_sync(smmu, 0, ARM_SMMU_IRQ_CTRL,
> @@ -5020,19 +5029,30 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu)
> /*
> * Cavium ThunderX2 implementation doesn't support unique irq
> * lines. Use a single irq line for all the SMMUv3 interrupts.
> + *
> + * In kdump, EVTQ/PRIQ are disabled, so no threaded handling.
> */
> - ret = devm_request_threaded_irq(smmu->dev, irq,
> - arm_smmu_combined_irq_handler,
> - arm_smmu_combined_irq_thread,
> - IRQF_ONESHOT,
> - "arm-smmu-v3-combined-irq", smmu);
> + if (is_kdump_kernel())
> + ret = devm_request_irq(smmu->dev, irq,
> + arm_smmu_combined_irq_handler, 0,
> + "arm-smmu-v3-combined-irq",
> + smmu);
This `if` isn't needed, we can continue using devm_request_threaded_irq,
if you look at the doc for devm_request_threaded_irq [1] it says:
/**
* devm_request_threaded_irq - allocate an interrupt line for a managed device with error logging
* @dev: Device to request interrupt for
* @irq: Interrupt line to allocate
* @handler: Function to be called when the interrupt occurs
* @thread_fn: Function to be called in a threaded interrupt context. NULL
* for devices which handle everything in @handler
* @irqflags: Interrupt type flags
* @devname: An ascii name for the claiming device, dev_name(dev) if NULL
* @dev_id: A cookie passed back to the handler function
[...]
*/
So, we can pass handler() here while leaving the thread_fn == NULL:
ret = devm_request_threaded_irq(smmu->dev, irq,
arm_smmu_combined_irq_handler,
is_kdump_kernel() ? NULL : arm_smmu_combined_irq_thread,
IRQF_ONESHOT,
"arm-smmu-v3-combined-irq", smmu);
(In fact that's exactly what devm_request_irq does under the hood [2])
Additionally, the arm_smmu_combined_irq_handler() returns
IRQ_WAKE_THREAD unconditionally, which causes us to hit the warn_on[3] in
__handle_irq_event_percpu.
Hence, we'd need to refactor the arm_smmu_combined_irq_handler() to
return IRQ_HANDLED / _NONE if is_kdump_kernel().
> + else
> + ret = devm_request_threaded_irq(
> + smmu->dev, irq, arm_smmu_combined_irq_handler,
> + arm_smmu_combined_irq_thread, IRQF_ONESHOT,
> + "arm-smmu-v3-combined-irq", smmu);
> if (ret < 0)
> dev_warn(smmu->dev, "failed to enable combined irq\n");
> } else
> arm_smmu_setup_unique_irqs(smmu);
>
> - if (smmu->features & ARM_SMMU_FEAT_PRI)
> - irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
> + /* No EVTQ/PRIQ IRQ generation in kdump -- queues are disabled */
> + if (!is_kdump_kernel()) {
> + irqen_flags |= IRQ_CTRL_EVTQ_IRQEN;
> + if (smmu->features & ARM_SMMU_FEAT_PRI)
> + irqen_flags |= IRQ_CTRL_PRIQ_IRQEN;
> + }
>
> /* Enable interrupt generation on the SMMU */
> ret = arm_smmu_write_reg_sync(smmu, irqen_flags,
> --
> 2.43.0
>
Thanks,
Praan
[1] https://elixir.bootlin.com/linux/v7.1.1/source/kernel/irq/devres.c#L75
[2] https://elixir.bootlin.com/linux/v7.1.1/source/include/linux/interrupt.h#L218
[3] https://elixir.bootlin.com/linux/v7.1.1/source/kernel/irq/handle.c#L225
^ permalink raw reply
* Re: [5/7] soc: aspeed: Add eSPI flash channel support
From: Markus Elfring @ 2026-06-29 8:50 UTC (permalink / raw)
To: YH Chung, linux-aspeed, openbmc, linux-arm-kernel, devicetree,
Andrew Jeffery, Conor Dooley, Joel Stanley, Krzysztof Kozlowski,
Philipp Zabel, Rob Herring, Ryan Chen
Cc: LKML, Maciej Lawniczak
In-Reply-To: <KL1PR0601MB4276C2C831B257898AAB363190E82@KL1PR0601MB4276.apcprd06.prod.outlook.com>
…
>>> +++ b/drivers/soc/aspeed/espi/aspeed-espi.c
>> …
>>> +static void aspeed_espi_flash_rx_work(struct work_struct *work) {
…
> Thanks for the suggestion. I agree that guard(mutex) is helpful when a locked
> section has multiple exit paths. Since this worker currently has a single
> simple path, I would prefer to keep the explicit mutex_lock()/mutex_unlock()
> pair for readability. I can switch to guard(mutex) if you think it would be
> better in this case.
I hope that development interests can increase more also for the application of
scope-based resource management.
Regards,
Markus
^ 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