* [PATCH v3 01/11] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 02/11] firmware: imx: ele: Fix indentation in ele_base_msg.h Frieder Schrempf
` (9 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
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 | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
index a8076d0e2737..38fe451f808f 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:
+ not:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - fsl,imx93-ocotp
+ then:
+ properties:
+ secure-enclave: false
properties:
compatible:
@@ -56,6 +66,10 @@ properties:
clocks:
maxItems: 1
+ secure-enclave:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: A phandle to the secure enclave node
+
required:
- "#address-cells"
- "#size-cells"
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 02/11] firmware: imx: ele: Fix indentation in ele_base_msg.h
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 01/11] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 03/11] firmware: imx: ele: Export API functions Frieder Schrempf
` (8 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
Frieder Schrempf
From: Frieder Schrempf <frieder.schrempf@kontron.de>
The file uses mixed indentation characters. Use tabs everywhere.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
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 475074580dd7..5c128bf56e88 100644
--- a/drivers/firmware/imx/ele_base_msg.h
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -28,19 +28,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] 16+ messages in thread* [PATCH v3 03/11] firmware: imx: ele: Export API functions
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 01/11] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 02/11] firmware: imx: ele: Fix indentation in ele_base_msg.h Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 18:34 ` Frank Li
2026-07-23 7:27 ` [PATCH v3 04/11] nvmem: imx-ocotp-ele: Add keepout table for i.MX93 Frieder Schrempf
` (7 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
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 | 42 ++++++++++----------
drivers/firmware/imx/ele_common.c | 35 ++++++++++++++++-
drivers/firmware/imx/ele_common.h | 14 -------
drivers/firmware/imx/se_ctrl.c | 6 +--
drivers/firmware/imx/se_ctrl.h | 14 +------
include/linux/firmware/imx/se_api.h | 78 +++++++++++++++++++++++++++++++++++++
6 files changed, 137 insertions(+), 52 deletions(-)
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index 28b835f2880f..a4ab45efdd63 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"
@@ -106,8 +107,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
}
}
- se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
- ELE_GET_INFO_REQ, ELE_GET_INFO_REQ_MSG_SZ, true);
+ 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);
tx_msg->data[0] = upper_32_bits(get_info_addr);
tx_msg->data[1] = lower_32_bits(get_info_addr);
@@ -120,8 +121,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
return ret;
}
- 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) {
ele_get_info_cleanup(priv, get_info_data, get_info_addr, get_info_len);
return ret;
@@ -156,16 +157,16 @@ int ele_ping(struct se_if_priv *priv)
if (!rx_msg)
return -ENOMEM;
- se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
- ELE_PING_REQ, ELE_PING_REQ_SZ, true);
+ imx_se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+ ELE_PING_REQ, ELE_PING_REQ_SZ, true);
ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_PING_REQ_SZ,
rx_msg, ELE_PING_RSP_SZ);
if (ret < 0)
return ret;
- ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
- ELE_PING_RSP_SZ, true);
+ ret = imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
+ ELE_PING_RSP_SZ, true);
return ret;
}
@@ -196,8 +197,9 @@ int ele_service_swap(struct se_if_priv *priv,
if (!rx_msg)
return -ENOMEM;
- se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
- ELE_SERVICE_SWAP_REQ, ELE_SERVICE_SWAP_REQ_MSG_SZ, true);
+ 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);
tx_msg->data[0] = flag;
tx_msg->data[1] = addr_size;
@@ -212,8 +214,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;
@@ -248,8 +250,8 @@ int ele_fw_authenticate(struct se_if_priv *priv, dma_addr_t contnr_addr,
if (!rx_msg)
return -ENOMEM;
- se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
- ELE_FW_AUTH_REQ, ELE_FW_AUTH_REQ_SZ, true);
+ imx_se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
+ ELE_FW_AUTH_REQ, ELE_FW_AUTH_REQ_SZ, true);
tx_msg->data[0] = lower_32_bits(contnr_addr);
tx_msg->data[1] = 0;
@@ -260,8 +262,8 @@ int ele_fw_authenticate(struct se_if_priv *priv, dma_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;
}
@@ -286,8 +288,8 @@ int ele_debug_dump(struct se_if_priv *priv)
if (!rx_msg)
return -ENOMEM;
- se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
- ELE_DEBUG_DUMP_REQ_SZ, true);
+ imx_se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
+ ELE_DEBUG_DUMP_REQ_SZ, true);
msg_ex_cnt = 0;
do {
@@ -298,8 +300,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 fbb6e584341a..f9c56fd42af0 100644
--- a/drivers/firmware/imx/ele_common.c
+++ b/drivers/firmware/imx/ele_common.c
@@ -3,11 +3,26 @@
* Copyright 2025 NXP
*/
+#include <linux/export.h>
+
#include "ele_base_msg.h"
#include "ele_common.h"
#include "ele_fw_api.h"
#include "se_ctrl.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_device_ctx *dev_ctx, struct se_msg_hdr *header)
{
struct se_if_priv *priv = dev_ctx->priv;
@@ -261,6 +276,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)
{
@@ -402,8 +432,8 @@ 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)
+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;
@@ -450,6 +480,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 b63a3fbf087a..8f0739960d4d 100644
--- a/drivers/firmware/imx/ele_common.h
+++ b/drivers/firmware/imx/ele_common.h
@@ -28,20 +28,6 @@ int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz);
void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
-
-int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
- u8 msg_id, u8 sz, bool is_base_api);
-
-/* Fill a command message header with a given command ID and length in bytes. */
-static inline void 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;
-}
-
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.c b/drivers/firmware/imx/se_ctrl.c
index 3c14964830a6..53f252d2f111 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -911,9 +911,9 @@ static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
"message received, start transmit to user");
rsp_status_err =
- se_val_rsp_hdr_n_status(priv, rx_msg, tx_msg->header.command,
- cmd_snd_rcv_rsp_info.rx_buf_sz,
- tx_msg->header.ver == priv->if_defs->base_api_ver);
+ imx_se_val_rsp_hdr_n_status(priv, rx_msg, tx_msg->header.command,
+ cmd_snd_rcv_rsp_info.rx_buf_sz,
+ tx_msg->header.ver == priv->if_defs->base_api_ver);
if (!rsp_status_err) {
err = se_dev_ctx_cpy_out_data(dev_ctx);
diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
index af7738ad76cd..76082e8b977c 100644
--- a/drivers/firmware/imx/se_ctrl.h
+++ b/drivers/firmware/imx/se_ctrl.h
@@ -7,6 +7,7 @@
#define SE_CTRL_H
#include <linux/bitfield.h>
+#include <linux/firmware/imx/se_api.h>
#include <linux/miscdevice.h>
#include <linux/mailbox_client.h>
#include <linux/semaphore.h>
@@ -95,22 +96,9 @@ struct se_if_device_ctx {
struct kref refcount;
};
-/* 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
#define SE_MU_HDR_WORD_SZ 1
-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] 16+ messages in thread* Re: [PATCH v3 03/11] firmware: imx: ele: Export API functions
2026-07-23 7:27 ` [PATCH v3 03/11] firmware: imx: ele: Export API functions Frieder Schrempf
@ 2026-07-23 18:34 ` Frank Li
0 siblings, 0 replies; 16+ messages in thread
From: Frank Li @ 2026-07-23 18:34 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, linux,
Frieder Schrempf
On Thu, Jul 23, 2026 at 09:27:25AM +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 | 42 ++++++++++----------
> drivers/firmware/imx/ele_common.c | 35 ++++++++++++++++-
> drivers/firmware/imx/ele_common.h | 14 -------
> drivers/firmware/imx/se_ctrl.c | 6 +--
> drivers/firmware/imx/se_ctrl.h | 14 +------
> include/linux/firmware/imx/se_api.h | 78 +++++++++++++++++++++++++++++++++++++
> 6 files changed, 137 insertions(+), 52 deletions(-)
>
> diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
> index 28b835f2880f..a4ab45efdd63 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"
> @@ -106,8 +107,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
> }
> }
>
> - se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
> - ELE_GET_INFO_REQ, ELE_GET_INFO_REQ_MSG_SZ, true);
> + 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);
>
> tx_msg->data[0] = upper_32_bits(get_info_addr);
> tx_msg->data[1] = lower_32_bits(get_info_addr);
> @@ -120,8 +121,8 @@ int ele_get_info(struct se_if_priv *priv, struct ele_dev_info *s_info)
> return ret;
> }
>
> - 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) {
> ele_get_info_cleanup(priv, get_info_data, get_info_addr, get_info_len);
> return ret;
> @@ -156,16 +157,16 @@ int ele_ping(struct se_if_priv *priv)
> if (!rx_msg)
> return -ENOMEM;
>
> - se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
> - ELE_PING_REQ, ELE_PING_REQ_SZ, true);
> + imx_se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
> + ELE_PING_REQ, ELE_PING_REQ_SZ, true);
>
> ret = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg, ELE_PING_REQ_SZ,
> rx_msg, ELE_PING_RSP_SZ);
> if (ret < 0)
> return ret;
>
> - ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
> - ELE_PING_RSP_SZ, true);
> + ret = imx_se_val_rsp_hdr_n_status(priv, rx_msg, ELE_PING_REQ,
> + ELE_PING_RSP_SZ, true);
>
> return ret;
> }
> @@ -196,8 +197,9 @@ int ele_service_swap(struct se_if_priv *priv,
> if (!rx_msg)
> return -ENOMEM;
>
> - se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
> - ELE_SERVICE_SWAP_REQ, ELE_SERVICE_SWAP_REQ_MSG_SZ, true);
> + 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);
>
> tx_msg->data[0] = flag;
> tx_msg->data[1] = addr_size;
> @@ -212,8 +214,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;
>
> @@ -248,8 +250,8 @@ int ele_fw_authenticate(struct se_if_priv *priv, dma_addr_t contnr_addr,
> if (!rx_msg)
> return -ENOMEM;
>
> - se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
> - ELE_FW_AUTH_REQ, ELE_FW_AUTH_REQ_SZ, true);
> + imx_se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&tx_msg->header,
> + ELE_FW_AUTH_REQ, ELE_FW_AUTH_REQ_SZ, true);
>
> tx_msg->data[0] = lower_32_bits(contnr_addr);
> tx_msg->data[1] = 0;
> @@ -260,8 +262,8 @@ int ele_fw_authenticate(struct se_if_priv *priv, dma_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;
> }
> @@ -286,8 +288,8 @@ int ele_debug_dump(struct se_if_priv *priv)
> if (!rx_msg)
> return -ENOMEM;
>
> - se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
> - ELE_DEBUG_DUMP_REQ_SZ, true);
> + imx_se_fill_cmd_msg_hdr(priv, &tx_msg->header, ELE_DEBUG_DUMP_REQ,
> + ELE_DEBUG_DUMP_REQ_SZ, true);
>
> msg_ex_cnt = 0;
> do {
> @@ -298,8 +300,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 fbb6e584341a..f9c56fd42af0 100644
> --- a/drivers/firmware/imx/ele_common.c
> +++ b/drivers/firmware/imx/ele_common.c
> @@ -3,11 +3,26 @@
> * Copyright 2025 NXP
> */
>
> +#include <linux/export.h>
> +
> #include "ele_base_msg.h"
> #include "ele_common.h"
> #include "ele_fw_api.h"
> #include "se_ctrl.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_device_ctx *dev_ctx, struct se_msg_hdr *header)
> {
> struct se_if_priv *priv = dev_ctx->priv;
> @@ -261,6 +276,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)
> {
> @@ -402,8 +432,8 @@ 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)
> +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;
> @@ -450,6 +480,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 b63a3fbf087a..8f0739960d4d 100644
> --- a/drivers/firmware/imx/ele_common.h
> +++ b/drivers/firmware/imx/ele_common.h
> @@ -28,20 +28,6 @@ int ele_msg_send_rcv(struct se_if_device_ctx *dev_ctx, void *tx_msg,
> int tx_msg_sz, void *rx_msg, int exp_rx_msg_sz);
>
> void se_if_rx_callback(struct mbox_client *mbox_cl, void *msg);
> -
> -int se_val_rsp_hdr_n_status(struct se_if_priv *priv, struct se_api_msg *msg,
> - u8 msg_id, u8 sz, bool is_base_api);
> -
> -/* Fill a command message header with a given command ID and length in bytes. */
> -static inline void 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;
> -}
> -
> 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.c b/drivers/firmware/imx/se_ctrl.c
> index 3c14964830a6..53f252d2f111 100644
> --- a/drivers/firmware/imx/se_ctrl.c
> +++ b/drivers/firmware/imx/se_ctrl.c
> @@ -911,9 +911,9 @@ static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx *dev_ctx,
> "message received, start transmit to user");
>
> rsp_status_err =
> - se_val_rsp_hdr_n_status(priv, rx_msg, tx_msg->header.command,
> - cmd_snd_rcv_rsp_info.rx_buf_sz,
> - tx_msg->header.ver == priv->if_defs->base_api_ver);
> + imx_se_val_rsp_hdr_n_status(priv, rx_msg, tx_msg->header.command,
> + cmd_snd_rcv_rsp_info.rx_buf_sz,
> + tx_msg->header.ver == priv->if_defs->base_api_ver);
>
> if (!rsp_status_err) {
> err = se_dev_ctx_cpy_out_data(dev_ctx);
> diff --git a/drivers/firmware/imx/se_ctrl.h b/drivers/firmware/imx/se_ctrl.h
> index af7738ad76cd..76082e8b977c 100644
> --- a/drivers/firmware/imx/se_ctrl.h
> +++ b/drivers/firmware/imx/se_ctrl.h
> @@ -7,6 +7,7 @@
> #define SE_CTRL_H
>
> #include <linux/bitfield.h>
> +#include <linux/firmware/imx/se_api.h>
> #include <linux/miscdevice.h>
> #include <linux/mailbox_client.h>
> #include <linux/semaphore.h>
> @@ -95,22 +96,9 @@ struct se_if_device_ctx {
> struct kref refcount;
> };
>
> -/* 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
> #define SE_MU_HDR_WORD_SZ 1
>
> -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] 16+ messages in thread
* [PATCH v3 04/11] nvmem: imx-ocotp-ele: Add keepout table for i.MX93
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (2 preceding siblings ...)
2026-07-23 7:27 ` [PATCH v3 03/11] firmware: imx: ele: Export API functions Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 05/11] nvmem: imx-ocotp-ele: Remove device-specific reg_read() Frieder Schrempf
` (6 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
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] 16+ messages in thread* [PATCH v3 05/11] nvmem: imx-ocotp-ele: Remove device-specific reg_read()
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (3 preceding siblings ...)
2026-07-23 7:27 ` [PATCH v3 04/11] nvmem: imx-ocotp-ele: Add keepout table for i.MX93 Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 18:38 ` Frank Li
2026-07-23 7:27 ` [PATCH v3 06/11] nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read() Frieder Schrempf
` (5 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
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] 16+ messages in thread* Re: [PATCH v3 05/11] nvmem: imx-ocotp-ele: Remove device-specific reg_read()
2026-07-23 7:27 ` [PATCH v3 05/11] nvmem: imx-ocotp-ele: Remove device-specific reg_read() Frieder Schrempf
@ 2026-07-23 18:38 ` Frank Li
0 siblings, 0 replies; 16+ messages in thread
From: Frank Li @ 2026-07-23 18:38 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, linux,
Frieder Schrempf
On Thu, Jul 23, 2026 at 09:27:27AM +0200, Frieder Schrempf wrote:
> 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.
Remove .reg_read() callback in the device data because all is the same
implementation.
Frank
>
> 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 [flat|nested] 16+ messages in thread
* [PATCH v3 06/11] nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read()
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (4 preceding siblings ...)
2026-07-23 7:27 ` [PATCH v3 05/11] nvmem: imx-ocotp-ele: Remove device-specific reg_read() Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 18:42 ` Frank Li
2026-07-23 7:27 ` [PATCH v3 07/11] nvmem: imx-ocotp-ele: Support the ELE API Frieder Schrempf
` (4 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
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] 16+ messages in thread* Re: [PATCH v3 06/11] nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read()
2026-07-23 7:27 ` [PATCH v3 06/11] nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read() Frieder Schrempf
@ 2026-07-23 18:42 ` Frank Li
0 siblings, 0 replies; 16+ messages in thread
From: Frank Li @ 2026-07-23 18:42 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, linux,
Frieder Schrempf
On Thu, Jul 23, 2026 at 09:27:28AM +0200, Frieder Schrempf wrote:
> 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;
according to cleanup.h, it should declare at where assign
void *p __free(free) = kzalloc(num_bytes, GFP_KERNEL);
Frank
> 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 [flat|nested] 16+ messages in thread
* [PATCH v3 07/11] nvmem: imx-ocotp-ele: Support the ELE API
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (5 preceding siblings ...)
2026-07-23 7:27 ` [PATCH v3 06/11] nvmem: imx-ocotp-ele: Use __free(kfree) in imx_ocotp_reg_read() Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 18:48 ` Frank Li
2026-07-23 7:27 ` [PATCH v3 08/11] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type Frieder Schrempf
` (3 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
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] 16+ messages in thread* Re: [PATCH v3 07/11] nvmem: imx-ocotp-ele: Support the ELE API
2026-07-23 7:27 ` [PATCH v3 07/11] nvmem: imx-ocotp-ele: Support the ELE API Frieder Schrempf
@ 2026-07-23 18:48 ` Frank Li
0 siblings, 0 replies; 16+ messages in thread
From: Frank Li @ 2026-07-23 18:48 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, linux,
Frieder Schrempf
On Thu, Jul 23, 2026 at 09:27:29AM +0200, Frieder Schrempf wrote:
> 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);
the same here
struct se_api_msg *tx_msg __free(kfree) = kzalloc(..);
> + 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);
you can change to guard(mutex) firstly
> + 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);
guard(mutex)(&priv->lock);
return imx_ocotp_se_write_fuse();
> +
> + 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);
struct device_node *np __free(device_node) = of_parse_phandle(...);
Frank
> + 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 [flat|nested] 16+ messages in thread
* [PATCH v3 08/11] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (6 preceding siblings ...)
2026-07-23 7:27 ` [PATCH v3 07/11] nvmem: imx-ocotp-ele: Support the ELE API Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 09/11] nvmem: imx-ocotp-ele: Rename FSB access map Frieder Schrempf
` (2 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
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] 16+ messages in thread* [PATCH v3 09/11] nvmem: imx-ocotp-ele: Rename FSB access map
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (7 preceding siblings ...)
2026-07-23 7:27 ` [PATCH v3 08/11] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 10/11] arm64: dts: Add common include for i.MX93 ELE firmware Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 11/11] arm64: dts: Enable EdgeLock Secure Enclave on all i.MX91/i.MX93 boards Frieder Schrempf
10 siblings, 0 replies; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
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] 16+ messages in thread* [PATCH v3 10/11] arm64: dts: Add common include for i.MX93 ELE firmware
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (8 preceding siblings ...)
2026-07-23 7:27 ` [PATCH v3 09/11] nvmem: imx-ocotp-ele: Rename FSB access map Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
2026-07-23 7:27 ` [PATCH v3 11/11] arm64: dts: Enable EdgeLock Secure Enclave on all i.MX91/i.MX93 boards Frieder Schrempf
10 siblings, 0 replies; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
Frieder Schrempf
From: Frieder Schrempf <frieder.schrempf@kontron.de>
To make it easier for boards to configure the EdgeLock Secure Enclave
on i.MX93, add a common include file that contains sane defaults. It
specifies the memory node, enables the ELE firmware node and adds a
reference to NVMEM OCOTP driver.
The 1MB memory area required for the firmware is placed in the first
256MB of the DDR. Boards that require a more specific alignment can
override this accordingly.
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
arch/arm64/boot/dts/freescale/imx93-firmware.dtsi | 28 +++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx93-firmware.dtsi b/arch/arm64/boot/dts/freescale/imx93-firmware.dtsi
new file mode 100644
index 000000000000..58614158ef90
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx93-firmware.dtsi
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2026 Kontron Electronics GmbH
+ */
+
+/{
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ ele_memory: ele-memory {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x80000000 0 0x10000000>;
+ size = <0 0x100000>;
+ no-map;
+ };
+ };
+};
+
+&hsm0 {
+ status = "okay";
+ memory-region = <&ele_memory>;
+};
+
+&ocotp {
+ secure-enclave = <&hsm0>;
+};
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v3 11/11] arm64: dts: Enable EdgeLock Secure Enclave on all i.MX91/i.MX93 boards
2026-07-23 7:27 [PATCH v3 00/11] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (9 preceding siblings ...)
2026-07-23 7:27 ` [PATCH v3 10/11] arm64: dts: Add common include for i.MX93 ELE firmware Frieder Schrempf
@ 2026-07-23 7:27 ` Frieder Schrempf
10 siblings, 0 replies; 16+ messages in thread
From: Frieder Schrempf @ 2026-07-23 7:27 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, linux,
Frieder Schrempf
From: Frieder Schrempf <frieder.schrempf@kontron.de>
Include the common dtsi to enable the firmware node for all boards
based on the i.MX91 or i.MX93 SoC.
For the TQ-Systems i.MX91 TQMa91xxCA / TQMa91xxLA SOM that already has
a node for the reserved memory, keep the current settings.
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts | 1 +
arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts | 1 +
arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts | 1 +
arch/arm64/boot/dts/freescale/imx91-9x9-qsb.dts | 1 +
arch/arm64/boot/dts/freescale/imx91-phycore-som.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx91-tqma9131.dtsi | 15 ++++++++-------
arch/arm64/boot/dts/freescale/imx91-var-dart.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx91-var-som.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx91_93_common.dtsi | 9 +++++++++
arch/arm64/boot/dts/freescale/imx93-11x11-evk-common.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts | 1 +
arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts | 1 +
arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts | 1 +
arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx93-var-dart.dtsi | 1 +
arch/arm64/boot/dts/freescale/imx93-var-som.dtsi | 1 +
18 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
index 5716febb5a50..7813a3cf215b 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-evk.dts
@@ -7,6 +7,7 @@
#include <dt-bindings/usb/pd.h>
#include "imx91.dtsi"
+#include "imx93-firmware.dtsi"
/ {
compatible = "fsl,imx91-11x11-evk", "fsl,imx91";
diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
index 62dc1dedfb0e..b5a042a58b57 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm-s.dts
@@ -7,6 +7,7 @@
#include <dt-bindings/usb/pd.h>
#include "imx91.dtsi"
+#include "imx93-firmware.dtsi"
/ {
compatible = "fsl,imx91-11x11-frdm-s", "fsl,imx91";
diff --git a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts
index c25561574d3f..20c7e4989367 100644
--- a/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-11x11-frdm.dts
@@ -7,6 +7,7 @@
#include <dt-bindings/usb/pd.h>
#include "imx91.dtsi"
+#include "imx93-firmware.dtsi"
/ {
compatible = "fsl,imx91-11x11-frdm", "fsl,imx91";
diff --git a/arch/arm64/boot/dts/freescale/imx91-9x9-qsb.dts b/arch/arm64/boot/dts/freescale/imx91-9x9-qsb.dts
index ea8cf14e0bc6..430c0402138b 100644
--- a/arch/arm64/boot/dts/freescale/imx91-9x9-qsb.dts
+++ b/arch/arm64/boot/dts/freescale/imx91-9x9-qsb.dts
@@ -7,6 +7,7 @@
#include <dt-bindings/usb/pd.h>
#include "imx91.dtsi"
+#include "imx93-firmware.dtsi"
/ {
compatible = "fsl,imx91-9x9-qsb", "fsl,imx91";
diff --git a/arch/arm64/boot/dts/freescale/imx91-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx91-phycore-som.dtsi
index 8b8cb3daecbb..509d869a216b 100644
--- a/arch/arm64/boot/dts/freescale/imx91-phycore-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91-phycore-som.dtsi
@@ -11,6 +11,7 @@
#include <dt-bindings/regulator/nxp,pca9450-regulator.h>
#include "imx91.dtsi"
+#include "imx93-firmware.dtsi"
/ {
model = "PHYTEC phyCORE-i.MX91";
diff --git a/arch/arm64/boot/dts/freescale/imx91-tqma9131.dtsi b/arch/arm64/boot/dts/freescale/imx91-tqma9131.dtsi
index c99d7bc16848..ad66fea4099a 100644
--- a/arch/arm64/boot/dts/freescale/imx91-tqma9131.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91-tqma9131.dtsi
@@ -7,6 +7,7 @@
*/
#include "imx91.dtsi"
+#include "imx93-firmware.dtsi"
/{
model = "TQ-Systems i.MX91 TQMa91xxCA / TQMa91xxLA SOM";
@@ -31,13 +32,6 @@ linux,cma {
size = <0 0x10000000>;
linux,cma-default;
};
-
- /* EdgeLock secure enclave */
- ele_reserved: ele-reserved@a4120000 {
- compatible = "shared-dma-pool";
- reg = <0 0xa4120000 0 0x100000>;
- no-map;
- };
};
/* SD2 RST# via PMIC SW_EN */
@@ -58,6 +52,13 @@ &adc1 {
vref-supply = <&buck5>;
};
+&ele_memory {
+ /delete-property/alloc-ranges;
+ /delete-property/size;
+ reg = <0 0xa4120000 0 0x100000>;
+ no-map;
+};
+
&flexspi1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_flexspi1>;
diff --git a/arch/arm64/boot/dts/freescale/imx91-var-dart.dtsi b/arch/arm64/boot/dts/freescale/imx91-var-dart.dtsi
index a9e44efad13f..2e1830c33012 100644
--- a/arch/arm64/boot/dts/freescale/imx91-var-dart.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91-var-dart.dtsi
@@ -13,6 +13,7 @@
#include <dt-bindings/leds/common.h>
#include <dt-bindings/usb/pd.h>
#include "imx91.dtsi"
+#include "imx93-firmware.dtsi"
/ {
model = "Variscite DART-MX91 Module";
diff --git a/arch/arm64/boot/dts/freescale/imx91-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx91-var-som.dtsi
index b30a0d8a81ba..87db0abb8257 100644
--- a/arch/arm64/boot/dts/freescale/imx91-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91-var-som.dtsi
@@ -11,6 +11,7 @@
/dts-v1/;
#include "imx91.dtsi"
+#include "imx93-firmware.dtsi"
/{
model = "Variscite VAR-SOM-MX91 module";
diff --git a/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi b/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
index a1a7e6a0571b..60798b216438 100644
--- a/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx91_93_common.dtsi
@@ -46,6 +46,15 @@ A55_0: cpu@0 {
};
};
+ firmware {
+ hsm0: secure-enclave {
+ compatible = "fsl,imx93-se-ele-hsm";
+ mbox-names = "tx", "rx";
+ mboxes = <&s4muap 0 0>, <&s4muap 1 0>;
+ status = "disabled";
+ };
+ };
+
osc_32k: clock-osc-32k {
compatible = "fixed-clock";
#clock-cells = <0>;
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-common.dtsi b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-common.dtsi
index f48e7947cf64..65db986fc7ba 100644
--- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-common.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-common.dtsi
@@ -4,6 +4,7 @@
*/
#include <dt-bindings/usb/pd.h>
+#include "imx93-firmware.dtsi"
/ {
aliases {
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
index bd14ba28690c..0bd19988ce9f 100644
--- a/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
@@ -3,6 +3,7 @@
#include <dt-bindings/usb/pd.h>
#include "imx93.dtsi"
+#include "imx93-firmware.dtsi"
/ {
compatible = "fsl,imx93-11x11-frdm", "fsl,imx93";
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts
index ec78c03f4788..0e5c7d1ed4ee 100644
--- a/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk.dts
@@ -7,6 +7,7 @@
#include <dt-bindings/usb/pd.h>
#include "imx93.dtsi"
+#include "imx93-firmware.dtsi"
/ {
model = "NXP i.MX93 14X14 EVK board";
diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts
index 01c11c517986..694f114aef36 100644
--- a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts
+++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts
@@ -7,6 +7,7 @@
#include <dt-bindings/usb/pd.h>
#include "imx93.dtsi"
+#include "imx93-firmware.dtsi"
/ {
model = "NXP i.MX93 9x9 Quick Start Board";
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..c9aa764cc3b8 100644
--- a/arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93-kontron-osm-s.dtsi
@@ -5,6 +5,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include "imx93.dtsi"
+#include "imx93-firmware.dtsi"
/ {
model = "Kontron OSM-S i.MX93";
diff --git a/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi b/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi
index 325e465d0056..076716cc2095 100644
--- a/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93-phycore-som.dtsi
@@ -12,6 +12,7 @@
#include <dt-bindings/regulator/nxp,pca9450-regulator.h>
#include "imx93.dtsi"
+#include "imx93-firmware.dtsi"
/{
model = "PHYTEC phyCORE-i.MX93";
diff --git a/arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi b/arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi
index ce34a296495c..159be0d5dfde 100644
--- a/arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93-tqma9352.dtsi
@@ -6,6 +6,7 @@
*/
#include "imx93.dtsi"
+#include "imx93-firmware.dtsi"
/{
model = "TQ-Systems i.MX93 TQMa93xxLA/TQMa93xxCA SOM";
diff --git a/arch/arm64/boot/dts/freescale/imx93-var-dart.dtsi b/arch/arm64/boot/dts/freescale/imx93-var-dart.dtsi
index 69495bb7fc9f..122a8a091c80 100644
--- a/arch/arm64/boot/dts/freescale/imx93-var-dart.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93-var-dart.dtsi
@@ -12,6 +12,7 @@
#include <dt-bindings/usb/pd.h>
#include "imx93.dtsi"
+#include "imx93-firmware.dtsi"
/ {
model = "Variscite DART-MX93 Module";
diff --git a/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi b/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi
index 24063bf8183d..50aec264f87c 100644
--- a/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93-var-som.dtsi
@@ -7,6 +7,7 @@
/dts-v1/;
#include "imx93.dtsi"
+#include "imx93-firmware.dtsi"
/{
model = "Variscite VAR-SOM-MX93 module";
--
2.55.0
^ permalink raw reply related [flat|nested] 16+ messages in thread