Devicetree
 help / color / mirror / Atom feed
* [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver
@ 2026-07-13 14:53 Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 01/10] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
                   ` (9 more replies)
  0 siblings, 10 replies; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

The imx-ocotp-ele.c driver currently uses the limited FSB (fuseblock)
to access the fuse registers. In order to gain full read/write access
to all fuses, we need to use the Edgelock Secure Enclave firmware.

This patchset does:

* Add bindings to reference ELE device in OCOTP driver (patch 1)
* Export ELE API functions (patch 3)
* Let the OCOTP driver use the ELE API (patch 7)
* Extend the devicetree of the Kontron boards for using the ELE API (patch 10)

The rest of the patches contain cleanups that were implemented along
the way.

This was tested using the 'crucible' tool and by directly reading from
the nvmem device on i.MX93.

This still lacks support for the i.MX94 and i.MX95 as I don't have the
hardware for testing on these platforms. As the documentations is
incomplete it is hard to get the keepout table right without testing
on the actual hardware. If someone else can provide the data and
testing, I can add it in a future version. If not this can be done
later.

---
Changes in v2:
- Adjust bindings to allow secure-enclave only for i.MX93 and improve commit message (suggested by Krzysztof)
- Export generic ELE API functions to be used by drivers (suggested by Frank and Peng)
- Move the fuse read/write functions to the NVMEM driver (suggested by Frank and Peng)
- Add patch to use __free(kfree) in imx_ocotp_reg_read() to fix memory leak (reported by Sashiko)
- Use device link to prevent SE device from being unbound while referenced (reported by Sashiko)
- Link to v1: https://patch.msgid.link/20260616-upstreaming-next-20260609-imx-ocotp-ele-v1-0-cb7f3698c3e6@kontron.de

To: Srinivas Kandagatla <srini@kernel.org>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: Frank Li <Frank.Li@nxp.com>
To: Sascha Hauer <s.hauer@pengutronix.de>
To: Pengutronix Kernel Team <kernel@pengutronix.de>
To: Fabio Estevam <festevam@gmail.com>
To: Shawn Guo <shawnguo@kernel.org>
Cc: devicetree@vger.kernel.org
Cc: imx@lists.linux.dev
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org

---
Frieder Schrempf (10):
      dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave
      firmware: imx: ele: Fix indentation in ele_base_msg.h
      firmware: imx: ele: Export API functions
      nvmem: imx-ocotp-ele: Add keepout table for i.MX93
      nvmem: imx-ocotp-ele: Remove device-specific reg_read()
      nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read()
      nvmem: imx-ocotp-ele: Support the ELE API
      nvmem: imx-ocotp-ele: Remove the FUSE_ELE type
      nvmem: imx-ocotp-ele: Rename FSB access map
      arm64: dts: imx93-kontron: Enable ELE firmware driver

 .../devicetree/bindings/nvmem/imx-ocotp.yaml       |  10 +
 .../boot/dts/freescale/imx93-kontron-osm-s.dtsi    |  26 +++
 drivers/firmware/imx/ele_base_msg.c                |  47 ++--
 drivers/firmware/imx/ele_base_msg.h                |  16 +-
 drivers/firmware/imx/ele_common.c                  |  35 ++-
 drivers/firmware/imx/ele_common.h                  |  15 --
 drivers/firmware/imx/se_ctrl.h                     |  14 +-
 drivers/nvmem/imx-ocotp-ele.c                      | 244 ++++++++++++++++++---
 include/linux/firmware/imx/se_api.h                |  78 +++++++
 9 files changed, 392 insertions(+), 93 deletions(-)
---
base-commit: 49e02880ec0a8c378e811bc9d85da188d7c6204c
change-id: 20260616-upstreaming-next-20260609-imx-ocotp-ele-a512ddf96b03

Best regards,
--  
Frieder Schrempf <frieder.schrempf@kontron.de>


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v2 01/10] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-14  8:00   ` Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 02/10] firmware: imx: ele: Fix indentation in ele_base_msg.h Frieder Schrempf
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

The driver currently uses the limited MMIO (FSB) interface to access the
OTPs. The intention is to support the firmware interface alongside the
MMIO interface so the driver can pick the interface that is available
(firmware might not be loaded) and fallback to MMIO.

Some SoCs like the i.MX9 family allow full access to the fuses only
through the secure enclave firmware API. Add a property to reference
the secure enclave node and let the driver use the API.

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
index a8076d0e2737..70901218871e 100644
--- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
+++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
@@ -20,6 +20,16 @@ description: |
 allOf:
   - $ref: nvmem.yaml#
   - $ref: nvmem-deprecated-cells.yaml#
+  - if:
+      properties:
+        compatible:
+          enum:
+            - fsl,imx93-ocotp
+    then:
+      properties:
+        secure-enclave:
+          $ref: /schemas/types.yaml#/definitions/phandle
+          description: A phandle to the secure enclave node
 
 properties:
   compatible:

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 02/10] firmware: imx: ele: Fix indentation in ele_base_msg.h
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 01/10] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-14 14:08   ` Frank Li
  2026-07-13 14:53 ` [PATCH v2 03/10] firmware: imx: ele: Export API functions Frieder Schrempf
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

The file uses mixed indentation characters. Use tabs everywhere.

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 drivers/firmware/imx/ele_base_msg.h | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
index 75e65e279193..1c5d6791b323 100644
--- a/drivers/firmware/imx/ele_base_msg.h
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -27,19 +27,19 @@
 #define ELE_GEN_KEY_BLOB_REQ		0xaf
 #define ELE_GET_FW_STATUS_REQ		0xc5
 #define ELE_XIP_DECRYPT_REQ		0xc6
-#define ELE_WRITE_FUSE                  0xd6
-#define ELE_DEV_ATTEST_REQ              0xdb
-#define ELE_WRITE_SHADOW_FUSE_REQ       0xf2
-#define ELE_READ_SHADOW_FUSE_REQ        0xf3
+#define ELE_WRITE_FUSE			0xd6
+#define ELE_DEV_ATTEST_REQ		0xdb
+#define ELE_WRITE_SHADOW_FUSE_REQ	0xf2
+#define ELE_READ_SHADOW_FUSE_REQ	0xf3
 
 #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 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

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 03/10] firmware: imx: ele: Export API functions
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 01/10] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 02/10] firmware: imx: ele: Fix indentation in ele_base_msg.h Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-14 14:08   ` Frank Li
  2026-07-13 14:53 ` [PATCH v2 04/10] nvmem: imx-ocotp-ele: Add keepout table for i.MX93 Frieder Schrempf
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

Export generic ELE API functions to send and receive messages. This
allows drivers to implement functions based on the ELE API.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 drivers/firmware/imx/ele_base_msg.c | 47 +++++++++++-----------
 drivers/firmware/imx/ele_common.c   | 35 ++++++++++++++++-
 drivers/firmware/imx/ele_common.h   | 15 -------
 drivers/firmware/imx/se_ctrl.h      | 14 +------
 include/linux/firmware/imx/se_api.h | 78 +++++++++++++++++++++++++++++++++++++
 5 files changed, 136 insertions(+), 53 deletions(-)

diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index ec718d322abc..69e70fd6a0d3 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -8,6 +8,7 @@
 #include <linux/cleanup.h>
 #include <linux/completion.h>
 #include <linux/dma-mapping.h>
+#include <linux/firmware/imx/se_api.h>
 #include <linux/genalloc.h>
 
 #include "ele_base_msg.h"
@@ -79,9 +80,9 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 		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);
+	ret = imx_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;
 
@@ -93,8 +94,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
 	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);
+	ret = imx_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;
 
@@ -132,10 +133,10 @@ int ele_ping(struct se_if_priv *priv)
 	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);
+	ret = imx_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.");
+		dev_err(priv->dev, "Error: imx_se_fill_cmd_msg_hdr failed.");
 		return ret;
 	}
 
@@ -144,8 +145,8 @@ int ele_ping(struct se_if_priv *priv)
 	if (ret < 0)
 		return ret;
 
-	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
-				      ELE_PING_RSP_SZ, true);
+	ret = imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
+					  ELE_PING_RSP_SZ, true);
 
 	return ret;
 }
@@ -169,9 +170,9 @@ int ele_service_swap(struct se_if_priv *priv,
 	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);
+	ret = imx_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;
 
@@ -189,8 +190,8 @@ int ele_service_swap(struct se_if_priv *priv,
 	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);
+	ret = imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_SERVICE_SWAP_REQ,
+					  ELE_SERVICE_SWAP_RSP_MSG_SZ, true);
 	if (ret)
 		return ret;
 
@@ -225,8 +226,8 @@ int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 	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);
+	ret = imx_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;
 
@@ -239,8 +240,8 @@ int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
 	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);
+	ret = imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_FW_AUTH_REQ,
+					  ELE_FW_AUTH_RSP_MSG_SZ, true);
 
 	return ret;
 }
@@ -265,8 +266,8 @@ int ele_debug_dump(struct se_if_priv *priv)
 	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);
+	ret = imx_se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
+				      ELE_DEBUG_DUMP_REQ_SZ, true);
 	if (ret)
 		return ret;
 
@@ -279,8 +280,8 @@ int ele_debug_dump(struct se_if_priv *priv)
 		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);
+		ret = imx_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;
diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
index 76bd3841acfc..81f3057aa7bf 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -3,9 +3,24 @@
  * Copyright 2025 NXP
  */
 
+#include <linux/export.h>
+
 #include "ele_base_msg.h"
 #include "ele_common.h"
 
+/* Fill a command message header with a given command ID and length in bytes. */
+int imx_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;
+}
+EXPORT_SYMBOL_GPL(imx_se_fill_cmd_msg_hdr);
+
 int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header)
 {
 	if (!header->size || header->size > MAX_WORD_SIZE)
@@ -155,6 +170,21 @@ int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
 	return err;
 }
 
+/*
+ * Send/receive blocking call for external drivers, operating on the SE
+ * interface private data (the misc device context is resolved internally).
+ */
+int imx_se_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+			void *rx_msg, int exp_rx_msg_sz)
+{
+	if (!priv)
+		return -EINVAL;
+
+	return ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, tx_msg_sz,
+				rx_msg, exp_rx_msg_sz);
+}
+EXPORT_SYMBOL_GPL(imx_se_msg_send_rcv);
+
 static bool check_hdr_exception_for_sz(struct se_if_priv *priv,
 				       struct se_msg_hdr *header)
 {
@@ -239,8 +269,8 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
 	complete(&se_clbk_hdl->done);
 }
 
-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)
+int imx_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;
@@ -285,6 +315,7 @@ int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(imx_se_val_rsp_hdr_n_status);
 
 int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
 {
diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
index bdc13d1b715d..792b0c6d9dae 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -28,21 +28,6 @@ int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
 
 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);
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index 7f9b0d199cfc..70a1ba369a06 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -7,6 +7,7 @@
 #define SE_MU_H
 
 #include <linux/bitfield.h>
+#include <linux/firmware/imx/se_api.h>
 #include <linux/miscdevice.h>
 #include <linux/semaphore.h>
 #include <linux/mailbox_client.h>
@@ -73,21 +74,8 @@ struct se_if_device_ctx {
 	struct list_head link;
 };
 
-/* 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;
diff --git a/include/linux/firmware/imx/se_api.h b/include/linux/firmware/imx/se_api.h
index b1c4c9115d7b..90104ecaaede 100644
--- a/include/linux/firmware/imx/se_api.h
+++ b/include/linux/firmware/imx/se_api.h
@@ -11,4 +11,82 @@
 #define SOC_ID_OF_IMX8ULP		0x084d
 #define SOC_ID_OF_IMX93			0x9300
 
+/**
+ * struct se_msg_hdr - Header of the messages exchanged with the secure enclave.
+ * @ver: API version the message conforms to (base or firmware API version).
+ * @size: Message size in 32-bit words, including the header.
+ * @command: Command identifier.
+ * @tag: Message tag identifying it as a command or a response.
+ */
+struct se_msg_hdr {
+	u8 ver;
+	u8 size;
+	u8 command;
+	u8 tag;
+}  __packed;
+
+/**
+ * struct se_api_msg - A message exchanged with the secure enclave.
+ * @header: Message header describing the command and its length.
+ * @data: Command or response payload, sized per @header.size.
+ */
+struct se_api_msg {
+	struct se_msg_hdr header;
+	u32 data[];
+};
+
+/* Opaque handle to a secure-enclave interface instance. */
+struct se_if_priv;
+
+/**
+ * imx_se_fill_cmd_msg_hdr() - Populate the header of a command message.
+ * @priv: Secure-enclave interface instance the command targets.
+ * @hdr: Message header to be filled in.
+ * @cmd: Command identifier to place in the header.
+ * @len: Total message length in bytes, including the header.
+ * @is_base_api: %true to tag the message with the base API version, %false to
+ *               use the firmware API version.
+ *
+ * Fill in the tag, version, command and size fields of @hdr so that the message
+ * can be sent to the secure enclave.
+ *
+ * Return: 0 on success.
+ */
+int imx_se_fill_cmd_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *hdr,
+			    u8 cmd, u32 len, bool is_base_api);
+
+/**
+ * imx_se_msg_send_rcv() - Send a command to the secure enclave and wait for the
+ *                         response.
+ * @priv: Secure-enclave interface instance to communicate with.
+ * @tx_msg: Buffer holding the command message to send.
+ * @tx_msg_sz: Size of the command message in bytes.
+ * @rx_msg: Buffer receiving the response message.
+ * @exp_rx_msg_sz: Expected size of the response message in bytes.
+ *
+ * Blocking send/receive helper for external drivers. The transaction is
+ * serialized internally and the misc device context is resolved from @priv.
+ *
+ * Return: number of bytes received on success, or a negative error code.
+ */
+int imx_se_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
+			void *rx_msg, int exp_rx_msg_sz);
+
+/**
+ * imx_se_val_rsp_hdr_n_status() - Validate a response header and status code.
+ * @priv: Secure-enclave interface instance the response came from.
+ * @msg: Response message to validate.
+ * @msg_id: Command identifier the response is expected to match.
+ * @sz: Expected response size in bytes.
+ * @is_base_api: %true if the command used the base API version, %false if it
+ *               used the firmware API version.
+ *
+ * Check that the response tag, command identifier, size and API version match
+ * the expectations, and that the enclave reported a successful status.
+ *
+ * Return: 0 if the response is valid and successful, or a negative error code.
+ */
+int imx_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);
+
 #endif /* __SE_API_H__ */

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 04/10] nvmem: imx-ocotp-ele: Add keepout table for i.MX93
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
                   ` (2 preceding siblings ...)
  2026-07-13 14:53 ` [PATCH v2 03/10] firmware: imx: ele: Export API functions Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 05/10] nvmem: imx-ocotp-ele: Remove device-specific reg_read() Frieder Schrempf
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

Add an overall keepout table to describe which fuse registers are
invalid and not accessible. No functional changes intended.

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 drivers/nvmem/imx-ocotp-ele.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index a0d2985c6d03..dadec19ca252 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -34,6 +34,8 @@ struct ocotp_devtype_data {
 	u32 num_entry;
 	u32 flag;
 	nvmem_reg_read_t reg_read;
+	const struct nvmem_keepout *keepout;
+	unsigned int nkeepout;
 	struct ocotp_map_entry entry[];
 };
 
@@ -163,6 +165,12 @@ static int imx_ele_ocotp_probe(struct platform_device *pdev)
 	priv->config.read_only = true;
 	priv->config.add_legacy_fixed_of_cells = true;
 	priv->config.fixup_dt_cell_info = imx_ocotp_fixup_dt_cell_info;
+
+	if (priv->data->nkeepout) {
+		priv->config.keepout = priv->data->keepout;
+		priv->config.nkeepout = priv->data->nkeepout;
+	}
+
 	mutex_init(&priv->lock);
 
 	nvmem = devm_nvmem_register(dev, &priv->config);
@@ -172,6 +180,14 @@ static int imx_ele_ocotp_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct nvmem_keepout imx93_ocotp_keepout[] = {
+	{.start = 208, .end = 252},
+	{.start = 256, .end = 512},
+	{.start = 576, .end = 728},
+	{.start = 732, .end = 752},
+	{.start = 756, .end = 1248},
+};
+
 static const struct ocotp_devtype_data imx93_ocotp_data = {
 	.reg_off = 0x8000,
 	.reg_read = imx_ocotp_reg_read,
@@ -185,6 +201,8 @@ static const struct ocotp_devtype_data imx93_ocotp_data = {
 		{ 188, 1, FUSE_ELE },
 		{ 312, 200, FUSE_FSB }
 	},
+	.keepout = imx93_ocotp_keepout,
+	.nkeepout = ARRAY_SIZE(imx93_ocotp_keepout),
 };
 
 static const struct ocotp_devtype_data imx94_ocotp_data = {

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 05/10] nvmem: imx-ocotp-ele: Remove device-specific reg_read()
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
                   ` (3 preceding siblings ...)
  2026-07-13 14:53 ` [PATCH v2 04/10] nvmem: imx-ocotp-ele: Add keepout table for i.MX93 Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 06/10] nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read() Frieder Schrempf
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

We only have a single implementation of the read hook. There is no
need to store it in the device data.

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 drivers/nvmem/imx-ocotp-ele.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index dadec19ca252..9d3f94e35508 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -33,7 +33,6 @@ struct ocotp_devtype_data {
 	u32 size;
 	u32 num_entry;
 	u32 flag;
-	nvmem_reg_read_t reg_read;
 	const struct nvmem_keepout *keepout;
 	unsigned int nkeepout;
 	struct ocotp_map_entry entry[];
@@ -158,7 +157,7 @@ static int imx_ele_ocotp_probe(struct platform_device *pdev)
 	priv->config.id = NVMEM_DEVID_AUTO;
 	priv->config.owner = THIS_MODULE;
 	priv->config.size = priv->data->size;
-	priv->config.reg_read = priv->data->reg_read;
+	priv->config.reg_read = imx_ocotp_reg_read;
 	priv->config.word_size = 1;
 	priv->config.stride = 1;
 	priv->config.priv = priv;
@@ -190,7 +189,6 @@ static const struct nvmem_keepout imx93_ocotp_keepout[] = {
 
 static const struct ocotp_devtype_data imx93_ocotp_data = {
 	.reg_off = 0x8000,
-	.reg_read = imx_ocotp_reg_read,
 	.size = 2048,
 	.num_entry = 6,
 	.entry = {
@@ -207,7 +205,6 @@ static const struct ocotp_devtype_data imx93_ocotp_data = {
 
 static const struct ocotp_devtype_data imx94_ocotp_data = {
 	.reg_off = 0x8000,
-	.reg_read = imx_ocotp_reg_read,
 	.size = 3296, /* 103 Banks */
 	.num_entry = 10,
 	.entry = {
@@ -226,7 +223,6 @@ static const struct ocotp_devtype_data imx94_ocotp_data = {
 
 static const struct ocotp_devtype_data imx95_ocotp_data = {
 	.reg_off = 0x8000,
-	.reg_read = imx_ocotp_reg_read,
 	.size = 2048,
 	.num_entry = 12,
 	.entry = {

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 06/10] nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read()
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
                   ` (4 preceding siblings ...)
  2026-07-13 14:53 ` [PATCH v2 05/10] nvmem: imx-ocotp-ele: Remove device-specific reg_read() Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 07/10] nvmem: imx-ocotp-ele: Support the ELE API Frieder Schrempf
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

This is useful to make sure the buffer is always freed when
its scope ends and makes the code slightly easier to read.

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 drivers/nvmem/imx-ocotp-ele.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index 9d3f94e35508..47ee6bd176a3 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -5,6 +5,7 @@
  * Copyright 2023 NXP
  */
 
+#include <linux/cleanup.h>
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -68,10 +69,10 @@ static int imx_ocotp_reg_read(void *context, unsigned int offset, void *val, siz
 {
 	struct imx_ocotp_priv *priv = context;
 	void __iomem *reg = priv->base + priv->data->reg_off;
+	void *p __free(kfree) = NULL;
 	u32 count, index, num_bytes;
 	enum fuse_type type;
 	u32 *buf;
-	void *p;
 	int i;
 	u8 skipbytes;
 
@@ -108,8 +109,6 @@ static int imx_ocotp_reg_read(void *context, unsigned int offset, void *val, siz
 
 	mutex_unlock(&priv->lock);
 
-	kfree(p);
-
 	return 0;
 };
 

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 07/10] nvmem: imx-ocotp-ele: Support the ELE API
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
                   ` (5 preceding siblings ...)
  2026-07-13 14:53 ` [PATCH v2 06/10] nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read() Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 08/10] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type Frieder Schrempf
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

The fuses inside the Edgelock Secure Enclave are currently not
accessed via its API but through the FSB block which provides
limited access to some fuses.

The ELE API allows us to access all fuses with read/write
permissions. Therefore use it as primary method and only fall
back to the limited FSB if the ELE API is not available.

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 drivers/nvmem/imx-ocotp-ele.c | 178 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 177 insertions(+), 1 deletion(-)

diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index 47ee6bd176a3..6ac7d588c4bd 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -7,10 +7,12 @@
 
 #include <linux/cleanup.h>
 #include <linux/device.h>
+#include <linux/firmware/imx/se_api.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/nvmem-provider.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/if_ether.h>	/* ETH_ALEN */
@@ -45,8 +47,113 @@ struct imx_ocotp_priv {
 	struct nvmem_config config;
 	struct mutex lock;
 	const struct ocotp_devtype_data *data;
+	struct se_if_priv *se_data;
 };
 
+/* ELE commands and message sizes used for OCOTP fuse access. */
+#define ELE_READ_FUSE_REQ		0x97
+#define ELE_READ_FUSE_REQ_MSG_SZ	0x08
+#define ELE_READ_FUSE_RSP_MSG_SZ	0x0c
+
+#define ELE_WRITE_FUSE			0xd6
+#define ELE_WRITE_FUSE_REQ_MSG_SZ	0x0c
+#define ELE_WRITE_FUSE_RSP_MSG_SZ	0x0c
+
+/*
+ * imx_ocotp_se_read_fuse() - Request the secure enclave FW to read a fuse.
+ * @priv: handle to the secure-enclave interface.
+ * @fuse_id: fuse identifier to read.
+ * @value: location to store the read fuse value.
+ *
+ * Secure enclaves like the EdgeLock Enclave manage the fuses. This requests
+ * the FW to read the fuse and returns the value reported by the FW.
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+static int imx_ocotp_se_read_fuse(struct se_if_priv *priv, u16 fuse_id, u32 *value)
+{
+	struct se_api_msg *tx_msg __free(kfree) = NULL;
+	struct se_api_msg *rx_msg __free(kfree) = NULL;
+	int ret;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_READ_FUSE_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_READ_FUSE_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = imx_se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_READ_FUSE_REQ,
+				      ELE_READ_FUSE_REQ_MSG_SZ, true);
+	if (ret)
+		return ret;
+
+	tx_msg->data[0] = fuse_id;
+
+	ret = imx_se_msg_send_rcv(priv, tx_msg, ELE_READ_FUSE_REQ_MSG_SZ,
+				  rx_msg, ELE_READ_FUSE_RSP_MSG_SZ);
+	if (ret < 0)
+		return ret;
+
+	ret = imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_READ_FUSE_REQ,
+					  ELE_READ_FUSE_RSP_MSG_SZ, true);
+	if (ret)
+		return ret;
+
+	*value = rx_msg->data[1];
+
+	return 0;
+}
+
+/*
+ * imx_ocotp_se_write_fuse() - Request the secure enclave FW to write a fuse.
+ * @priv: handle to the secure-enclave interface.
+ * @fuse_id: fuse identifier to write to.
+ * @value: value to write to the fuse.
+ *
+ * Secure enclaves like the EdgeLock Enclave manage the fuses. This requests
+ * the FW to program the fuse with the given value.
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+static int imx_ocotp_se_write_fuse(struct se_if_priv *priv, u16 fuse_id, u32 value)
+{
+	struct se_api_msg *tx_msg __free(kfree) = NULL;
+	struct se_api_msg *rx_msg __free(kfree) = NULL;
+	int ret;
+
+	if (!priv)
+		return -EINVAL;
+
+	tx_msg = kzalloc(ELE_WRITE_FUSE_REQ_MSG_SZ, GFP_KERNEL);
+	if (!tx_msg)
+		return -ENOMEM;
+
+	rx_msg = kzalloc(ELE_WRITE_FUSE_RSP_MSG_SZ, GFP_KERNEL);
+	if (!rx_msg)
+		return -ENOMEM;
+
+	ret = imx_se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_WRITE_FUSE,
+				      ELE_WRITE_FUSE_REQ_MSG_SZ, true);
+	if (ret)
+		return ret;
+
+	tx_msg->data[0] = (32 << 16) | (fuse_id << 5);
+	tx_msg->data[1] = value;
+
+	ret = imx_se_msg_send_rcv(priv, tx_msg, ELE_WRITE_FUSE_REQ_MSG_SZ,
+				  rx_msg, ELE_WRITE_FUSE_RSP_MSG_SZ);
+	if (ret < 0)
+		return ret;
+
+	return imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_WRITE_FUSE,
+					   ELE_WRITE_FUSE_RSP_MSG_SZ, true);
+}
+
 static enum fuse_type imx_ocotp_fuse_type(void *context, u32 index)
 {
 	struct imx_ocotp_priv *priv = context;
@@ -73,6 +180,7 @@ static int imx_ocotp_reg_read(void *context, unsigned int offset, void *val, siz
 	u32 count, index, num_bytes;
 	enum fuse_type type;
 	u32 *buf;
+	int ret;
 	int i;
 	u8 skipbytes;
 
@@ -93,6 +201,19 @@ static int imx_ocotp_reg_read(void *context, unsigned int offset, void *val, siz
 	buf = p;
 
 	for (i = index; i < (index + count); i++) {
+		/*
+		 * All fuse registers can be read via ELE. If the SE device is
+		 * available, always prefer it.
+		 */
+		if (priv->se_data) {
+			ret = imx_ocotp_se_read_fuse(priv->se_data, i, buf++);
+			if (ret) {
+				mutex_unlock(&priv->lock);
+				return ret;
+			}
+			continue;
+		}
+
 		type = imx_ocotp_fuse_type(context, i);
 		if (type == FUSE_INVALID || type == FUSE_ELE) {
 			*buf++ = 0;
@@ -112,6 +233,32 @@ static int imx_ocotp_reg_read(void *context, unsigned int offset, void *val, siz
 	return 0;
 };
 
+static int imx_ocotp_reg_write(void *context, unsigned int offset, void *val, size_t bytes)
+{
+	struct imx_ocotp_priv *priv = context;
+	u32 word = offset >> 2;
+	u32 *buf = val;
+	int ret;
+
+	/* allow only writing one complete OTP word at a time */
+	if ((bytes != 4) || (offset % 4 != 0))
+		return -EINVAL;
+
+	/*
+	 * The ELE API returns an error when writing an all-zero value. As
+	 * OTP fuse bits can not be switched from 1 to 0 anyway, skip these
+	 * values.
+	 */
+	if (!*buf)
+		return 0;
+
+	mutex_lock(&priv->lock);
+	ret = imx_ocotp_se_write_fuse(priv->se_data, word, *buf);
+	mutex_unlock(&priv->lock);
+
+	return ret;
+}
+
 static int imx_ocotp_cell_pp(void *context, const char *id, int index,
 			     unsigned int offset, void *data, size_t bytes)
 {
@@ -138,8 +285,10 @@ static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
 static int imx_ele_ocotp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct platform_device *se_pdev;
 	struct imx_ocotp_priv *priv;
 	struct nvmem_device *nvmem;
+	struct device_node *np;
 
 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 	if (!priv)
@@ -151,16 +300,40 @@ static int imx_ele_ocotp_probe(struct platform_device *pdev)
 	if (IS_ERR(priv->base))
 		return PTR_ERR(priv->base);
 
+	np = of_parse_phandle(pdev->dev.of_node, "secure-enclave", 0);
+	if (!np) {
+		dev_info(dev, "missing or invalid SE handle, using readonly FSB\n");
+	} else {
+		se_pdev = of_find_device_by_node(np);
+
+		of_node_put(np);
+		if (!se_pdev)
+			return dev_err_probe(dev, -ENODEV, "failed to find SE device\n");
+
+		priv->se_data = platform_get_drvdata(se_pdev);
+		if (!priv->se_data) {
+			put_device(&se_pdev->dev);
+			return dev_err_probe(dev, -EPROBE_DEFER, "SE device not ready\n");
+		}
+
+		if (!device_link_add(dev, &se_pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) {
+			put_device(&se_pdev->dev);
+			return dev_err_probe(dev, -EINVAL, "failed to link to SE device\n");
+		}
+
+		put_device(&se_pdev->dev);
+	}
+
 	priv->config.dev = dev;
 	priv->config.name = "ELE-OCOTP";
 	priv->config.id = NVMEM_DEVID_AUTO;
 	priv->config.owner = THIS_MODULE;
 	priv->config.size = priv->data->size;
 	priv->config.reg_read = imx_ocotp_reg_read;
+	priv->config.reg_write = imx_ocotp_reg_write;
 	priv->config.word_size = 1;
 	priv->config.stride = 1;
 	priv->config.priv = priv;
-	priv->config.read_only = true;
 	priv->config.add_legacy_fixed_of_cells = true;
 	priv->config.fixup_dt_cell_info = imx_ocotp_fixup_dt_cell_info;
 
@@ -169,6 +342,9 @@ static int imx_ele_ocotp_probe(struct platform_device *pdev)
 		priv->config.nkeepout = priv->data->nkeepout;
 	}
 
+	if (!priv->se_data)
+		priv->config.read_only = true;
+
 	mutex_init(&priv->lock);
 
 	nvmem = devm_nvmem_register(dev, &priv->config);

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 08/10] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
                   ` (6 preceding siblings ...)
  2026-07-13 14:53 ` [PATCH v2 07/10] nvmem: imx-ocotp-ele: Support the ELE API Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 09/10] nvmem: imx-ocotp-ele: Rename FSB access map Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver Frieder Schrempf
  9 siblings, 0 replies; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

There is no use in tracking the fuses that are only accessible via
ELE API and the current lists are incomplete. If the ELE API is
available it will be used as primary access method anyway, otherwise
the fuses not listed as accessible through the FSB can be considered
invalid.

No functional changes intended.

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 drivers/nvmem/imx-ocotp-ele.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index 6ac7d588c4bd..f07565c0a02d 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -19,8 +19,7 @@
 
 enum fuse_type {
 	FUSE_FSB = BIT(0),
-	FUSE_ELE = BIT(1),
-	FUSE_ECC = BIT(2),
+	FUSE_ECC = BIT(1),
 	FUSE_INVALID = -1
 };
 
@@ -215,7 +214,7 @@ static int imx_ocotp_reg_read(void *context, unsigned int offset, void *val, siz
 		}
 
 		type = imx_ocotp_fuse_type(context, i);
-		if (type == FUSE_INVALID || type == FUSE_ELE) {
+		if (type == FUSE_INVALID) {
 			*buf++ = 0;
 			continue;
 		}
@@ -365,13 +364,9 @@ static const struct nvmem_keepout imx93_ocotp_keepout[] = {
 static const struct ocotp_devtype_data imx93_ocotp_data = {
 	.reg_off = 0x8000,
 	.size = 2048,
-	.num_entry = 6,
+	.num_entry = 2,
 	.entry = {
 		{ 0, 52, FUSE_FSB },
-		{ 63, 1, FUSE_ELE},
-		{ 128, 16, FUSE_ELE },
-		{ 182, 1, FUSE_ELE },
-		{ 188, 1, FUSE_ELE },
 		{ 312, 200, FUSE_FSB }
 	},
 	.keepout = imx93_ocotp_keepout,
@@ -381,7 +376,7 @@ static const struct ocotp_devtype_data imx93_ocotp_data = {
 static const struct ocotp_devtype_data imx94_ocotp_data = {
 	.reg_off = 0x8000,
 	.size = 3296, /* 103 Banks */
-	.num_entry = 10,
+	.num_entry = 9,
 	.entry = {
 		{ 0, 1, FUSE_FSB | FUSE_ECC },
 		{ 7, 1, FUSE_FSB | FUSE_ECC },
@@ -389,7 +384,6 @@ static const struct ocotp_devtype_data imx94_ocotp_data = {
 		{ 12, 24, FUSE_FSB },
 		{ 36, 2, FUSE_FSB  | FUSE_ECC },
 		{ 38, 14, FUSE_FSB },
-		{ 59, 1, FUSE_ELE },
 		{ 525, 2, FUSE_FSB | FUSE_ECC },
 		{ 528, 7, FUSE_FSB },
 		{ 536, 280, FUSE_FSB },
@@ -399,7 +393,7 @@ static const struct ocotp_devtype_data imx94_ocotp_data = {
 static const struct ocotp_devtype_data imx95_ocotp_data = {
 	.reg_off = 0x8000,
 	.size = 2048,
-	.num_entry = 12,
+	.num_entry = 9,
 	.entry = {
 		{ 0, 1, FUSE_FSB | FUSE_ECC },
 		{ 7, 1, FUSE_FSB | FUSE_ECC },
@@ -407,9 +401,6 @@ static const struct ocotp_devtype_data imx95_ocotp_data = {
 		{ 12, 24, FUSE_FSB },
 		{ 36, 2, FUSE_FSB  | FUSE_ECC },
 		{ 38, 14, FUSE_FSB },
-		{ 63, 1, FUSE_ELE },
-		{ 128, 16, FUSE_ELE },
-		{ 188, 1, FUSE_ELE },
 		{ 317, 2, FUSE_FSB | FUSE_ECC },
 		{ 320, 7, FUSE_FSB },
 		{ 328, 184, FUSE_FSB }

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 09/10] nvmem: imx-ocotp-ele: Rename FSB access map
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
                   ` (7 preceding siblings ...)
  2026-07-13 14:53 ` [PATCH v2 08/10] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-13 14:53 ` [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver Frieder Schrempf
  9 siblings, 0 replies; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

The table is used to declare which fuse registers are accessible
through the FSB block. Name it accordingly to make this clearer for
the reader.

No functional changes intended.

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 drivers/nvmem/imx-ocotp-ele.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index f07565c0a02d..1a125f9c5b1d 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -33,11 +33,11 @@ struct ocotp_devtype_data {
 	u32 reg_off;
 	char *name;
 	u32 size;
-	u32 num_entry;
+	u32 num_fsb_map;
 	u32 flag;
 	const struct nvmem_keepout *keepout;
 	unsigned int nkeepout;
-	struct ocotp_map_entry entry[];
+	struct ocotp_map_entry fsb_map[];
 };
 
 struct imx_ocotp_priv {
@@ -160,12 +160,12 @@ static enum fuse_type imx_ocotp_fuse_type(void *context, u32 index)
 	u32 start, end;
 	int i;
 
-	for (i = 0; i < data->num_entry; i++) {
-		start = data->entry[i].start;
-		end = data->entry[i].start + data->entry[i].num;
+	for (i = 0; i < data->num_fsb_map; i++) {
+		start = data->fsb_map[i].start;
+		end = data->fsb_map[i].start + data->fsb_map[i].num;
 
 		if (index >= start && index < end)
-			return data->entry[i].type;
+			return data->fsb_map[i].type;
 	}
 
 	return FUSE_INVALID;
@@ -364,8 +364,8 @@ static const struct nvmem_keepout imx93_ocotp_keepout[] = {
 static const struct ocotp_devtype_data imx93_ocotp_data = {
 	.reg_off = 0x8000,
 	.size = 2048,
-	.num_entry = 2,
-	.entry = {
+	.num_fsb_map = 2,
+	.fsb_map = {
 		{ 0, 52, FUSE_FSB },
 		{ 312, 200, FUSE_FSB }
 	},
@@ -376,8 +376,8 @@ static const struct ocotp_devtype_data imx93_ocotp_data = {
 static const struct ocotp_devtype_data imx94_ocotp_data = {
 	.reg_off = 0x8000,
 	.size = 3296, /* 103 Banks */
-	.num_entry = 9,
-	.entry = {
+	.num_fsb_map = 9,
+	.fsb_map = {
 		{ 0, 1, FUSE_FSB | FUSE_ECC },
 		{ 7, 1, FUSE_FSB | FUSE_ECC },
 		{ 9, 3, FUSE_FSB | FUSE_ECC },
@@ -393,8 +393,8 @@ static const struct ocotp_devtype_data imx94_ocotp_data = {
 static const struct ocotp_devtype_data imx95_ocotp_data = {
 	.reg_off = 0x8000,
 	.size = 2048,
-	.num_entry = 9,
-	.entry = {
+	.num_fsb_map = 9,
+	.fsb_map = {
 		{ 0, 1, FUSE_FSB | FUSE_ECC },
 		{ 7, 1, FUSE_FSB | FUSE_ECC },
 		{ 9, 3, FUSE_FSB | FUSE_ECC },

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver
  2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
                   ` (8 preceding siblings ...)
  2026-07-13 14:53 ` [PATCH v2 09/10] nvmem: imx-ocotp-ele: Rename FSB access map Frieder Schrempf
@ 2026-07-13 14:53 ` Frieder Schrempf
  2026-07-14  6:59   ` Francesco Dolcini
  9 siblings, 1 reply; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-13 14:53 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

From: Frieder Schrempf <frieder.schrempf@kontron.de>

Add the ELE firmware API node and pass its handle to the OCOTP
driver. This allows us to gain read/write access to the OTP fuses.

Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
 .../boot/dts/freescale/imx93-kontron-osm-s.dtsi    | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi b/arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi
index c79b1df339db..c1da4b52c878 100644
--- a/arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi
@@ -24,6 +24,15 @@ chosen {
 		stdout-path = &lpuart1;
 	};
 
+	firmware {
+		hsm0: secure-enclave {
+			compatible = "fsl,imx93-se-ele-hsm";
+			mbox-names = "tx", "rx";
+			mboxes = <&s4muap 0 0>, <&s4muap 1 0>;
+			memory-region = <&ele_memory>;
+		};
+	};
+
 	reg_usdhc2_vcc: regulator-usdhc2-vcc {
 		compatible = "regulator-fixed";
 		pinctrl-names = "default";
@@ -57,6 +66,19 @@ regulator-state-disk {
 			regulator-off-in-suspend;
 		};
 	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		ele_memory: ele-memory {
+			compatible = "shared-dma-pool";
+			alloc-ranges = <0 0x80000000 0 0x40000000>;
+			size = <0 0x100000>;
+			no-map;
+		};
+	};
 };
 
 &flexcan1 { /* OSM-S CAN_A */
@@ -253,6 +275,10 @@ &lpuart7 { /* OSM-S UART_A */
 	pinctrl-0 = <&pinctrl_lpuart7>;
 };
 
+&ocotp {
+	secure-enclave = <&hsm0>;
+};
+
 &tpm3 { /* OSM-S PWM_0 */
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_tpm3>;

-- 
2.55.0


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver
  2026-07-13 14:53 ` [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver Frieder Schrempf
@ 2026-07-14  6:59   ` Francesco Dolcini
  2026-07-14  8:09     ` Frieder Schrempf
  0 siblings, 1 reply; 22+ messages in thread
From: Francesco Dolcini @ 2026-07-14  6:59 UTC (permalink / raw)
  To: Frieder Schrempf
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS),
	devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

Hello Frieder,

On Mon, Jul 13, 2026 at 04:53:46PM +0200, Frieder Schrempf wrote:
> From: Frieder Schrempf <frieder.schrempf@kontron.de>
> 
> Add the ELE firmware API node and pass its handle to the OCOTP
> driver. This allows us to gain read/write access to the OTP fuses.

This seems something we should have in the soc dtsi (imx93/imx91), it
does not seems board specific.

Francesco


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 01/10] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave
  2026-07-13 14:53 ` [PATCH v2 01/10] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
@ 2026-07-14  8:00   ` Frieder Schrempf
  0 siblings, 0 replies; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-14  8:00 UTC (permalink / raw)
  To: Frieder Schrempf, Srinivas Kandagatla, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shawn Guo, Pankaj Gupta,
	Peng Fan (OSS)
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel

On 13.07.26 16:53, Frieder Schrempf wrote:
> From: Frieder Schrempf <frieder.schrempf@kontron.de>
> 
> The driver currently uses the limited MMIO (FSB) interface to access the
> OTPs. The intention is to support the firmware interface alongside the
> MMIO interface so the driver can pick the interface that is available
> (firmware might not be loaded) and fallback to MMIO.
> 
> Some SoCs like the i.MX9 family allow full access to the fuses only
> through the secure enclave firmware API. Add a property to reference
> the secure enclave node and let the driver use the API.
> 
> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
> ---
>  Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
> index a8076d0e2737..70901218871e 100644
> --- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
> +++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
> @@ -20,6 +20,16 @@ description: |
>  allOf:
>    - $ref: nvmem.yaml#
>    - $ref: nvmem-deprecated-cells.yaml#
> +  - if:
> +      properties:
> +        compatible:
> +          enum:
> +            - fsl,imx93-ocotp
> +    then:
> +      properties:
> +        secure-enclave:
> +          $ref: /schemas/types.yaml#/definitions/phandle
> +          description: A phandle to the secure enclave node

The binding validation succeeded here, but the DT check fails. It seems
like this is not the way to do it and I need to add the property
unconditionally and then reverse the logic of the condition and disable
it in the if branch. Will fix it in the next version.

>  
>  properties:
>    compatible:
> 


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver
  2026-07-14  6:59   ` Francesco Dolcini
@ 2026-07-14  8:09     ` Frieder Schrempf
  2026-07-14  8:32       ` Francesco Dolcini
  0 siblings, 1 reply; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-14  8:09 UTC (permalink / raw)
  To: Francesco Dolcini, Frieder Schrempf
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS),
	devicetree, imx, linux-arm-kernel, linux-kernel

Hi Francesco,

On 14.07.26 08:59, Francesco Dolcini wrote:
> Hello Frieder,
> 
> On Mon, Jul 13, 2026 at 04:53:46PM +0200, Frieder Schrempf wrote:
>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>>
>> Add the ELE firmware API node and pass its handle to the OCOTP
>> driver. This allows us to gain read/write access to the OTP fuses.
> 
> This seems something we should have in the soc dtsi (imx93/imx91), it
> does not seems board specific.

My original intention was to move as much as possible into the SoC dtsi.
The problem is that the memory node is somewhat board specific due to
the DDR. And I can't move the firmware node into the SoC dtsi and assign
the memory node in the board dts as the checks for all boards not
specifying a memory node would fail then.

But I'm open to any suggestions how to improve this.

Thanks
Frieder

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver
  2026-07-14  8:09     ` Frieder Schrempf
@ 2026-07-14  8:32       ` Francesco Dolcini
  2026-07-14  8:43         ` Frieder Schrempf
  0 siblings, 1 reply; 22+ messages in thread
From: Francesco Dolcini @ 2026-07-14  8:32 UTC (permalink / raw)
  To: Frieder Schrempf
  Cc: Francesco Dolcini, Frieder Schrempf, Srinivas Kandagatla,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Shawn Guo,
	Pankaj Gupta, Peng Fan (OSS), devicetree, imx, linux-arm-kernel,
	linux-kernel

On Tue, Jul 14, 2026 at 10:09:11AM +0200, Frieder Schrempf wrote:
> Hi Francesco,
> 
> On 14.07.26 08:59, Francesco Dolcini wrote:
> > Hello Frieder,
> > 
> > On Mon, Jul 13, 2026 at 04:53:46PM +0200, Frieder Schrempf wrote:
> >> From: Frieder Schrempf <frieder.schrempf@kontron.de>
> >>
> >> Add the ELE firmware API node and pass its handle to the OCOTP
> >> driver. This allows us to gain read/write access to the OTP fuses.
> > 
> > This seems something we should have in the soc dtsi (imx93/imx91), it
> > does not seems board specific.
> 
> My original intention was to move as much as possible into the SoC dtsi.
> The problem is that the memory node is somewhat board specific due to
> the DDR. And I can't move the firmware node into the SoC dtsi and assign
> the memory node in the board dts as the checks for all boards not
> specifying a memory node would fail then.

The ELEFW is required to boot, is not an optional component for this
SoC, so I would try to find a way to have this duplicated in all the
board files.

What is the reason to have this memory address different on various
boards? Can we have a default in the soc dtsi, and allow the board to
override the address if needed?

Or can't you add the address in all the boards, and keep everything else
in the soc dtsi?

Francesco


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver
  2026-07-14  8:32       ` Francesco Dolcini
@ 2026-07-14  8:43         ` Frieder Schrempf
  2026-07-14  9:33           ` Francesco Dolcini
  0 siblings, 1 reply; 22+ messages in thread
From: Frieder Schrempf @ 2026-07-14  8:43 UTC (permalink / raw)
  To: Francesco Dolcini
  Cc: Frieder Schrempf, Srinivas Kandagatla, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shawn Guo, Pankaj Gupta,
	Peng Fan (OSS), devicetree, imx, linux-arm-kernel, linux-kernel

On 14.07.26 10:32, Francesco Dolcini wrote:
> On Tue, Jul 14, 2026 at 10:09:11AM +0200, Frieder Schrempf wrote:
>> Hi Francesco,
>>
>> On 14.07.26 08:59, Francesco Dolcini wrote:
>>> Hello Frieder,
>>>
>>> On Mon, Jul 13, 2026 at 04:53:46PM +0200, Frieder Schrempf wrote:
>>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>>>>
>>>> Add the ELE firmware API node and pass its handle to the OCOTP
>>>> driver. This allows us to gain read/write access to the OTP fuses.
>>>
>>> This seems something we should have in the soc dtsi (imx93/imx91), it
>>> does not seems board specific.
>>
>> My original intention was to move as much as possible into the SoC dtsi.
>> The problem is that the memory node is somewhat board specific due to
>> the DDR. And I can't move the firmware node into the SoC dtsi and assign
>> the memory node in the board dts as the checks for all boards not
>> specifying a memory node would fail then.
> 
> The ELEFW is required to boot, is not an optional component for this
> SoC, so I would try to find a way to have this duplicated in all the
> board files.

I don't think that this is correct. The ELE firmware is currently
mandatory in U-Boot, but this could theoretically change in the future.
As far as I know there is no hard requirement for the ELE firmware to be
available in order for the SoC to boot. If someone wants to build
software without optional blobs, they might choose to not have the ELE
firmware in place.

> 
> What is the reason to have this memory address different on various
> boards? Can we have a default in the soc dtsi, and allow the board to
> override the address if needed?

There is no real point in having different addresses on different
boards. But the node describes memory that is physically on the board
and not on the SoC. And I think that is why DT maintainers want to have
it in the board DT. It's the same with the memory nodes for the
remoteproc drivers to communicate with the Cortex M-Cores in the i.MX.
But maybe I'm wrong and if there is a possibility to move this to the
SoC DT I will definitely take it.

> 
> Or can't you add the address in all the boards, and keep everything else
> in the soc dtsi?
This could be a possible way, yes. In that case maybe we could even
create a generic dtsi to contain such defaults for all boards.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver
  2026-07-14  8:43         ` Frieder Schrempf
@ 2026-07-14  9:33           ` Francesco Dolcini
  2026-07-14 12:06             ` Alexander Stein
  0 siblings, 1 reply; 22+ messages in thread
From: Francesco Dolcini @ 2026-07-14  9:33 UTC (permalink / raw)
  To: Frieder Schrempf
  Cc: Francesco Dolcini, Frieder Schrempf, Srinivas Kandagatla,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Shawn Guo,
	Pankaj Gupta, Peng Fan (OSS), devicetree, imx, linux-arm-kernel,
	linux-kernel

On Tue, Jul 14, 2026 at 10:43:56AM +0200, Frieder Schrempf wrote:
> On 14.07.26 10:32, Francesco Dolcini wrote:
> > On Tue, Jul 14, 2026 at 10:09:11AM +0200, Frieder Schrempf wrote:
> >> Hi Francesco,
> >>
> >> On 14.07.26 08:59, Francesco Dolcini wrote:
> >>> Hello Frieder,
> >>>
> >>> On Mon, Jul 13, 2026 at 04:53:46PM +0200, Frieder Schrempf wrote:
> >>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
> >>>>
> >>>> Add the ELE firmware API node and pass its handle to the OCOTP
> >>>> driver. This allows us to gain read/write access to the OTP fuses.
> >>>
> >>> This seems something we should have in the soc dtsi (imx93/imx91), it
> >>> does not seems board specific.
> >>
> >> My original intention was to move as much as possible into the SoC dtsi.
> >> The problem is that the memory node is somewhat board specific due to
> >> the DDR. And I can't move the firmware node into the SoC dtsi and assign
> >> the memory node in the board dts as the checks for all boards not
> >> specifying a memory node would fail then.
> > 
> > What is the reason to have this memory address different on various
> > boards? Can we have a default in the soc dtsi, and allow the board to
> > override the address if needed?
> 
> There is no real point in having different addresses on different
> boards. But the node describes memory that is physically on the board
> and not on the SoC. And I think that is why DT maintainers want to have
> it in the board DT. It's the same with the memory nodes for the
> remoteproc drivers to communicate with the Cortex M-Cores in the i.MX.
> But maybe I'm wrong and if there is a possibility to move this to the
> SoC DT I will definitely take it.
> 
> > 
> > Or can't you add the address in all the boards, and keep everything else
> > in the soc dtsi?
> This could be a possible way, yes. In that case maybe we could even
> create a generic dtsi to contain such defaults for all boards.

I would go for this solution, we could have something like
`k3-am62-ti-ipc-firmware.dtsi`, include it from all the boards, have a
sane default memory address, and have an easy way to override the memory
address from the board dts, if needed.

Francesco



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver
  2026-07-14  9:33           ` Francesco Dolcini
@ 2026-07-14 12:06             ` Alexander Stein
  2026-07-14 12:33               ` Francesco Dolcini
  0 siblings, 1 reply; 22+ messages in thread
From: Alexander Stein @ 2026-07-14 12:06 UTC (permalink / raw)
  To: Frieder Schrempf, linux-arm-kernel
  Cc: Francesco Dolcini, Frieder Schrempf, Srinivas Kandagatla,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Shawn Guo,
	Pankaj Gupta, Peng Fan (OSS), devicetree, imx, linux-arm-kernel,
	linux-kernel, Francesco Dolcini

Am Dienstag, 14. Juli 2026, 11:33:54 CEST schrieb Francesco Dolcini:
> On Tue, Jul 14, 2026 at 10:43:56AM +0200, Frieder Schrempf wrote:
> > On 14.07.26 10:32, Francesco Dolcini wrote:
> > > On Tue, Jul 14, 2026 at 10:09:11AM +0200, Frieder Schrempf wrote:
> > >> Hi Francesco,
> > >>
> > >> On 14.07.26 08:59, Francesco Dolcini wrote:
> > >>> Hello Frieder,
> > >>>
> > >>> On Mon, Jul 13, 2026 at 04:53:46PM +0200, Frieder Schrempf wrote:
> > >>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
> > >>>>
> > >>>> Add the ELE firmware API node and pass its handle to the OCOTP
> > >>>> driver. This allows us to gain read/write access to the OTP fuses.
> > >>>
> > >>> This seems something we should have in the soc dtsi (imx93/imx91), it
> > >>> does not seems board specific.
> > >>
> > >> My original intention was to move as much as possible into the SoC dtsi.
> > >> The problem is that the memory node is somewhat board specific due to
> > >> the DDR. And I can't move the firmware node into the SoC dtsi and assign
> > >> the memory node in the board dts as the checks for all boards not
> > >> specifying a memory node would fail then.
> > > 
> > > What is the reason to have this memory address different on various
> > > boards? Can we have a default in the soc dtsi, and allow the board to
> > > override the address if needed?
> > 
> > There is no real point in having different addresses on different
> > boards. But the node describes memory that is physically on the board
> > and not on the SoC. And I think that is why DT maintainers want to have
> > it in the board DT. It's the same with the memory nodes for the
> > remoteproc drivers to communicate with the Cortex M-Cores in the i.MX.
> > But maybe I'm wrong and if there is a possibility to move this to the
> > SoC DT I will definitely take it.

We are talking about reserved memory, so this is highly board-specific.
So for different hardware variants with different amount of RAM you have to
go for the minimum anyway.

> > > 
> > > Or can't you add the address in all the boards, and keep everything else
> > > in the soc dtsi?
> > This could be a possible way, yes. In that case maybe we could even
> > create a generic dtsi to contain such defaults for all boards.
> 
> I would go for this solution, we could have something like
> `k3-am62-ti-ipc-firmware.dtsi`, include it from all the boards, have a
> sane default memory address, and have an easy way to override the memory
> address from the board dts, if needed.

So what is a sane default? At the end of the minimal possible RAM?
I'm not really fond of something you have to make sure matches to your
hardware, but won't raise an error if you forgot.

How about providing defaults for the SoC part and users have to provide their
memory on board-level? Similar to the VPU nodes on imx8qm/imx8qxp. There you
have to specify memory-region in your board.

Best regards,
Alexander
-- 
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
http://www.tq-group.com/



^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver
  2026-07-14 12:06             ` Alexander Stein
@ 2026-07-14 12:33               ` Francesco Dolcini
  2026-07-14 12:37                 ` Alexander Stein
  0 siblings, 1 reply; 22+ messages in thread
From: Francesco Dolcini @ 2026-07-14 12:33 UTC (permalink / raw)
  To: Alexander Stein
  Cc: Frieder Schrempf, linux-arm-kernel, Francesco Dolcini,
	Frieder Schrempf, Srinivas Kandagatla, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shawn Guo, Pankaj Gupta,
	Peng Fan (OSS), devicetree, imx, linux-kernel

On Tue, Jul 14, 2026 at 02:06:38PM +0200, Alexander Stein wrote:
> Am Dienstag, 14. Juli 2026, 11:33:54 CEST schrieb Francesco Dolcini:
> > On Tue, Jul 14, 2026 at 10:43:56AM +0200, Frieder Schrempf wrote:
> > > On 14.07.26 10:32, Francesco Dolcini wrote:
> > > > On Tue, Jul 14, 2026 at 10:09:11AM +0200, Frieder Schrempf wrote:
> > > >> Hi Francesco,
> > > >>
> > > >> On 14.07.26 08:59, Francesco Dolcini wrote:
> > > >>> Hello Frieder,
> > > >>>
> > > >>> On Mon, Jul 13, 2026 at 04:53:46PM +0200, Frieder Schrempf wrote:
> > > >>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
> > > >>>>
> > > >>>> Add the ELE firmware API node and pass its handle to the OCOTP
> > > >>>> driver. This allows us to gain read/write access to the OTP fuses.
> > > >>>
> > > >>> This seems something we should have in the soc dtsi (imx93/imx91), it
> > > >>> does not seems board specific.
> > > >>
> > > >> My original intention was to move as much as possible into the SoC dtsi.
> > > >> The problem is that the memory node is somewhat board specific due to
> > > >> the DDR. And I can't move the firmware node into the SoC dtsi and assign
> > > >> the memory node in the board dts as the checks for all boards not
> > > >> specifying a memory node would fail then.
> > > > 
> > > > What is the reason to have this memory address different on various
> > > > boards? Can we have a default in the soc dtsi, and allow the board to
> > > > override the address if needed?
> > > 
> > > There is no real point in having different addresses on different
> > > boards. But the node describes memory that is physically on the board
> > > and not on the SoC. And I think that is why DT maintainers want to have
> > > it in the board DT. It's the same with the memory nodes for the
> > > remoteproc drivers to communicate with the Cortex M-Cores in the i.MX.
> > > But maybe I'm wrong and if there is a possibility to move this to the
> > > SoC DT I will definitely take it.
> 
> We are talking about reserved memory, so this is highly board-specific.
> So for different hardware variants with different amount of RAM you have to
> go for the minimum anyway.
> 
> > > > 
> > > > Or can't you add the address in all the boards, and keep everything else
> > > > in the soc dtsi?
> > > This could be a possible way, yes. In that case maybe we could even
> > > create a generic dtsi to contain such defaults for all boards.
> > 
> > I would go for this solution, we could have something like
> > `k3-am62-ti-ipc-firmware.dtsi`, include it from all the boards, have a
> > sane default memory address, and have an easy way to override the memory
> > address from the board dts, if needed.
> 
> So what is a sane default? At the end of the minimal possible RAM?
> I'm not really fond of something you have to make sure matches to your
> hardware, but won't raise an error if you forgot.
> 
> How about providing defaults for the SoC part and users have to provide their
> memory on board-level? Similar to the VPU nodes on imx8qm/imx8qxp. There you
> have to specify memory-region in your board.

I am personally ok with both solution.

I think it is easy to have a sane default in this case. You cannot have
less than 256MiB in practice, and this is just about the offset, is not
that you are going to want more memory reserved if the board has more
memory available.

At the same time, having the memory range in the board dts is also ok to
me.

Francesco


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver
  2026-07-14 12:33               ` Francesco Dolcini
@ 2026-07-14 12:37                 ` Alexander Stein
  0 siblings, 0 replies; 22+ messages in thread
From: Alexander Stein @ 2026-07-14 12:37 UTC (permalink / raw)
  To: Francesco Dolcini
  Cc: Frieder Schrempf, linux-arm-kernel, Francesco Dolcini,
	Frieder Schrempf, Srinivas Kandagatla, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, Shawn Guo, Pankaj Gupta,
	Peng Fan (OSS), devicetree, imx, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4248 bytes --]

Am Dienstag, 14. Juli 2026, 14:33:50 CEST schrieb Francesco Dolcini:
> On Tue, Jul 14, 2026 at 02:06:38PM +0200, Alexander Stein wrote:
> > Am Dienstag, 14. Juli 2026, 11:33:54 CEST schrieb Francesco Dolcini:
> > > On Tue, Jul 14, 2026 at 10:43:56AM +0200, Frieder Schrempf wrote:
> > > > On 14.07.26 10:32, Francesco Dolcini wrote:
> > > > > On Tue, Jul 14, 2026 at 10:09:11AM +0200, Frieder Schrempf wrote:
> > > > >> Hi Francesco,
> > > > >>
> > > > >> On 14.07.26 08:59, Francesco Dolcini wrote:
> > > > >>> Hello Frieder,
> > > > >>>
> > > > >>> On Mon, Jul 13, 2026 at 04:53:46PM +0200, Frieder Schrempf wrote:
> > > > >>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
> > > > >>>>
> > > > >>>> Add the ELE firmware API node and pass its handle to the OCOTP
> > > > >>>> driver. This allows us to gain read/write access to the OTP fuses.
> > > > >>>
> > > > >>> This seems something we should have in the soc dtsi (imx93/imx91), it
> > > > >>> does not seems board specific.
> > > > >>
> > > > >> My original intention was to move as much as possible into the SoC dtsi.
> > > > >> The problem is that the memory node is somewhat board specific due to
> > > > >> the DDR. And I can't move the firmware node into the SoC dtsi and assign
> > > > >> the memory node in the board dts as the checks for all boards not
> > > > >> specifying a memory node would fail then.
> > > > > 
> > > > > What is the reason to have this memory address different on various
> > > > > boards? Can we have a default in the soc dtsi, and allow the board to
> > > > > override the address if needed?
> > > > 
> > > > There is no real point in having different addresses on different
> > > > boards. But the node describes memory that is physically on the board
> > > > and not on the SoC. And I think that is why DT maintainers want to have
> > > > it in the board DT. It's the same with the memory nodes for the
> > > > remoteproc drivers to communicate with the Cortex M-Cores in the i.MX.
> > > > But maybe I'm wrong and if there is a possibility to move this to the
> > > > SoC DT I will definitely take it.
> > 
> > We are talking about reserved memory, so this is highly board-specific.
> > So for different hardware variants with different amount of RAM you have to
> > go for the minimum anyway.
> > 
> > > > > 
> > > > > Or can't you add the address in all the boards, and keep everything else
> > > > > in the soc dtsi?
> > > > This could be a possible way, yes. In that case maybe we could even
> > > > create a generic dtsi to contain such defaults for all boards.
> > > 
> > > I would go for this solution, we could have something like
> > > `k3-am62-ti-ipc-firmware.dtsi`, include it from all the boards, have a
> > > sane default memory address, and have an easy way to override the memory
> > > address from the board dts, if needed.
> > 
> > So what is a sane default? At the end of the minimal possible RAM?
> > I'm not really fond of something you have to make sure matches to your
> > hardware, but won't raise an error if you forgot.
> > 
> > How about providing defaults for the SoC part and users have to provide their
> > memory on board-level? Similar to the VPU nodes on imx8qm/imx8qxp. There you
> > have to specify memory-region in your board.
> 
> I am personally ok with both solution.
> 
> I think it is easy to have a sane default in this case. You cannot have
> less than 256MiB in practice, and this is just about the offset, is not
> that you are going to want more memory reserved if the board has more
> memory available.
> 
> At the same time, having the memory range in the board dts is also ok to
> me.

I'm just saying, because we had lots of problem with assumed offsets/length
in code/DT for NXP boards. They usually come with big/huge amount of RAM.
This breaks for all hardware using a small amount of RAM.
So it's better to not have a default than silently breaking things because
the default doesn't match.

Best regards,
Alexander
-- 
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
http://www.tq-group.com/

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 02/10] firmware: imx: ele: Fix indentation in ele_base_msg.h
  2026-07-13 14:53 ` [PATCH v2 02/10] firmware: imx: ele: Fix indentation in ele_base_msg.h Frieder Schrempf
@ 2026-07-14 14:08   ` Frank Li
  0 siblings, 0 replies; 22+ messages in thread
From: Frank Li @ 2026-07-14 14:08 UTC (permalink / raw)
  To: Frieder Schrempf
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS),
	devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

On Mon, Jul 13, 2026 at 04:53:38PM +0200, Frieder Schrempf wrote:
> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>
> The file uses mixed indentation characters. Use tabs everywhere.
>
> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/firmware/imx/ele_base_msg.h | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
> index 75e65e279193..1c5d6791b323 100644
> --- a/drivers/firmware/imx/ele_base_msg.h
> +++ b/drivers/firmware/imx/ele_base_msg.h
> @@ -27,19 +27,19 @@
>  #define ELE_GEN_KEY_BLOB_REQ		0xaf
>  #define ELE_GET_FW_STATUS_REQ		0xc5
>  #define ELE_XIP_DECRYPT_REQ		0xc6
> -#define ELE_WRITE_FUSE                  0xd6
> -#define ELE_DEV_ATTEST_REQ              0xdb
> -#define ELE_WRITE_SHADOW_FUSE_REQ       0xf2
> -#define ELE_READ_SHADOW_FUSE_REQ        0xf3
> +#define ELE_WRITE_FUSE			0xd6
> +#define ELE_DEV_ATTEST_REQ		0xdb
> +#define ELE_WRITE_SHADOW_FUSE_REQ	0xf2
> +#define ELE_READ_SHADOW_FUSE_REQ	0xf3
>
>  #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 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
>
> --
> 2.55.0
>
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v2 03/10] firmware: imx: ele: Export API functions
  2026-07-13 14:53 ` [PATCH v2 03/10] firmware: imx: ele: Export API functions Frieder Schrempf
@ 2026-07-14 14:08   ` Frank Li
  0 siblings, 0 replies; 22+ messages in thread
From: Frank Li @ 2026-07-14 14:08 UTC (permalink / raw)
  To: Frieder Schrempf
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Shawn Guo, Pankaj Gupta, Peng Fan (OSS),
	devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf

On Mon, Jul 13, 2026 at 04:53:39PM +0200, Frieder Schrempf wrote:
> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>
> Export generic ELE API functions to send and receive messages. This
> allows drivers to implement functions based on the ELE API.
>
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/firmware/imx/ele_base_msg.c | 47 +++++++++++-----------
>  drivers/firmware/imx/ele_common.c   | 35 ++++++++++++++++-
>  drivers/firmware/imx/ele_common.h   | 15 -------
>  drivers/firmware/imx/se_ctrl.h      | 14 +------
>  include/linux/firmware/imx/se_api.h | 78 +++++++++++++++++++++++++++++++++++++
>  5 files changed, 136 insertions(+), 53 deletions(-)
>
> diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
> index ec718d322abc..69e70fd6a0d3 100644
> --- a/drivers/firmware/imx/ele_base_msg.c
> +++ b/drivers/firmware/imx/ele_base_msg.c
> @@ -8,6 +8,7 @@
>  #include <linux/cleanup.h>
>  #include <linux/completion.h>
>  #include <linux/dma-mapping.h>
> +#include <linux/firmware/imx/se_api.h>
>  #include <linux/genalloc.h>
>
>  #include "ele_base_msg.h"
> @@ -79,9 +80,9 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
>  		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);
> +	ret = imx_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;
>
> @@ -93,8 +94,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
>  	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);
> +	ret = imx_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;
>
> @@ -132,10 +133,10 @@ int ele_ping(struct se_if_priv *priv)
>  	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);
> +	ret = imx_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.");
> +		dev_err(priv->dev, "Error: imx_se_fill_cmd_msg_hdr failed.");
>  		return ret;
>  	}
>
> @@ -144,8 +145,8 @@ int ele_ping(struct se_if_priv *priv)
>  	if (ret < 0)
>  		return ret;
>
> -	ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
> -				      ELE_PING_RSP_SZ, true);
> +	ret = imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
> +					  ELE_PING_RSP_SZ, true);
>
>  	return ret;
>  }
> @@ -169,9 +170,9 @@ int ele_service_swap(struct se_if_priv *priv,
>  	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);
> +	ret = imx_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;
>
> @@ -189,8 +190,8 @@ int ele_service_swap(struct se_if_priv *priv,
>  	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);
> +	ret = imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_SERVICE_SWAP_REQ,
> +					  ELE_SERVICE_SWAP_RSP_MSG_SZ, true);
>  	if (ret)
>  		return ret;
>
> @@ -225,8 +226,8 @@ int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
>  	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);
> +	ret = imx_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;
>
> @@ -239,8 +240,8 @@ int ele_fw_authenticate(struct se_if_priv *priv, phys_addr_t contnr_addr,
>  	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);
> +	ret = imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_FW_AUTH_REQ,
> +					  ELE_FW_AUTH_RSP_MSG_SZ, true);
>
>  	return ret;
>  }
> @@ -265,8 +266,8 @@ int ele_debug_dump(struct se_if_priv *priv)
>  	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);
> +	ret = imx_se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
> +				      ELE_DEBUG_DUMP_REQ_SZ, true);
>  	if (ret)
>  		return ret;
>
> @@ -279,8 +280,8 @@ int ele_debug_dump(struct se_if_priv *priv)
>  		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);
> +		ret = imx_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;
> diff --git a/drivers/firmware/imx/ele_common.c b/drivers/firmware/imx/ele_common.c
> index 76bd3841acfc..81f3057aa7bf 100644
> --- a/drivers/firmware/imx/ele_common.c
> +++ b/drivers/firmware/imx/ele_common.c
> @@ -3,9 +3,24 @@
>   * Copyright 2025 NXP
>   */
>
> +#include <linux/export.h>
> +
>  #include "ele_base_msg.h"
>  #include "ele_common.h"
>
> +/* Fill a command message header with a given command ID and length in bytes. */
> +int imx_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;
> +}
> +EXPORT_SYMBOL_GPL(imx_se_fill_cmd_msg_hdr);
> +
>  int se_chk_tx_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *header)
>  {
>  	if (!header->size || header->size > MAX_WORD_SIZE)
> @@ -155,6 +170,21 @@ int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
>  	return err;
>  }
>
> +/*
> + * Send/receive blocking call for external drivers, operating on the SE
> + * interface private data (the misc device context is resolved internally).
> + */
> +int imx_se_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
> +			void *rx_msg, int exp_rx_msg_sz)
> +{
> +	if (!priv)
> +		return -EINVAL;
> +
> +	return ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, tx_msg_sz,
> +				rx_msg, exp_rx_msg_sz);
> +}
> +EXPORT_SYMBOL_GPL(imx_se_msg_send_rcv);
> +
>  static bool check_hdr_exception_for_sz(struct se_if_priv *priv,
>  				       struct se_msg_hdr *header)
>  {
> @@ -239,8 +269,8 @@ void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg)
>  	complete(&se_clbk_hdl->done);
>  }
>
> -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)
> +int imx_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;
> @@ -285,6 +315,7 @@ int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
>
>  	return 0;
>  }
> +EXPORT_SYMBOL_GPL(imx_se_val_rsp_hdr_n_status);
>
>  int se_save_imem_state(struct se_if_priv *priv, struct se_imem_buf *imem)
>  {
> diff --git a/drivers/firmware/imx/ele_common.h b/drivers/firmware/imx/ele_common.h
> index bdc13d1b715d..792b0c6d9dae 100644
> --- a/drivers/firmware/imx/ele_common.h
> +++ b/drivers/firmware/imx/ele_common.h
> @@ -28,21 +28,6 @@ int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
>
>  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);
> diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
> index 7f9b0d199cfc..70a1ba369a06 100644
> --- a/drivers/firmware/imx/se_ctrl.h
> +++ b/drivers/firmware/imx/se_ctrl.h
> @@ -7,6 +7,7 @@
>  #define SE_MU_H
>
>  #include <linux/bitfield.h>
> +#include <linux/firmware/imx/se_api.h>
>  #include <linux/miscdevice.h>
>  #include <linux/semaphore.h>
>  #include <linux/mailbox_client.h>
> @@ -73,21 +74,8 @@ struct se_if_device_ctx {
>  	struct list_head link;
>  };
>
> -/* 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;
> diff --git a/include/linux/firmware/imx/se_api.h b/include/linux/firmware/imx/se_api.h
> index b1c4c9115d7b..90104ecaaede 100644
> --- a/include/linux/firmware/imx/se_api.h
> +++ b/include/linux/firmware/imx/se_api.h
> @@ -11,4 +11,82 @@
>  #define SOC_ID_OF_IMX8ULP		0x084d
>  #define SOC_ID_OF_IMX93			0x9300
>
> +/**
> + * struct se_msg_hdr - Header of the messages exchanged with the secure enclave.
> + * @ver: API version the message conforms to (base or firmware API version).
> + * @size: Message size in 32-bit words, including the header.
> + * @command: Command identifier.
> + * @tag: Message tag identifying it as a command or a response.
> + */
> +struct se_msg_hdr {
> +	u8 ver;
> +	u8 size;
> +	u8 command;
> +	u8 tag;
> +}  __packed;
> +
> +/**
> + * struct se_api_msg - A message exchanged with the secure enclave.
> + * @header: Message header describing the command and its length.
> + * @data: Command or response payload, sized per @header.size.
> + */
> +struct se_api_msg {
> +	struct se_msg_hdr header;
> +	u32 data[];
> +};
> +
> +/* Opaque handle to a secure-enclave interface instance. */
> +struct se_if_priv;
> +
> +/**
> + * imx_se_fill_cmd_msg_hdr() - Populate the header of a command message.
> + * @priv: Secure-enclave interface instance the command targets.
> + * @hdr: Message header to be filled in.
> + * @cmd: Command identifier to place in the header.
> + * @len: Total message length in bytes, including the header.
> + * @is_base_api: %true to tag the message with the base API version, %false to
> + *               use the firmware API version.
> + *
> + * Fill in the tag, version, command and size fields of @hdr so that the message
> + * can be sent to the secure enclave.
> + *
> + * Return: 0 on success.
> + */
> +int imx_se_fill_cmd_msg_hdr(struct se_if_priv *priv, struct se_msg_hdr *hdr,
> +			    u8 cmd, u32 len, bool is_base_api);
> +
> +/**
> + * imx_se_msg_send_rcv() - Send a command to the secure enclave and wait for the
> + *                         response.
> + * @priv: Secure-enclave interface instance to communicate with.
> + * @tx_msg: Buffer holding the command message to send.
> + * @tx_msg_sz: Size of the command message in bytes.
> + * @rx_msg: Buffer receiving the response message.
> + * @exp_rx_msg_sz: Expected size of the response message in bytes.
> + *
> + * Blocking send/receive helper for external drivers. The transaction is
> + * serialized internally and the misc device context is resolved from @priv.
> + *
> + * Return: number of bytes received on success, or a negative error code.
> + */
> +int imx_se_msg_send_rcv(struct se_if_priv *priv, void *tx_msg, int tx_msg_sz,
> +			void *rx_msg, int exp_rx_msg_sz);
> +
> +/**
> + * imx_se_val_rsp_hdr_n_status() - Validate a response header and status code.
> + * @priv: Secure-enclave interface instance the response came from.
> + * @msg: Response message to validate.
> + * @msg_id: Command identifier the response is expected to match.
> + * @sz: Expected response size in bytes.
> + * @is_base_api: %true if the command used the base API version, %false if it
> + *               used the firmware API version.
> + *
> + * Check that the response tag, command identifier, size and API version match
> + * the expectations, and that the enclave reported a successful status.
> + *
> + * Return: 0 if the response is valid and successful, or a negative error code.
> + */
> +int imx_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);
> +
>  #endif /* __SE_API_H__ */
>
> --
> 2.55.0
>
>

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2026-07-14 14:09 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-13 14:53 [PATCH v2 00/10] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
2026-07-13 14:53 ` [PATCH v2 01/10] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
2026-07-14  8:00   ` Frieder Schrempf
2026-07-13 14:53 ` [PATCH v2 02/10] firmware: imx: ele: Fix indentation in ele_base_msg.h Frieder Schrempf
2026-07-14 14:08   ` Frank Li
2026-07-13 14:53 ` [PATCH v2 03/10] firmware: imx: ele: Export API functions Frieder Schrempf
2026-07-14 14:08   ` Frank Li
2026-07-13 14:53 ` [PATCH v2 04/10] nvmem: imx-ocotp-ele: Add keepout table for i.MX93 Frieder Schrempf
2026-07-13 14:53 ` [PATCH v2 05/10] nvmem: imx-ocotp-ele: Remove device-specific reg_read() Frieder Schrempf
2026-07-13 14:53 ` [PATCH v2 06/10] nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read() Frieder Schrempf
2026-07-13 14:53 ` [PATCH v2 07/10] nvmem: imx-ocotp-ele: Support the ELE API Frieder Schrempf
2026-07-13 14:53 ` [PATCH v2 08/10] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type Frieder Schrempf
2026-07-13 14:53 ` [PATCH v2 09/10] nvmem: imx-ocotp-ele: Rename FSB access map Frieder Schrempf
2026-07-13 14:53 ` [PATCH v2 10/10] arm64: dts: imx93-kontron: Enable ELE firmware driver Frieder Schrempf
2026-07-14  6:59   ` Francesco Dolcini
2026-07-14  8:09     ` Frieder Schrempf
2026-07-14  8:32       ` Francesco Dolcini
2026-07-14  8:43         ` Frieder Schrempf
2026-07-14  9:33           ` Francesco Dolcini
2026-07-14 12:06             ` Alexander Stein
2026-07-14 12:33               ` Francesco Dolcini
2026-07-14 12:37                 ` Alexander Stein

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox