* [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver
@ 2026-06-16 11:52 Frieder Schrempf
2026-06-16 11:52 ` [PATCH 1/9] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
` (8 more replies)
0 siblings, 9 replies; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
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)
* Add ELE API functions for accessing the fuses (patch 3)
* Let the OCOTP driver use the ELE API (patch 6)
* Extend the devicetree of the Kontron boards for using the ELE API (patch 9)
The rest of the patches contain cleanups that were implemented along
the way.
This was tested using the 'crucible' tool and through hexdump on the
nvmem device.
---
Frieder Schrempf (9):
dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave
firmware: imx: ele: Fix indentation in ele_base_msg.h
firmware: imx: ele: Add API functions for OCOTP fuse access
nvmem: imx-ocotp-ele: Add keepout table for i.MX93
nvmem: imx-ocotp-ele: Remove device-specific 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 | 4 +
.../boot/dts/freescale/imx93-kontron-osm-s.dtsi | 26 ++++
drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++
drivers/firmware/imx/ele_base_msg.h | 22 ++--
drivers/nvmem/imx-ocotp-ele.c | 137 ++++++++++++++++-----
include/linux/firmware/imx/se_api.h | 3 +
6 files changed, 277 insertions(+), 37 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] 17+ messages in thread
* [PATCH 1/9] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
@ 2026-06-16 11:52 ` Frieder Schrempf
2026-06-17 10:49 ` Krzysztof Kozlowski
2026-06-16 11:52 ` [PATCH 2/9] firmware: imx: ele: Fix indentation in ele_base_msg.h Frieder Schrempf
` (7 subsequent siblings)
8 siblings, 1 reply; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf
From: Frieder Schrempf <frieder.schrempf@kontron.de>
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 | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
index a8076d0e2737..14a6429f4a4c 100644
--- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
+++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
@@ -53,6 +53,10 @@ properties:
reg:
maxItems: 1
+ secure-enclave:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: A phandle to the secure enclave node
+
clocks:
maxItems: 1
--
2.54.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 2/9] firmware: imx: ele: Fix indentation in ele_base_msg.h
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
2026-06-16 11:52 ` [PATCH 1/9] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
@ 2026-06-16 11:52 ` Frieder Schrempf
2026-06-16 11:52 ` [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access Frieder Schrempf
` (6 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
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.54.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
2026-06-16 11:52 ` [PATCH 1/9] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
2026-06-16 11:52 ` [PATCH 2/9] firmware: imx: ele: Fix indentation in ele_base_msg.h Frieder Schrempf
@ 2026-06-16 11:52 ` Frieder Schrempf
2026-06-16 15:36 ` Frank Li
2026-06-16 11:52 ` [PATCH 4/9] nvmem: imx-ocotp-ele: Add keepout table for i.MX93 Frieder Schrempf
` (5 subsequent siblings)
8 siblings, 1 reply; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Frieder Schrempf
From: Frieder Schrempf <frieder.schrempf@kontron.de>
The ELE S400 API provides read and write access to the OCOTP fuse
registers. This adds the necessary API functions imx_se_read_fuse()
and imx_se_write_fuse() to be used by other drivers such as the
OCOTP S400 NVMEM driver.
This is ported from the downstream vendor kernel.
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
drivers/firmware/imx/ele_base_msg.h | 6 ++
include/linux/firmware/imx/se_api.h | 3 +
3 files changed, 131 insertions(+)
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index ec718d322abc..281d223aa144 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"
@@ -303,3 +304,124 @@ int ele_debug_dump(struct se_if_priv *priv)
return ret;
}
+
+static int ele_read_fuse(struct se_if_priv *priv, uint16_t fuse_id, u32 *value)
+{
+ struct se_api_msg *tx_msg __free(kfree) = NULL;
+ struct se_api_msg *rx_msg __free(kfree) = NULL;
+ int rx_msg_sz = ELE_READ_FUSE_RSP_MSG_SZ;
+ int ret = 0;
+
+ if (!priv)
+ return -EINVAL;
+
+ tx_msg = kzalloc(ELE_READ_FUSE_REQ_MSG_SZ, GFP_KERNEL);
+ if (!tx_msg)
+ return -ENOMEM;
+
+ rx_msg = kzalloc(rx_msg_sz, GFP_KERNEL);
+ if (!rx_msg)
+ return -ENOMEM;
+
+ ret = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&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 = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg,
+ ELE_READ_FUSE_REQ_MSG_SZ, rx_msg, rx_msg_sz);
+ if (ret < 0)
+ return ret;
+
+ ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_READ_FUSE_REQ,
+ rx_msg_sz, true);
+ if (ret)
+ return ret;
+
+ *value = rx_msg->data[1];
+
+ return 0;
+}
+
+/**
+ * imx_se_read_fuse() - API to request SE-FW to read the fuse value.
+ * @se_if_data: refs to data attached to the se interface.
+ * @fuse_id: fuse identifier to read.
+ * @value: unsigned integer array to store the fuse values.
+ *
+ * Secure enclave like EdgeLock Enclave, manages the fuses. This API
+ * requests the FW to read the fuses. FW responds with the read values.
+ *
+ * Context:
+ *
+ * Return value:
+ * 0, means success.
+ * < 0, means failure.
+ */
+int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value)
+{
+ return ele_read_fuse((struct se_if_priv *)se_if_data, fuse_id, value);
+}
+EXPORT_SYMBOL_GPL(imx_se_read_fuse);
+
+static int ele_write_fuse(struct se_if_priv *priv, uint16_t fuse_id, u32 value)
+{
+ struct se_api_msg *tx_msg __free(kfree) = NULL;
+ struct se_api_msg *rx_msg __free(kfree) = NULL;
+ int ret = 0;
+
+ 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 = se_fill_cmd_msg_hdr(priv, (struct se_msg_hdr *)&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 = ele_msg_send_rcv(priv->priv_dev_ctx, tx_msg,
+ ELE_WRITE_FUSE_REQ_MSG_SZ, rx_msg,
+ ELE_WRITE_FUSE_RSP_MSG_SZ);
+ if (ret < 0)
+ return ret;
+
+ ret = se_val_rsp_hdr_n_status(priv, rx_msg, ELE_WRITE_FUSE,
+ ELE_WRITE_FUSE_RSP_MSG_SZ, true);
+
+ return ret;
+}
+
+/**
+ * imx_se_write_fuse() - API to request SE-FW to write to fuses.
+ * @se_if_data: refs to data attached to the se interface.
+ * @fuse_id: fuse identifier to write to.
+ * @value: unsigned integer value that to be written to the fuse.
+ *
+ * Secure enclave like EdgeLock Enclave, manages the fuses. This API
+ * requests the FW to write the fuse with the given value.
+ *
+ * Context:
+ *
+ * Return value:
+ * 0, means success.
+ * < 0, means failure.
+ */
+int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value)
+{
+ return ele_write_fuse((struct se_if_priv *)se_if_data, fuse_id, value);
+}
+EXPORT_SYMBOL_GPL(imx_se_write_fuse);
diff --git a/drivers/firmware/imx/ele_base_msg.h b/drivers/firmware/imx/ele_base_msg.h
index 1c5d6791b323..2af3ada2ad07 100644
--- a/drivers/firmware/imx/ele_base_msg.h
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -36,6 +36,12 @@
#define ELE_GET_INFO_REQ_MSG_SZ 0x10
#define ELE_GET_INFO_RSP_MSG_SZ 0x08
+#define ELE_READ_FUSE_REQ_MSG_SZ (8)
+#define ELE_READ_FUSE_RSP_MSG_SZ (12)
+
+#define ELE_WRITE_FUSE_REQ_MSG_SZ (12)
+#define ELE_WRITE_FUSE_RSP_MSG_SZ (12)
+
#define MAX_UID_SIZE (16)
#define DEV_GETINFO_ROM_PATCH_SHA_SZ (32)
#define DEV_GETINFO_FW_SHA_SZ (32)
diff --git a/include/linux/firmware/imx/se_api.h b/include/linux/firmware/imx/se_api.h
index b1c4c9115d7b..ed766b1d48f8 100644
--- a/include/linux/firmware/imx/se_api.h
+++ b/include/linux/firmware/imx/se_api.h
@@ -11,4 +11,7 @@
#define SOC_ID_OF_IMX8ULP 0x084d
#define SOC_ID_OF_IMX93 0x9300
+int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
+int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
+
#endif /* __SE_API_H__ */
--
2.54.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 4/9] nvmem: imx-ocotp-ele: Add keepout table for i.MX93
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (2 preceding siblings ...)
2026-06-16 11:52 ` [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access Frieder Schrempf
@ 2026-06-16 11:52 ` Frieder Schrempf
2026-06-16 11:52 ` [PATCH 5/9] nvmem: imx-ocotp-ele: Remove device-specific reg_read() Frieder Schrempf
` (4 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
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.54.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 5/9] nvmem: imx-ocotp-ele: Remove device-specific reg_read()
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (3 preceding siblings ...)
2026-06-16 11:52 ` [PATCH 4/9] nvmem: imx-ocotp-ele: Add keepout table for i.MX93 Frieder Schrempf
@ 2026-06-16 11:52 ` Frieder Schrempf
2026-06-16 11:52 ` [PATCH 6/9] nvmem: imx-ocotp-ele: Support the ELE API Frieder Schrempf
` (3 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
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.54.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 6/9] nvmem: imx-ocotp-ele: Support the ELE API
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (4 preceding siblings ...)
2026-06-16 11:52 ` [PATCH 5/9] nvmem: imx-ocotp-ele: Remove device-specific reg_read() Frieder Schrempf
@ 2026-06-16 11:52 ` Frieder Schrempf
2026-06-16 11:52 ` [PATCH 7/9] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type Frieder Schrempf
` (2 subsequent siblings)
8 siblings, 0 replies; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
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 | 76 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 75 insertions(+), 1 deletion(-)
diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index 9d3f94e35508..92cc061b9b34 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -6,10 +6,12 @@
*/
#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 */
@@ -44,6 +46,8 @@ struct imx_ocotp_priv {
struct nvmem_config config;
struct mutex lock;
const struct ocotp_devtype_data *data;
+ void *se_data;
+ struct platform_device *se_dev;
};
static enum fuse_type imx_ocotp_fuse_type(void *context, u32 index)
@@ -72,6 +76,7 @@ static int imx_ocotp_reg_read(void *context, unsigned int offset, void *val, siz
enum fuse_type type;
u32 *buf;
void *p;
+ int ret;
int i;
u8 skipbytes;
@@ -92,6 +97,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_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;
@@ -113,6 +131,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_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)
{
@@ -136,11 +180,18 @@ static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
cell->read_post_process = imx_ocotp_cell_pp;
}
+static void imx_ocotp_put_se_dev(void *data)
+{
+ platform_device_put(data);
+}
+
static int imx_ele_ocotp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct imx_ocotp_priv *priv;
struct nvmem_device *nvmem;
+ struct device_node *np;
+ int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -152,16 +203,36 @@ 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(&pdev->dev, "missing or invalid SE handle, using readonly FSB\n");
+ } else {
+ priv->se_dev = of_find_device_by_node(np);
+ of_node_put(np);
+ if (!priv->se_dev)
+ return dev_err_probe(&pdev->dev, -ENODEV, "failed to find SE device\n");
+
+ ret = devm_add_action_or_reset(&pdev->dev, imx_ocotp_put_se_dev,
+ priv->se_dev);
+ if (ret)
+ return ret;
+
+ priv->se_data = platform_get_drvdata(priv->se_dev);
+ if (!priv->se_data)
+ return dev_err_probe(&pdev->dev, -EPROBE_DEFER,
+ "SE device not ready\n");
+ }
+
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;
@@ -170,6 +241,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.54.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 7/9] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (5 preceding siblings ...)
2026-06-16 11:52 ` [PATCH 6/9] nvmem: imx-ocotp-ele: Support the ELE API Frieder Schrempf
@ 2026-06-16 11:52 ` Frieder Schrempf
2026-06-16 11:52 ` [PATCH 8/9] nvmem: imx-ocotp-ele: Rename FSB access map Frieder Schrempf
2026-06-16 11:52 ` [PATCH 9/9] arm64: dts: imx93-kontron: Enable ELE firmware driver Frieder Schrempf
8 siblings, 0 replies; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
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 92cc061b9b34..3d6fad149ed5 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -18,8 +18,7 @@
enum fuse_type {
FUSE_FSB = BIT(0),
- FUSE_ELE = BIT(1),
- FUSE_ECC = BIT(2),
+ FUSE_ECC = BIT(1),
FUSE_INVALID = -1
};
@@ -111,7 +110,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;
}
@@ -264,13 +263,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,
@@ -280,7 +275,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 },
@@ -288,7 +283,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 },
@@ -298,7 +292,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 },
@@ -306,9 +300,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.54.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 8/9] nvmem: imx-ocotp-ele: Rename FSB access map
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (6 preceding siblings ...)
2026-06-16 11:52 ` [PATCH 7/9] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type Frieder Schrempf
@ 2026-06-16 11:52 ` Frieder Schrempf
2026-06-16 11:52 ` [PATCH 9/9] arm64: dts: imx93-kontron: Enable ELE firmware driver Frieder Schrempf
8 siblings, 0 replies; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
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 3d6fad149ed5..766b0d746f6c 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -32,11 +32,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 {
@@ -56,12 +56,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;
@@ -263,8 +263,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 }
},
@@ -275,8 +275,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 },
@@ -292,8 +292,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.54.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 9/9] arm64: dts: imx93-kontron: Enable ELE firmware driver
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
` (7 preceding siblings ...)
2026-06-16 11:52 ` [PATCH 8/9] nvmem: imx-ocotp-ele: Rename FSB access map Frieder Schrempf
@ 2026-06-16 11:52 ` Frieder Schrempf
8 siblings, 0 replies; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 11:52 UTC (permalink / raw)
To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo
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.54.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
2026-06-16 11:52 ` [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access Frieder Schrempf
@ 2026-06-16 15:36 ` Frank Li
2026-06-16 17:59 ` Frieder Schrempf
0 siblings, 1 reply; 17+ messages in thread
From: Frank Li @ 2026-06-16 15:36 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, devicetree, imx, linux-arm-kernel,
linux-kernel, Frieder Schrempf
On Tue, Jun 16, 2026 at 01:52:18PM +0200, Frieder Schrempf wrote:
> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>
> The ELE S400 API provides read and write access to the OCOTP fuse
> registers. This adds the necessary API functions imx_se_read_fuse()
> and imx_se_write_fuse() to be used by other drivers such as the
> OCOTP S400 NVMEM driver.
>
> This is ported from the downstream vendor kernel.
>
> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
> ---
> drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
> drivers/firmware/imx/ele_base_msg.h | 6 ++
> include/linux/firmware/imx/se_api.h | 3 +
> 3 files changed, 131 insertions(+)
>
...
> +++ b/include/linux/firmware/imx/se_api.h
> @@ -11,4 +11,7 @@
> #define SOC_ID_OF_IMX8ULP 0x084d
> #define SOC_ID_OF_IMX93 0x9300
>
> +int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
> +int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
> +
This API should implement in fuse drivers. Other consume should use standard
fuse API to get value. If put here, it may bypass fuse driver.
Frank
> #endif /* __SE_API_H__ */
>
> --
> 2.54.0
>
>
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
2026-06-16 15:36 ` Frank Li
@ 2026-06-16 17:59 ` Frieder Schrempf
2026-06-16 20:05 ` Frank Li
0 siblings, 1 reply; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-16 17:59 UTC (permalink / raw)
To: Frank Li, Frieder Schrempf, Pankaj Gupta
Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo, devicetree, imx, linux-arm-kernel,
linux-kernel
On 16.06.26 17:36, Frank Li wrote:
> On Tue, Jun 16, 2026 at 01:52:18PM +0200, Frieder Schrempf wrote:
>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>>
>> The ELE S400 API provides read and write access to the OCOTP fuse
>> registers. This adds the necessary API functions imx_se_read_fuse()
>> and imx_se_write_fuse() to be used by other drivers such as the
>> OCOTP S400 NVMEM driver.
>>
>> This is ported from the downstream vendor kernel.
>>
>> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
>> ---
>> drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
>> drivers/firmware/imx/ele_base_msg.h | 6 ++
>> include/linux/firmware/imx/se_api.h | 3 +
>> 3 files changed, 131 insertions(+)
>>
> ...
>> +++ b/include/linux/firmware/imx/se_api.h
>> @@ -11,4 +11,7 @@
>> #define SOC_ID_OF_IMX8ULP 0x084d
>> #define SOC_ID_OF_IMX93 0x9300
>>
>> +int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
>> +int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
>> +
>
> This API should implement in fuse drivers. Other consume should use standard
> fuse API to get value. If put here, it may bypass fuse driver.
The reason this is here, is the downstream implementation in linux-imx
and the current code organization. I thought there is some good reason
to have shared functions and it looks like Pankaj structured it like
this so all API functions live in ele_base_msg.c and the internal
structs and defines in ele_base_msg.h and se_ctrl.h are not exposed to
other drivers.
If I would move this into imx-ocotp-ele.c, then I would also need to
change how the code is organized and make the internal se_api functions
exposed to other drivers. I don't know if that is really a good idea.
I get your point but it looks like this contradicts the intention of
having a clean API in the firmware driver.
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
2026-06-16 17:59 ` Frieder Schrempf
@ 2026-06-16 20:05 ` Frank Li
2026-06-17 6:54 ` Frieder Schrempf
0 siblings, 1 reply; 17+ messages in thread
From: Frank Li @ 2026-06-16 20:05 UTC (permalink / raw)
To: Frieder Schrempf
Cc: Frieder Schrempf, Pankaj Gupta, Srinivas Kandagatla, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Shawn Guo, devicetree,
imx, linux-arm-kernel, linux-kernel
On Tue, Jun 16, 2026 at 07:59:54PM +0200, Frieder Schrempf wrote:
> On 16.06.26 17:36, Frank Li wrote:
> > On Tue, Jun 16, 2026 at 01:52:18PM +0200, Frieder Schrempf wrote:
> >> From: Frieder Schrempf <frieder.schrempf@kontron.de>
> >>
> >> The ELE S400 API provides read and write access to the OCOTP fuse
> >> registers. This adds the necessary API functions imx_se_read_fuse()
> >> and imx_se_write_fuse() to be used by other drivers such as the
> >> OCOTP S400 NVMEM driver.
> >>
> >> This is ported from the downstream vendor kernel.
> >>
> >> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
> >> ---
> >> drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
> >> drivers/firmware/imx/ele_base_msg.h | 6 ++
> >> include/linux/firmware/imx/se_api.h | 3 +
> >> 3 files changed, 131 insertions(+)
> >>
> > ...
> >> +++ b/include/linux/firmware/imx/se_api.h
> >> @@ -11,4 +11,7 @@
> >> #define SOC_ID_OF_IMX8ULP 0x084d
> >> #define SOC_ID_OF_IMX93 0x9300
> >>
> >> +int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
> >> +int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
> >> +
> >
> > This API should implement in fuse drivers. Other consume should use standard
> > fuse API to get value. If put here, it may bypass fuse driver.
>
> The reason this is here, is the downstream implementation in linux-imx
> and the current code organization.
Downstream may not good enough, sometime, it is quick solution.
> I thought there is some good reason
> to have shared functions and it looks like Pankaj structured it like
> this so all API functions live in ele_base_msg.c and the internal
> structs and defines in ele_base_msg.h and se_ctrl.h are not exposed to
> other drivers.
>
> If I would move this into imx-ocotp-ele.c, then I would also need to
> change how the code is organized and make the internal se_api functions
> exposed to other drivers. I don't know if that is really a good idea.
>
> I get your point but it looks like this contradicts the intention of
> having a clean API in the firmware driver.
You can refer imx-ocotp-scu.c, structure should be similar, only difference
is that lower transfer APIs.
Frank
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
2026-06-16 20:05 ` Frank Li
@ 2026-06-17 6:54 ` Frieder Schrempf
2026-06-17 19:56 ` Frank Li
0 siblings, 1 reply; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-17 6:54 UTC (permalink / raw)
To: Frank Li, Pankaj Gupta, Peng Fan (OSS)
Cc: Frieder Schrempf, Srinivas Kandagatla, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Shawn Guo, devicetree,
imx, linux-arm-kernel, linux-kernel
On 16.06.26 22:05, Frank Li wrote:
> On Tue, Jun 16, 2026 at 07:59:54PM +0200, Frieder Schrempf wrote:
>> On 16.06.26 17:36, Frank Li wrote:
>>> On Tue, Jun 16, 2026 at 01:52:18PM +0200, Frieder Schrempf wrote:
>>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>>>>
>>>> The ELE S400 API provides read and write access to the OCOTP fuse
>>>> registers. This adds the necessary API functions imx_se_read_fuse()
>>>> and imx_se_write_fuse() to be used by other drivers such as the
>>>> OCOTP S400 NVMEM driver.
>>>>
>>>> This is ported from the downstream vendor kernel.
>>>>
>>>> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
>>>> ---
>>>> drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
>>>> drivers/firmware/imx/ele_base_msg.h | 6 ++
>>>> include/linux/firmware/imx/se_api.h | 3 +
>>>> 3 files changed, 131 insertions(+)
>>>>
>>> ...
>>>> +++ b/include/linux/firmware/imx/se_api.h
>>>> @@ -11,4 +11,7 @@
>>>> #define SOC_ID_OF_IMX8ULP 0x084d
>>>> #define SOC_ID_OF_IMX93 0x9300
>>>>
>>>> +int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
>>>> +int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
>>>> +
>>>
>>> This API should implement in fuse drivers. Other consume should use standard
>>> fuse API to get value. If put here, it may bypass fuse driver.
>>
>> The reason this is here, is the downstream implementation in linux-imx
>> and the current code organization.
>
> Downstream may not good enough, sometime, it is quick solution.
Ok, but the code structure and API design has been upstreamed like this
and the refactoring could have been done before, if downstream is known
to not be well organized.
>
>> I thought there is some good reason
>> to have shared functions and it looks like Pankaj structured it like
>> this so all API functions live in ele_base_msg.c and the internal
>> structs and defines in ele_base_msg.h and se_ctrl.h are not exposed to
>> other drivers.
>>
>> If I would move this into imx-ocotp-ele.c, then I would also need to
>> change how the code is organized and make the internal se_api functions
>> exposed to other drivers. I don't know if that is really a good idea.
>>
>> I get your point but it looks like this contradicts the intention of
>> having a clean API in the firmware driver.
>
> You can refer imx-ocotp-scu.c, structure should be similar, only difference
> is that lower transfer APIs.
Ok, this would mean that I expose the generic SE functions and structs
required for fuse handling. In practice, I would remove
imx_se_read_fuse() and imx_se_write_fuse() from se_api.h and instead add
the following:
struct se_msg_hdr { ... };
struct se_api_msg { ... };
struct se_if_priv;
se_fill_cmd_msg_hdr( ... );
se_msg_send_rcv( ... );
se_val_rsp_hdr_n_status( ... );
Then I would export the functions in ele_common.c and put the fuse
read/write functions in the NVMEM driver.
Is that what you want me to do?
Pankaj (and maybe Peng), do you have any comments on this?
Thanks!
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/9] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave
2026-06-16 11:52 ` [PATCH 1/9] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
@ 2026-06-17 10:49 ` Krzysztof Kozlowski
2026-06-17 11:36 ` Frieder Schrempf
0 siblings, 1 reply; 17+ messages in thread
From: Krzysztof Kozlowski @ 2026-06-17 10:49 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, devicetree, imx, linux-arm-kernel,
linux-kernel, Frieder Schrempf
On Tue, Jun 16, 2026 at 01:52:16PM +0200, Frieder Schrempf wrote:
> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>
> 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 | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
> index a8076d0e2737..14a6429f4a4c 100644
> --- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
> +++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
> @@ -53,6 +53,10 @@ properties:
> reg:
> maxItems: 1
>
> + secure-enclave:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: A phandle to the secure enclave node
Two things here:
1. Here you describe what for is that phandle, how it is used by the
hardware. Currently the description repeats the property name and type,
so not much useful.
2. If you access OTP via firmware, then this is completely different
interface than MMIO, thus:
A. reg is not appropriate
B. Device is very different thus it has different compatible and I even
claim should be in different binding. Devices having completely
different SW interface should not be in the same binding, at least
usually.
If any of above is not accurate, then your commit msg should answer why
and give some background.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 1/9] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave
2026-06-17 10:49 ` Krzysztof Kozlowski
@ 2026-06-17 11:36 ` Frieder Schrempf
0 siblings, 0 replies; 17+ messages in thread
From: Frieder Schrempf @ 2026-06-17 11:36 UTC (permalink / raw)
To: Krzysztof Kozlowski, Frieder Schrempf
Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo, devicetree, imx, linux-arm-kernel,
linux-kernel
On 17.06.26 12:49, Krzysztof Kozlowski wrote:
> On Tue, Jun 16, 2026 at 01:52:16PM +0200, Frieder Schrempf wrote:
>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>>
>> 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 | 4 ++++
>> 1 file changed, 4 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
>> index a8076d0e2737..14a6429f4a4c 100644
>> --- a/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
>> +++ b/Documentation/devicetree/bindings/nvmem/imx-ocotp.yaml
>> @@ -53,6 +53,10 @@ properties:
>> reg:
>> maxItems: 1
>>
>> + secure-enclave:
>> + $ref: /schemas/types.yaml#/definitions/phandle
>> + description: A phandle to the secure enclave node
>
> Two things here:
> 1. Here you describe what for is that phandle, how it is used by the
> hardware. Currently the description repeats the property name and type,
> so not much useful.
Ok, agree.
>
> 2. If you access OTP via firmware, then this is completely different
> interface than MMIO, thus:
> A. reg is not appropriate
> B. Device is very different thus it has different compatible and I even
> claim should be in different binding. Devices having completely
> different SW interface should not be in the same binding, at least
> usually.
>
> If any of above is not accurate, then your commit msg should answer why
> and give some background.
Thanks for the feedback!
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.
Following your argument would mean a driver deciding by itself which
interface to use at runtime is not something we want to have in general,
right?
In turn this would mean we need two drivers, or at least two
compatibles/bindings for something that is effectively the same hardware.
Actually, my first RFC approach [1] was to create a separate driver. But
in the end it seemed very weird to have two drivers and two DT nodes for
the same hardware block. Also I have no idea what happens if both
interfaces are used at the same time.
The other idea from back then was to replace the MMIO (FSB) interface
with ELE, but this would mean that we rely on the proprietary ELE
firmware to be available for simple things like reading a MAC address,
which is not desirable either, I guess.
In which direction should I move on with this?
[1]
https://patchwork.kernel.org/project/linux-arm-kernel/patch/20250416142715.1042363-1-frieder@fris.de/
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
2026-06-17 6:54 ` Frieder Schrempf
@ 2026-06-17 19:56 ` Frank Li
0 siblings, 0 replies; 17+ messages in thread
From: Frank Li @ 2026-06-17 19:56 UTC (permalink / raw)
To: Frieder Schrempf
Cc: Pankaj Gupta, Peng Fan (OSS), Frieder Schrempf,
Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo, devicetree, imx, linux-arm-kernel,
linux-kernel
On Wed, Jun 17, 2026 at 08:54:35AM +0200, Frieder Schrempf wrote:
> On 16.06.26 22:05, Frank Li wrote:
> > On Tue, Jun 16, 2026 at 07:59:54PM +0200, Frieder Schrempf wrote:
> >> On 16.06.26 17:36, Frank Li wrote:
> >>> On Tue, Jun 16, 2026 at 01:52:18PM +0200, Frieder Schrempf wrote:
> >>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
> >>>>
> >>>> The ELE S400 API provides read and write access to the OCOTP fuse
> >>>> registers. This adds the necessary API functions imx_se_read_fuse()
> >>>> and imx_se_write_fuse() to be used by other drivers such as the
> >>>> OCOTP S400 NVMEM driver.
> >>>>
> >>>> This is ported from the downstream vendor kernel.
> >>>>
> >>>> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
> >>>> ---
> >>>> drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
> >>>> drivers/firmware/imx/ele_base_msg.h | 6 ++
> >>>> include/linux/firmware/imx/se_api.h | 3 +
> >>>> 3 files changed, 131 insertions(+)
> >>>>
> >>> ...
> >>>> +++ b/include/linux/firmware/imx/se_api.h
> >>>> @@ -11,4 +11,7 @@
> >>>> #define SOC_ID_OF_IMX8ULP 0x084d
> >>>> #define SOC_ID_OF_IMX93 0x9300
> >>>>
> >>>> +int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
> >>>> +int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
> >>>> +
> >>>
> >>> This API should implement in fuse drivers. Other consume should use standard
> >>> fuse API to get value. If put here, it may bypass fuse driver.
> >>
> >> The reason this is here, is the downstream implementation in linux-imx
> >> and the current code organization.
> >
> > Downstream may not good enough, sometime, it is quick solution.
>
> Ok, but the code structure and API design has been upstreamed like this
> and the refactoring could have been done before, if downstream is known
> to not be well organized.
>
> >
> >> I thought there is some good reason
> >> to have shared functions and it looks like Pankaj structured it like
> >> this so all API functions live in ele_base_msg.c and the internal
> >> structs and defines in ele_base_msg.h and se_ctrl.h are not exposed to
> >> other drivers.
> >>
> >> If I would move this into imx-ocotp-ele.c, then I would also need to
> >> change how the code is organized and make the internal se_api functions
> >> exposed to other drivers. I don't know if that is really a good idea.
> >>
> >> I get your point but it looks like this contradicts the intention of
> >> having a clean API in the firmware driver.
> >
> > You can refer imx-ocotp-scu.c, structure should be similar, only difference
> > is that lower transfer APIs.
> Ok, this would mean that I expose the generic SE functions and structs
> required for fuse handling. In practice, I would remove
> imx_se_read_fuse() and imx_se_write_fuse() from se_api.h and instead add
> the following:
>
> struct se_msg_hdr { ... };
> struct se_api_msg { ... };
> struct se_if_priv;
> se_fill_cmd_msg_hdr( ... );
> se_msg_send_rcv( ... );
> se_val_rsp_hdr_n_status( ... );
>
> Then I would export the functions in ele_common.c and put the fuse
> read/write functions in the NVMEM driver.
>
> Is that what you want me to do?
Yes, Idealy, it should be children device under ele, ELE like a bus, which
previous lower level data transfer, ocotp should be base on top then it.
like spi/i2c, which provide low level data transfer.
Frank
>
> Pankaj (and maybe Peng), do you have any comments on this?
>
> Thanks!
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2026-06-17 19:57 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-16 11:52 [PATCH 0/9] Support ELE API in i.MX OCOTP NVMEM driver Frieder Schrempf
2026-06-16 11:52 ` [PATCH 1/9] dt-bindings: nvmem: imx-ocotp: Add support for secure-enclave Frieder Schrempf
2026-06-17 10:49 ` Krzysztof Kozlowski
2026-06-17 11:36 ` Frieder Schrempf
2026-06-16 11:52 ` [PATCH 2/9] firmware: imx: ele: Fix indentation in ele_base_msg.h Frieder Schrempf
2026-06-16 11:52 ` [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access Frieder Schrempf
2026-06-16 15:36 ` Frank Li
2026-06-16 17:59 ` Frieder Schrempf
2026-06-16 20:05 ` Frank Li
2026-06-17 6:54 ` Frieder Schrempf
2026-06-17 19:56 ` Frank Li
2026-06-16 11:52 ` [PATCH 4/9] nvmem: imx-ocotp-ele: Add keepout table for i.MX93 Frieder Schrempf
2026-06-16 11:52 ` [PATCH 5/9] nvmem: imx-ocotp-ele: Remove device-specific reg_read() Frieder Schrempf
2026-06-16 11:52 ` [PATCH 6/9] nvmem: imx-ocotp-ele: Support the ELE API Frieder Schrempf
2026-06-16 11:52 ` [PATCH 7/9] nvmem: imx-ocotp-ele: Remove the FUSE_ELE type Frieder Schrempf
2026-06-16 11:52 ` [PATCH 8/9] nvmem: imx-ocotp-ele: Rename FSB access map Frieder Schrempf
2026-06-16 11:52 ` [PATCH 9/9] arm64: dts: imx93-kontron: Enable ELE firmware driver Frieder Schrempf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox