* [PATCH 2/5] ARM: i.MX: ele: add function comments
2024-03-11 10:21 [PATCH 1/5] ARM: i.MX: ele: move ELE_READ_SHADOW_REQ definition Sascha Hauer
@ 2024-03-11 10:21 ` Sascha Hauer
2024-03-11 10:21 ` [PATCH 3/5] ARM: i.MX: ele: add ele_write_shadow_fuse Sascha Hauer
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2024-03-11 10:21 UTC (permalink / raw)
To: Barebox List
i.MX fuse numbers are sometimes referred to as the index of the 32bit
word, sometimes as bit offsets and the device in /dev/imx_ocotp counts
in bytes. To avoid more confusion add some comments to the function
headers of functions reading/writing the fuses that clearly state that
they take the 32bit word number as input.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-imx/ele.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/arch/arm/mach-imx/ele.c b/arch/arm/mach-imx/ele.c
index 095eaec8f6..ce5ad287d8 100644
--- a/arch/arm/mach-imx/ele.c
+++ b/arch/arm/mach-imx/ele.c
@@ -207,6 +207,16 @@ int imx93_ele_load_fw(void *bl33)
return 0;
}
+/*
+ * ele_read_common_fuse - read a fuse
+ * @fuse_id: The fuse to read (in 32bit word number)
+ * fuse_word: The value read from the fuse
+ * @response: on return contains the response from ELE
+ *
+ * This reads the shadow value of the fuse @fuse_id.
+ *
+ * Return: 0 when the ELE call succeeds, negative error code otherwise
+ */
int ele_read_common_fuse(u16 fuse_id, u32 *fuse_word, u32 *response)
{
struct ele_msg msg;
@@ -228,6 +238,16 @@ int ele_read_common_fuse(u16 fuse_id, u32 *fuse_word, u32 *response)
return ret;
}
+/*
+ * ele_read_shadow_fuse - read a fuse
+ * @fuse_id: The fuse to read (in 32bit word number)
+ * fuse_word: The value read from the fuse
+ * @response: on return contains the response from ELE
+ *
+ * This reads the shadow value of the fuse @fuse_id.
+ *
+ * Return: 0 when the ELE call succeeds, negative error code otherwise
+ */
int ele_read_shadow_fuse(u16 fuse_id, u32 *fuse_word, u32 *response)
{
struct ele_msg msg;
@@ -251,7 +271,7 @@ int ele_read_shadow_fuse(u16 fuse_id, u32 *fuse_word, u32 *response)
/*
* ele_write_fuse - write a fuse
- * @fuse_id: The fuse to write to
+ * @fuse_id: The fuse to write to (in 32bit word number)
* @fuse_val: The value to write to the fuse
* @lock: lock fuse after writing
* @response: on return contains the response from ELE
--
2.39.2
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/5] ARM: i.MX: ele: add ele_write_shadow_fuse
2024-03-11 10:21 [PATCH 1/5] ARM: i.MX: ele: move ELE_READ_SHADOW_REQ definition Sascha Hauer
2024-03-11 10:21 ` [PATCH 2/5] ARM: i.MX: ele: add function comments Sascha Hauer
@ 2024-03-11 10:21 ` Sascha Hauer
2024-03-11 10:21 ` [PATCH 4/5] nvmem: add nvmem_device_get_device() Sascha Hauer
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2024-03-11 10:21 UTC (permalink / raw)
To: Barebox List
The ocotp fuses have shadow values. For some fuses the shadow values
can be read from and written to. While it's not really clear where
the ROM really uses these shadow values, it still helps reading and
writing them to get an idea if we are about to write the correct
fuses before we finally enable permanent write.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
arch/arm/mach-imx/ele.c | 33 +++++++++++++++++++++++++++++++++
include/mach/imx/ele.h | 2 ++
2 files changed, 35 insertions(+)
diff --git a/arch/arm/mach-imx/ele.c b/arch/arm/mach-imx/ele.c
index ce5ad287d8..58cffad797 100644
--- a/arch/arm/mach-imx/ele.c
+++ b/arch/arm/mach-imx/ele.c
@@ -305,6 +305,39 @@ int ele_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response)
return ret;
}
+/*
+ * ele_write_shadow_fuse - write a fuse
+ * @fuse_id: The fuse to write to
+ * @fuse_val: The value to write to the fuse
+ * @lock: lock fuse after writing
+ * @response: on return contains the response from ELE
+ *
+ * This writes the 32bit given in @fuse_val to the fuses at @fuse_id. This is
+ * a permanent change, be careful.
+ *
+ * Return: 0 when the ELE call succeeds, negative error code otherwise
+ */
+int ele_write_shadow_fuse(u16 fuse_id, u32 fuse_val, u32 *response)
+{
+ struct ele_msg msg;
+ int ret;
+
+ msg.version = ELE_VERSION;
+ msg.tag = ELE_CMD_TAG;
+ msg.size = 3;
+ msg.command = ELE_WRITE_SHADOW_REQ;
+ msg.data[0] = fuse_id;
+
+ msg.data[1] = fuse_val;
+
+ ret = imx9_s3mua_call(&msg);
+
+ if (response)
+ *response = msg.data[0];
+
+ return ret;
+}
+
/*
* ele_forward_lifecycle - forward lifecycle
* @lc: The lifecycle value to forward to
diff --git a/include/mach/imx/ele.h b/include/mach/imx/ele.h
index da4b0aa50d..7ba8afde20 100644
--- a/include/mach/imx/ele.h
+++ b/include/mach/imx/ele.h
@@ -45,6 +45,7 @@
#define ELE_ATTEST_REQ (0xDB)
#define ELE_RELEASE_PATCH_REQ (0xDC)
#define ELE_OTP_SEQ_SWITH_REQ (0xDD)
+#define ELE_WRITE_SHADOW_REQ (0xF2)
#define ELE_READ_SHADOW_REQ (0xF3)
/* ELE failure indications */
@@ -152,6 +153,7 @@ int ele_call(struct ele_msg *msg);
int ele_read_common_fuse(u16 fuse_id, u32 *fuse_word, u32 *response);
int ele_release_rdc(u8 core_id, u8 xrdc, u32 *response);
int ele_read_shadow_fuse(u16 fuse_id, u32 *fuse_word, u32 *response);
+int ele_write_shadow_fuse(u16 fuse_id, u32 fuse_val, u32 *response);
int ele_get_info(struct ele_get_info_data *info);
int ele_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response);
int ele_authenticate_container(unsigned long addr, u32 *response);
--
2.39.2
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 4/5] nvmem: add nvmem_device_get_device()
2024-03-11 10:21 [PATCH 1/5] ARM: i.MX: ele: move ELE_READ_SHADOW_REQ definition Sascha Hauer
2024-03-11 10:21 ` [PATCH 2/5] ARM: i.MX: ele: add function comments Sascha Hauer
2024-03-11 10:21 ` [PATCH 3/5] ARM: i.MX: ele: add ele_write_shadow_fuse Sascha Hauer
@ 2024-03-11 10:21 ` Sascha Hauer
2024-03-11 10:21 ` [PATCH 5/5] nvmem: imx-ocotp-ele: implement permanent write support Sascha Hauer
2024-03-13 7:42 ` [PATCH 1/5] ARM: i.MX: ele: move ELE_READ_SHADOW_REQ definition Sascha Hauer
4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2024-03-11 10:21 UTC (permalink / raw)
To: Barebox List
We'll want to add a device parameter to the imx_ocotp0 device in the
next step, but the device is private to the nvmem core. Add a getter
function for it.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/nvmem/core.c | 6 ++++++
include/linux/nvmem-provider.h | 5 +++++
2 files changed, 11 insertions(+)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index 67bb1d7993..ad145a4242 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -858,3 +858,9 @@ int nvmem_cell_read_variable_le_u32(struct device *dev, const char *cell_id,
return 0;
}
EXPORT_SYMBOL_GPL(nvmem_cell_read_variable_le_u32);
+
+struct device *nvmem_device_get_device(struct nvmem_device *nvmem)
+{
+ return &nvmem->dev;
+}
+EXPORT_SYMBOL_GPL(nvmem_device_get_device);
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
index 3c30e18409..b3b4372d30 100644
--- a/include/linux/nvmem-provider.h
+++ b/include/linux/nvmem-provider.h
@@ -48,6 +48,7 @@ struct nvmem_device *nvmem_regmap_register(struct regmap *regmap, const char *na
struct nvmem_device *nvmem_regmap_register_with_pp(struct regmap *regmap,
const char *name, nvmem_cell_post_process_t cell_post_process);
struct nvmem_device *nvmem_partition_register(struct cdev *cdev);
+struct device *nvmem_device_get_device(struct nvmem_device *nvmem);
#else
@@ -73,5 +74,9 @@ static inline struct nvmem_device *nvmem_partition_register(struct cdev *cdev)
return ERR_PTR(-ENOSYS);
}
+static struct device *nvmem_device_get_device(struct nvmem_device *nvmem)
+{
+ return ERR_PTR(-ENOSYS);
+}
#endif /* CONFIG_NVMEM */
#endif /* ifndef _LINUX_NVMEM_PROVIDER_H */
--
2.39.2
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 5/5] nvmem: imx-ocotp-ele: implement permanent write support
2024-03-11 10:21 [PATCH 1/5] ARM: i.MX: ele: move ELE_READ_SHADOW_REQ definition Sascha Hauer
` (2 preceding siblings ...)
2024-03-11 10:21 ` [PATCH 4/5] nvmem: add nvmem_device_get_device() Sascha Hauer
@ 2024-03-11 10:21 ` Sascha Hauer
2024-03-13 7:42 ` [PATCH 1/5] ARM: i.MX: ele: move ELE_READ_SHADOW_REQ definition Sascha Hauer
4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2024-03-11 10:21 UTC (permalink / raw)
To: Barebox List
This implements write support to imx-ocotp-ele. By default only the
shadow values are written which is harmless and nearly useless (as the
ROM doesn't seem use these values). Real write support is enabled by
setting imx_ocotp0.permanent_write_enable to true. A big warning is
printed and the next write access to /dev/imx_ocotp will then really
burn fuses.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/nvmem/imx-ocotp-ele.c | 36 ++++++++++++++++++++++++++++++++++-
1 file changed, 35 insertions(+), 1 deletion(-)
diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
index 9708d3f4bb..b25ab32fea 100644
--- a/drivers/nvmem/imx-ocotp-ele.c
+++ b/drivers/nvmem/imx-ocotp-ele.c
@@ -41,6 +41,7 @@ struct imx_ocotp_priv {
void __iomem *base;
const struct ocotp_devtype_data *data;
struct regmap_config map_config;
+ int permanent_write_enable;
};
static enum fuse_type imx_ocotp_fuse_type(struct imx_ocotp_priv *priv, u32 index)
@@ -92,6 +93,22 @@ static int imx_ocotp_reg_read(void *context, unsigned int offset, unsigned int *
return 0;
};
+static int imx_ocotp_reg_write(void *context, unsigned int offset, unsigned int val)
+{
+ struct imx_ocotp_priv *priv = context;
+ u32 index;
+ int ret;
+
+ index = offset >> 2;
+
+ if (priv->permanent_write_enable)
+ ret = ele_write_fuse(index, val, false, NULL);
+ else
+ ret = ele_write_shadow_fuse(index, val, NULL);
+
+ return ret;
+}
+
static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int offset,
void *data, size_t bytes)
{
@@ -116,6 +133,7 @@ static int imx_ocotp_cell_pp(void *context, const char *id, unsigned int offset,
}
static struct regmap_bus imx_ocotp_regmap_bus = {
+ .reg_write = imx_ocotp_reg_write,
.reg_read = imx_ocotp_reg_read,
};
@@ -132,6 +150,18 @@ static void imx_ocotp_set_unique_machine_id(struct imx_ocotp_priv *priv)
machine_id_set_hashable(unique_id_parts, sizeof(unique_id_parts));
}
+static int permanent_write_enable_set(struct param_d *param, void *ctx)
+{
+ struct imx_ocotp_priv *priv = ctx;
+
+ if (priv->permanent_write_enable) {
+ dev_warn(priv->dev, "Enabling permanent write on fuses.\n");
+ dev_warn(priv->dev, "Writing fuses may damage your device. Be careful!\n");
+ }
+
+ return 0;
+}
+
static int imx_ele_ocotp_probe(struct device *dev)
{
struct imx_ocotp_priv *priv;
@@ -141,6 +171,7 @@ static int imx_ele_ocotp_probe(struct device *dev)
int ret;
priv = xzalloc(sizeof(*priv));
+ priv->dev = dev;
ret = dev_get_drvdata(dev, (const void **)&data);
if (ret)
@@ -165,11 +196,14 @@ static int imx_ele_ocotp_probe(struct device *dev)
if (IS_ENABLED(CONFIG_MACHINE_ID))
imx_ocotp_set_unique_machine_id(priv);
- nvmem = nvmem_regmap_register_with_pp(priv->map, "imx-ocotp",
+ nvmem = nvmem_regmap_register_with_pp(priv->map, "imx_ocotp",
imx_ocotp_cell_pp);
if (IS_ERR(nvmem))
return PTR_ERR(nvmem);
+ dev_add_param_bool(nvmem_device_get_device(nvmem), "permanent_write_enable",
+ permanent_write_enable_set, NULL, &priv->permanent_write_enable, priv);
+
return 0;
}
--
2.39.2
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/5] ARM: i.MX: ele: move ELE_READ_SHADOW_REQ definition
2024-03-11 10:21 [PATCH 1/5] ARM: i.MX: ele: move ELE_READ_SHADOW_REQ definition Sascha Hauer
` (3 preceding siblings ...)
2024-03-11 10:21 ` [PATCH 5/5] nvmem: imx-ocotp-ele: implement permanent write support Sascha Hauer
@ 2024-03-13 7:42 ` Sascha Hauer
4 siblings, 0 replies; 6+ messages in thread
From: Sascha Hauer @ 2024-03-13 7:42 UTC (permalink / raw)
To: Barebox List, Sascha Hauer
On Mon, 11 Mar 2024 11:21:48 +0100, Sascha Hauer wrote:
> The ELE request defines are in include/mach/imx/ele.h, move definition
> of ELE_READ_SHADOW_REQ there as well.
>
>
Applied, thanks!
[1/5] ARM: i.MX: ele: move ELE_READ_SHADOW_REQ definition
https://git.pengutronix.de/cgit/barebox/commit/?id=2ec5d544549e (link may not be stable)
[2/5] ARM: i.MX: ele: add function comments
https://git.pengutronix.de/cgit/barebox/commit/?id=f95b4906c0f7 (link may not be stable)
[3/5] ARM: i.MX: ele: add ele_write_shadow_fuse
https://git.pengutronix.de/cgit/barebox/commit/?id=2554f8daa381 (link may not be stable)
[4/5] nvmem: add nvmem_device_get_device()
https://git.pengutronix.de/cgit/barebox/commit/?id=50c4a22e1232 (link may not be stable)
[5/5] nvmem: imx-ocotp-ele: implement permanent write support
https://git.pengutronix.de/cgit/barebox/commit/?id=9b799d058e46 (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 6+ messages in thread