* [RFC PATCH 1/5] firmware: imx: ele: Add API functions for OCOTP fuse access
2025-04-16 14:26 [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Frieder Schrempf
@ 2025-04-16 14:26 ` Frieder Schrempf
2025-04-16 14:26 ` [RFC PATCH 2/5] nvmem: Add i.MX OCOTP fuse driver using ELE S400 API Frieder Schrempf
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Frieder Schrempf @ 2025-04-16 14:26 UTC (permalink / raw)
To: Peng Fan, Pankaj Gupta, linux-arm-kernel, imx, linux-kernel,
Sascha Hauer, Shawn Guo
Cc: Frieder Schrempf, Fabio Estevam, Frank Li,
Pengutronix Kernel Team
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 | 8 ++
include/linux/firmware/imx/se_api.h | 3 +
3 files changed, 133 insertions(+)
diff --git a/drivers/firmware/imx/ele_base_msg.c b/drivers/firmware/imx/ele_base_msg.c
index bed1a0459d8d..0dfd4d2fef5a 100644
--- a/drivers/firmware/imx/ele_base_msg.c
+++ b/drivers/firmware/imx/ele_base_msg.c
@@ -311,3 +311,125 @@ 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(s) value.
+ * @void *se_if_data: refs to data attached to the se interface.
+ * @uint16_t fuse_id: Fuse identifier to read.
+ * @u32 *value: unsigned integer array to store the fuse values.
+ *
+ * Secure enclave like EdgeLock Enclave, manages the fuse. 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.
+ * @void *se_if_data: refs to data attached to the se interface.
+ * @uint16_t fuse_id: Fuse identifier to write to.
+ * @u32 value: unsigned integer value that to be written to the fuse.
+ *
+ * Secure enclave like EdgeLock Enclave, manages the fuse. 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 dd89412f485e..22f553cdbc33 100644
--- a/drivers/firmware/imx/ele_base_msg.h
+++ b/drivers/firmware/imx/ele_base_msg.h
@@ -19,6 +19,14 @@
#define ELE_GET_INFO_REQ_MSG_SZ 0x10
#define ELE_GET_INFO_RSP_MSG_SZ 0x08
+#define ELE_WRITE_FUSE 0xD6
+#define ELE_WRITE_FUSE_REQ_MSG_SZ 12
+#define ELE_WRITE_FUSE_RSP_MSG_SZ 12
+
+#define ELE_READ_FUSE_REQ 0x97
+#define ELE_READ_FUSE_REQ_MSG_SZ 0x08
+#define ELE_READ_FUSE_RSP_MSG_SZ 0x0C
+
#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..9503b9363593 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_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
+int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
+
#endif /* __SE_API_H__ */
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC PATCH 2/5] nvmem: Add i.MX OCOTP fuse driver using ELE S400 API
2025-04-16 14:26 [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Frieder Schrempf
2025-04-16 14:26 ` [RFC PATCH 1/5] firmware: imx: ele: Add API functions for OCOTP fuse access Frieder Schrempf
@ 2025-04-16 14:26 ` Frieder Schrempf
2025-04-16 14:26 ` [RFC PATCH 3/5] arm64: dts: imx93: Add node for EdgeLock Enclave (ELE) firmware driver Frieder Schrempf
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Frieder Schrempf @ 2025-04-16 14:26 UTC (permalink / raw)
To: Peng Fan, Pankaj Gupta, linux-arm-kernel, imx, linux-kernel,
Sascha Hauer, Shawn Guo, Srinivas Kandagatla
Cc: Frieder Schrempf, Arnd Bergmann, Fabio Estevam,
Geert Uytterhoeven, Greg Kroah-Hartman, Miquel Raynal,
Pengutronix Kernel Team, Rafał Miłecki,
Yoshihiro Shimoda
From: Frieder Schrempf <frieder.schrempf@kontron.de>
The ELE S400 API is the only way to get full read and write access
to all OCOTP fuse registers. The other possible way through the FSB
is limited and currently provided by the imx-ocotp-ele driver
(misnamed as it currently doesn't use the ELE API at all).
This provides a separate driver that uses the ELE API to provide
an NVMEM device for the OTP fuses.
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
drivers/nvmem/Kconfig | 11 ++
drivers/nvmem/Makefile | 2 +
drivers/nvmem/imx-ocotp-s400.c | 195 +++++++++++++++++++++++++++++++++
3 files changed, 208 insertions(+)
create mode 100644 drivers/nvmem/imx-ocotp-s400.c
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 8671b7c974b9..b7109637f47b 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -93,6 +93,17 @@ config NVMEM_IMX_OCOTP_ELE
This is a driver for the On-Chip OTP Controller (OCOTP)
available on i.MX SoCs which has ELE.
+config NVMEM_IMX_OCOTP_S400
+ tristate "i.MX On-Chip OTP support via S400 API"
+ depends on ARCH_MXC || COMPILE_TEST
+ depends on IMX_SEC_ENCLAVE
+ help
+ This is a driver for the OCOTP fuses accessed through the S400 API
+ of the Secure Enclave firmware.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem-imx-ocotp-s400.
+
config NVMEM_IMX_OCOTP_SCU
tristate "i.MX8 SCU On-Chip OTP Controller support"
depends on IMX_SCU
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 5b77bbb6488b..96572fd7cd6e 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -22,6 +22,8 @@ obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o
nvmem-imx-ocotp-y := imx-ocotp.o
obj-$(CONFIG_NVMEM_IMX_OCOTP_ELE) += nvmem-imx-ocotp-ele.o
nvmem-imx-ocotp-ele-y := imx-ocotp-ele.o
+obj-$(CONFIG_NVMEM_IMX_OCOTP_S400) += nvmem-imx-ocotp-s400.o
+nvmem-imx-ocotp-s400-y := imx-ocotp-s400.o
obj-$(CONFIG_NVMEM_IMX_OCOTP_SCU) += nvmem-imx-ocotp-scu.o
nvmem-imx-ocotp-scu-y := imx-ocotp-scu.o
obj-$(CONFIG_NVMEM_JZ4780_EFUSE) += nvmem_jz4780_efuse.o
diff --git a/drivers/nvmem/imx-ocotp-s400.c b/drivers/nvmem/imx-ocotp-s400.c
new file mode 100644
index 000000000000..b14d3a88f52a
--- /dev/null
+++ b/drivers/nvmem/imx-ocotp-s400.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Kontron Electronics GmbH
+ */
+
+#include <linux/dev_printk.h>
+#include <linux/errno.h>
+#include <linux/firmware/imx/se_api.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+struct imx_s400_fuse_hw {
+ const bool reverse_mac_address;
+ const struct nvmem_keepout *keepout;
+ unsigned int nkeepout;
+};
+
+struct imx_s400_fuse {
+ const struct imx_s400_fuse_hw *hw;
+ struct platform_device *se_dev;
+ struct nvmem_config config;
+ struct mutex lock;
+ void *se_data;
+};
+
+static int imx_s400_fuse_read(void *priv, unsigned int offset, void *val,
+ size_t bytes)
+{
+ struct imx_s400_fuse *fuse = priv;
+ u32 i, word, num_words;
+ int ret;
+
+ word = offset >> 2;
+ num_words = bytes >> 2;
+
+ mutex_lock(&fuse->lock);
+
+ for (i = word; i < (word + num_words); i++) {
+ ret = imx_se_read_fuse(fuse->se_data, i, ((u32 *)val) + i - word);
+ if (ret) {
+ mutex_unlock(&fuse->lock);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&fuse->lock);
+ return 0;
+}
+
+static int imx_s400_fuse_post_process(void *priv, const char *id, int index,
+ unsigned int offset, void *data,
+ size_t bytes)
+{
+ u8 *buf = data;
+ int i;
+
+ if (id && !strcmp(id, "mac-address")) {
+ for (i = 0; i < bytes / 2; i++)
+ swap(buf[i], buf[bytes - i - 1]);
+ }
+
+ return 0;
+}
+
+static int imx_s400_fuse_write(void *priv, unsigned int offset, void *val, size_t bytes)
+{
+ struct imx_s400_fuse *fuse = priv;
+ u32 word = offset >> 2;
+ u32 *buf = val;
+ int ret;
+
+ /* allow only writing one complete OTP word at a time */
+ if (bytes != 4)
+ return -EINVAL;
+
+ /*
+ * The S400 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(&fuse->lock);
+ ret = imx_se_write_fuse(fuse->se_data, word, *buf);
+ mutex_unlock(&fuse->lock);
+
+ return ret;
+}
+
+static void imx_s400_fuse_fixup_cell_info(struct nvmem_device *nvmem,
+ struct nvmem_cell_info *cell)
+{
+ cell->read_post_process = imx_s400_fuse_post_process;
+}
+
+static int imx_s400_fuse_probe(struct platform_device *pdev)
+{
+ struct imx_s400_fuse *fuse;
+ struct nvmem_device *nvmem;
+ struct device_node *np;
+
+ fuse = devm_kzalloc(&pdev->dev, sizeof(*fuse), GFP_KERNEL);
+ if (!fuse)
+ return -ENOMEM;
+
+ fuse->hw = of_device_get_match_data(&pdev->dev);
+
+ fuse->config.dev = &pdev->dev;
+ fuse->config.name = "imx_s400_fuse";
+ fuse->config.id = NVMEM_DEVID_AUTO;
+ fuse->config.owner = THIS_MODULE;
+ fuse->config.size = 2048; /* 64 Banks of 8 Words */
+ fuse->config.word_size = 4;
+ fuse->config.add_legacy_fixed_of_cells = true;
+ fuse->config.reg_read = imx_s400_fuse_read;
+ fuse->config.reg_write = imx_s400_fuse_write;
+ fuse->config.priv = fuse;
+ fuse->config.keepout = fuse->hw->keepout;
+ fuse->config.nkeepout = fuse->hw->nkeepout;
+
+ if (fuse->hw->reverse_mac_address)
+ fuse->config.fixup_dt_cell_info = &imx_s400_fuse_fixup_cell_info;
+
+ dev_set_drvdata(&pdev->dev, fuse);
+
+ mutex_init(&fuse->lock);
+
+ nvmem = devm_nvmem_register(&pdev->dev, &fuse->config);
+ if (IS_ERR(nvmem))
+ return dev_err_probe(&pdev->dev, PTR_ERR(nvmem), "failed to register nvmem device\n");
+
+ np = of_parse_phandle(pdev->dev.of_node, "secure-enclave", 0);
+ if (!np)
+ return dev_err_probe(&pdev->dev, -ENODEV, "missing or invalid secure-enclave handle\n");
+
+ fuse->se_dev = of_find_device_by_node(np);
+ of_node_put(np);
+ if (!fuse->se_dev)
+ return dev_err_probe(&pdev->dev, -ENODEV, "failed to find secure-enclave device\n");
+
+ get_device(&fuse->se_dev->dev);
+ fuse->se_data = platform_get_drvdata(fuse->se_dev);
+ if (!fuse->se_data)
+ return -EPROBE_DEFER;
+
+ dev_info(&pdev->dev, "i.MX S400 OCOTP NVMEM device registered successfully\n");
+
+ return 0;
+}
+
+static void imx_s400_fuse_remove(struct platform_device *pdev)
+{
+ struct imx_s400_fuse *fuse = platform_get_drvdata(pdev);
+ put_device(&fuse->se_dev->dev);
+}
+
+static const struct nvmem_keepout imx93_s400_keepout[] = {
+ {.start = 208, .end = 252},
+ {.start = 256, .end = 512},
+ {.start = 576, .end = 728},
+ {.start = 732, .end = 752},
+ {.start = 756, .end = 1248},
+};
+
+static const struct imx_s400_fuse_hw imx93_s400_fuse_hw = {
+ .reverse_mac_address = true,
+ .keepout = imx93_s400_keepout,
+ .nkeepout = ARRAY_SIZE(imx93_s400_keepout),
+};
+
+static const struct of_device_id imx_s400_fuse_match[] = {
+ { .compatible = "fsl,imx93-ocotp-s400", .data = &imx93_s400_fuse_hw, },
+ {},
+};
+
+static struct platform_driver imx_s400_fuse_driver = {
+ .driver = {
+ .name = "fsl-ocotp-s400",
+ .of_match_table = imx_s400_fuse_match,
+ },
+ .probe = imx_s400_fuse_probe,
+ .remove = imx_s400_fuse_remove,
+};
+MODULE_DEVICE_TABLE(of, imx_s400_fuse_match);
+module_platform_driver(imx_s400_fuse_driver);
+
+MODULE_AUTHOR("Frieder Schrempf <frieder.schrempf@kontron.de>");
+MODULE_DESCRIPTION("i.MX S400 OCOTP Driver");
+MODULE_LICENSE("GPL v2");
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC PATCH 3/5] arm64: dts: imx93: Add node for EdgeLock Enclave (ELE) firmware driver
2025-04-16 14:26 [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Frieder Schrempf
2025-04-16 14:26 ` [RFC PATCH 1/5] firmware: imx: ele: Add API functions for OCOTP fuse access Frieder Schrempf
2025-04-16 14:26 ` [RFC PATCH 2/5] nvmem: Add i.MX OCOTP fuse driver using ELE S400 API Frieder Schrempf
@ 2025-04-16 14:26 ` Frieder Schrempf
2025-04-16 14:26 ` [RFC PATCH 4/5] arm64: dts: imx93: Add node for OCOTP S400 NVMEM driver Frieder Schrempf
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Frieder Schrempf @ 2025-04-16 14:26 UTC (permalink / raw)
To: Peng Fan, Pankaj Gupta, linux-arm-kernel, Conor Dooley,
devicetree, imx, Krzysztof Kozlowski, linux-kernel, Rob Herring,
Sascha Hauer, Shawn Guo
Cc: Frieder Schrempf, Fabio Estevam, Frank Li, Haibo Chen,
Pengutronix Kernel Team, Shengjiu Wang, Shenwei Wang, Xu Yang
From: Frieder Schrempf <frieder.schrempf@kontron.de>
This adds the node for the ELE firmware driver that provides the
S400 API.
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
arch/arm64/boot/dts/freescale/imx93.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi
index 64cd0776b43d..122519648d1b 100644
--- a/arch/arm64/boot/dts/freescale/imx93.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93.dtsi
@@ -222,6 +222,12 @@ cm33: remoteproc-cm33 {
status = "disabled";
};
+ hsm0: secure-enclave {
+ compatible = "fsl,imx93-se-ele-hsm";
+ mbox-names = "tx", "rx";
+ mboxes = <&s4muap 0 0>, <&s4muap 1 0>;
+ };
+
mqs1: mqs1 {
compatible = "fsl,imx93-mqs";
gpr = <&aonmix_ns_gpr>;
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC PATCH 4/5] arm64: dts: imx93: Add node for OCOTP S400 NVMEM driver
2025-04-16 14:26 [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Frieder Schrempf
` (2 preceding siblings ...)
2025-04-16 14:26 ` [RFC PATCH 3/5] arm64: dts: imx93: Add node for EdgeLock Enclave (ELE) firmware driver Frieder Schrempf
@ 2025-04-16 14:26 ` Frieder Schrempf
2025-04-16 14:26 ` [RFC PATCH 5/5] arm64: dts: imx93-kontron: Add DMA memory region for ELE firmware Frieder Schrempf
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Frieder Schrempf @ 2025-04-16 14:26 UTC (permalink / raw)
To: Peng Fan, Pankaj Gupta, linux-arm-kernel, Conor Dooley,
devicetree, imx, Krzysztof Kozlowski, linux-kernel, Rob Herring,
Sascha Hauer, Shawn Guo
Cc: Frieder Schrempf, Carlos Song, Fabio Estevam, Frank Li,
Haibo Chen, Pengutronix Kernel Team, Shengjiu Wang, Shenwei Wang,
Xu Yang
From: Frieder Schrempf <frieder.schrempf@kontron.de>
This adds a node for the OCOTP NVMEM driver that uses the
ELE S400 API to access the fuse registers.
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
arch/arm64/boot/dts/freescale/imx93.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/imx93.dtsi b/arch/arm64/boot/dts/freescale/imx93.dtsi
index 122519648d1b..12463cf6c214 100644
--- a/arch/arm64/boot/dts/freescale/imx93.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx93.dtsi
@@ -228,6 +228,11 @@ hsm0: secure-enclave {
mboxes = <&s4muap 0 0>, <&s4muap 1 0>;
};
+ ocotp-s400 {
+ compatible = "fsl,imx93-ocotp-s400";
+ secure-enclave = <&hsm0>;
+ };
+
mqs1: mqs1 {
compatible = "fsl,imx93-mqs";
gpr = <&aonmix_ns_gpr>;
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [RFC PATCH 5/5] arm64: dts: imx93-kontron: Add DMA memory region for ELE firmware
2025-04-16 14:26 [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Frieder Schrempf
` (3 preceding siblings ...)
2025-04-16 14:26 ` [RFC PATCH 4/5] arm64: dts: imx93: Add node for OCOTP S400 NVMEM driver Frieder Schrempf
@ 2025-04-16 14:26 ` Frieder Schrempf
2025-04-22 6:30 ` [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Peng Fan
2025-04-22 6:40 ` Arnd Bergmann
6 siblings, 0 replies; 10+ messages in thread
From: Frieder Schrempf @ 2025-04-16 14:26 UTC (permalink / raw)
To: Peng Fan, Pankaj Gupta, linux-arm-kernel, Conor Dooley,
devicetree, imx, Krzysztof Kozlowski, linux-kernel, Rob Herring,
Sascha Hauer, Shawn Guo
Cc: Frieder Schrempf, Fabio Estevam, Pengutronix Kernel Team
From: Frieder Schrempf <frieder.schrempf@kontron.de>
The Edgelock Enclave firmware requires a small 1 MiB memory pool.
Reserving this pool makes the ELE firmware driver probe and allows
us to use the S400 API.
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
---
.../boot/dts/freescale/imx93-kontron-osm-s.dtsi | 16 ++++++++++++++++
1 file changed, 16 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 119a16207059..44d98cf812bf 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,18 @@ chosen {
stdout-path = &lpuart1;
};
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ ele_reserved: memory@90000000 {
+ compatible = "shared-dma-pool";
+ reg = <0 0x90000000 0 0x100000>;
+ no-map;
+ };
+ };
+
reg_usdhc2_vcc: regulator-usdhc2-vcc {
compatible = "regulator-fixed";
pinctrl-names = "default";
@@ -116,6 +128,10 @@ &gpio4 {
"GPIO_B_0", "CARRIER_PWR_EN";
};
+&hsm0 {
+ memory-region = <&ele_reserved>;
+};
+
&lpi2c1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lpi2c1>;
--
2.49.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE
2025-04-16 14:26 [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Frieder Schrempf
` (4 preceding siblings ...)
2025-04-16 14:26 ` [RFC PATCH 5/5] arm64: dts: imx93-kontron: Add DMA memory region for ELE firmware Frieder Schrempf
@ 2025-04-22 6:30 ` Peng Fan
2025-04-22 7:33 ` Frieder Schrempf
2025-04-22 6:40 ` Arnd Bergmann
6 siblings, 1 reply; 10+ messages in thread
From: Peng Fan @ 2025-04-22 6:30 UTC (permalink / raw)
To: Frieder Schrempf
Cc: Peng Fan, Pankaj Gupta, linux-arm-kernel, Conor Dooley,
devicetree, imx, Krzysztof Kozlowski, linux-kernel, Rob Herring,
Sascha Hauer, Shawn Guo, Srinivas Kandagatla, Frieder Schrempf,
Arnd Bergmann, Fabio Estevam, Frank Li, Geert Uytterhoeven,
Greg Kroah-Hartman, Pengutronix Kernel Team,
Rafał Miłecki, Shengjiu Wang, Shenwei Wang, Xu Yang,
Yoshihiro Shimoda
Hi Frieder,
On Wed, Apr 16, 2025 at 04:26:19PM +0200, Frieder Schrempf wrote:
>From: Frieder Schrempf <frieder.schrempf@kontron.de>
>
>This depends on [1] for the support of the Edgelock Secure Enclave firmware
>driver.
>
>There are at least two ways to access the OTP fuses on i.MX93:
>
>(1) through the FSB (fuseblock) registers
>(2) through the ELE S400 API
>
>There currently is a NVMEM driver imx-ocotp-ele.c that (despite its name)
>implements (1). As the FSB only provides limited access to the OTP registers
>(read only) it's not sufficient for all use-cases.
>
>It seems like imx-ocotp-ele.c was intended to be extended later to implement
>(1) and (2) deciding on a per-fuse-register basis which of both access methods
>should be used.
>
>This has some downsides:
>
>* the driver gets convoluted and complex
>* the driver decides which OTP registers are accessed in which way and therefore
> mixes read-only and read/write access
>
>Therefore I implemented a simple driver that uses the ELE S400 API only, as the
>FSB access (1) doesn't provide any benefits except for that it doesn't depend
>on the ELE firmware being available. This is used by us downstream.
>
>For the upstream solution I would like to have some feedback on how to move
>on:
>
>1. switch imx-ocotp-ele.c to use ELE API exclusively
> -> this will create a hard dependency on the ELE firmware/driver being available
>2. extend imx-ocotp-ele.c to use FSB and ELE API
> -> make the driver use ELE API for all registers if ELE firmware/driver is available
>3. create separate drivers as done in this RFC
Need to confirm ELE APIs supports all fuses. If yes, switching to using ELE API
exclusively should be ok, no need to mix FSB and ELE API. And drop the current
FSB usage
Thanks,
Peng.
>
>Thanks!
>
>[1] https://patchwork.kernel.org/project/linux-arm-kernel/cover/20250409-imx-se-if-v16-0-5394e5f3417e@nxp.com/
>
>Frieder Schrempf (5):
> firmware: imx: ele: Add API functions for OCOTP fuse access
> nvmem: Add i.MX OCOTP fuse driver using ELE S400 API
> arm64: dts: imx93: Add node for EdgeLock Enclave (ELE) firmware driver
> arm64: dts: imx93: Add node for OCOTP S400 NVMEM driver
> arm64: dts: imx93-kontron: Add DMA memory region for ELE firmware
>
> .../dts/freescale/imx93-kontron-osm-s.dtsi | 16 ++
> arch/arm64/boot/dts/freescale/imx93.dtsi | 11 +
> drivers/firmware/imx/ele_base_msg.c | 122 +++++++++++
> drivers/firmware/imx/ele_base_msg.h | 8 +
> drivers/nvmem/Kconfig | 11 +
> drivers/nvmem/Makefile | 2 +
> drivers/nvmem/imx-ocotp-s400.c | 195 ++++++++++++++++++
> include/linux/firmware/imx/se_api.h | 3 +
> 8 files changed, 368 insertions(+)
> create mode 100644 drivers/nvmem/imx-ocotp-s400.c
>
>--
>2.49.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE
2025-04-22 6:30 ` [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Peng Fan
@ 2025-04-22 7:33 ` Frieder Schrempf
0 siblings, 0 replies; 10+ messages in thread
From: Frieder Schrempf @ 2025-04-22 7:33 UTC (permalink / raw)
To: Peng Fan, Frieder Schrempf
Cc: Peng Fan, Pankaj Gupta, linux-arm-kernel, Conor Dooley,
devicetree, imx, Krzysztof Kozlowski, linux-kernel, Rob Herring,
Sascha Hauer, Shawn Guo, Srinivas Kandagatla, Arnd Bergmann,
Fabio Estevam, Frank Li, Geert Uytterhoeven, Greg Kroah-Hartman,
Pengutronix Kernel Team, Rafał Miłecki, Shengjiu Wang,
Shenwei Wang, Xu Yang, Yoshihiro Shimoda
Hi Peng,
Am 22.04.25 um 08:30 schrieb Peng Fan:
> Hi Frieder,
>
> On Wed, Apr 16, 2025 at 04:26:19PM +0200, Frieder Schrempf wrote:
>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>>
>> This depends on [1] for the support of the Edgelock Secure Enclave firmware
>> driver.
>>
>> There are at least two ways to access the OTP fuses on i.MX93:
>>
>> (1) through the FSB (fuseblock) registers
>> (2) through the ELE S400 API
>>
>> There currently is a NVMEM driver imx-ocotp-ele.c that (despite its name)
>> implements (1). As the FSB only provides limited access to the OTP registers
>> (read only) it's not sufficient for all use-cases.
>>
>> It seems like imx-ocotp-ele.c was intended to be extended later to implement
>> (1) and (2) deciding on a per-fuse-register basis which of both access methods
>> should be used.
>>
>> This has some downsides:
>>
>> * the driver gets convoluted and complex
>> * the driver decides which OTP registers are accessed in which way and therefore
>> mixes read-only and read/write access
>>
>> Therefore I implemented a simple driver that uses the ELE S400 API only, as the
>> FSB access (1) doesn't provide any benefits except for that it doesn't depend
>> on the ELE firmware being available. This is used by us downstream.
>>
>> For the upstream solution I would like to have some feedback on how to move
>> on:
>>
>> 1. switch imx-ocotp-ele.c to use ELE API exclusively
>> -> this will create a hard dependency on the ELE firmware/driver being available
>> 2. extend imx-ocotp-ele.c to use FSB and ELE API
>> -> make the driver use ELE API for all registers if ELE firmware/driver is available
>> 3. create separate drivers as done in this RFC
>
> Need to confirm ELE APIs supports all fuses. If yes, switching to using ELE API
> exclusively should be ok, no need to mix FSB and ELE API. And drop the current
> FSB usage
Ok, I already compared what fuse registers I can access via FSB and ELE.
The ELE seems to cover all registers that are available via FSB so that
shouldn't be a problem.
Still, after thinking a bit more about it, option 2 above seems like the
best way to go to me.
In case someone wants to use the system without the proprietary ELE
firmware, I'd like them to not run into the obstacle of loosing read
access to the OTPs. Especially as the Ethernet driver expects the NVMEM
cells for the MAC address to be available.
I know that the ELE firmware is currently somewhat mandatory as the
bootloader uses it, but I guess it would be possible and for some people
also desirable to have a system without it.
So what I would like to have is an optional DT property for the
imx-ocotp-ele.c driver to point to the secure enclave node. If the ELE
device is available at probe time, make the driver use the ELE API
exclusively. If not, fall back to the FSB API with read-only access.
If someone wants to avoid the ELE API altogether for whatever reason,
they could remove the link to the secure enclave node in their board DT.
Thanks
Frieder
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE
2025-04-16 14:26 [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Frieder Schrempf
` (5 preceding siblings ...)
2025-04-22 6:30 ` [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE Peng Fan
@ 2025-04-22 6:40 ` Arnd Bergmann
2025-04-22 7:37 ` Frieder Schrempf
6 siblings, 1 reply; 10+ messages in thread
From: Arnd Bergmann @ 2025-04-22 6:40 UTC (permalink / raw)
To: Frieder Schrempf, Peng Fan, Pankaj Gupta, linux-arm-kernel,
Conor Dooley, devicetree, imx, Krzysztof Kozlowski, linux-kernel,
Rob Herring, Sascha Hauer, Shawn Guo, Srinivas Kandagatla
Cc: Frieder Schrempf, Fabio Estevam, Frank Li, Geert Uytterhoeven,
Greg Kroah-Hartman, Pengutronix Kernel Team,
Rafał Miłecki, Shengjiu Wang, Shenwei Wang, Xu Yang,
Yoshihiro Shimoda
On Wed, Apr 16, 2025, at 16:26, Frieder Schrempf wrote:
> Therefore I implemented a simple driver that uses the ELE S400 API only, as the
> FSB access (1) doesn't provide any benefits except for that it doesn't depend
> on the ELE firmware being available. This is used by us downstream.
>
> For the upstream solution I would like to have some feedback on how to move
> on:
>
> 1. switch imx-ocotp-ele.c to use ELE API exclusively
> -> this will create a hard dependency on the ELE firmware/driver
> being available
Could this cause problems for real-time Linux users? Usually going
through a firmware driver adds more latency than doing the thing
from Linux directly, and the firmware is usually not preemptable.
In particular, programming a one-time fuse is likely a slow
operation in hardware, so it may still be necessary to support
both methods if there are users that need to update the fuses
on real-time systems.
Arnd
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [RFC PATCH 0/5] Add NVMEM driver for i.MX93 OTP access through ELE
2025-04-22 6:40 ` Arnd Bergmann
@ 2025-04-22 7:37 ` Frieder Schrempf
0 siblings, 0 replies; 10+ messages in thread
From: Frieder Schrempf @ 2025-04-22 7:37 UTC (permalink / raw)
To: Arnd Bergmann, Frieder Schrempf, Peng Fan, Pankaj Gupta,
linux-arm-kernel, Conor Dooley, devicetree, imx,
Krzysztof Kozlowski, linux-kernel, Rob Herring, Sascha Hauer,
Shawn Guo, Srinivas Kandagatla
Cc: Fabio Estevam, Frank Li, Geert Uytterhoeven, Greg Kroah-Hartman,
Pengutronix Kernel Team, Rafał Miłecki, Shengjiu Wang,
Shenwei Wang, Xu Yang, Yoshihiro Shimoda
Am 22.04.25 um 08:40 schrieb Arnd Bergmann:
> On Wed, Apr 16, 2025, at 16:26, Frieder Schrempf wrote:
>
>> Therefore I implemented a simple driver that uses the ELE S400 API only, as the
>> FSB access (1) doesn't provide any benefits except for that it doesn't depend
>> on the ELE firmware being available. This is used by us downstream.
>>
>> For the upstream solution I would like to have some feedback on how to move
>> on:
>>
>> 1. switch imx-ocotp-ele.c to use ELE API exclusively
>> -> this will create a hard dependency on the ELE firmware/driver
>> being available
>
> Could this cause problems for real-time Linux users? Usually going
> through a firmware driver adds more latency than doing the thing
> from Linux directly, and the firmware is usually not preemptable.
>
> In particular, programming a one-time fuse is likely a slow
> operation in hardware, so it may still be necessary to support
> both methods if there are users that need to update the fuses
> on real-time systems.
Hm, interesting thought. I can't really tell if that could end up being
a real problem, but it might just be another good argument for
supporting both methods, yes.
^ permalink raw reply [flat|nested] 10+ messages in thread