mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: Barebox List <barebox@lists.infradead.org>
Subject: [PATCH] nvmem: am62l: add fuse support
Date: Fri, 21 Nov 2025 15:46:01 +0100	[thread overview]
Message-ID: <20251121144601.3183308-1-s.hauer@pengutronix.de> (raw)

This driver reads/writes to the extended OTP area using TF-A call using
TF-A calls.
So far only the AM62l is supported, but this should work on other K3
SoCs as well..
So far only the AM62l is supported, but this should work on other K3
SoCs as well.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/dts/k3-am62l-barebox.dtsi |   4 ++
 drivers/nvmem/Kconfig              |   6 ++
 drivers/nvmem/Makefile             |   1 +
 drivers/nvmem/k3-fuse.c            | 112 +++++++++++++++++++++++++++++
 4 files changed, 123 insertions(+)
 create mode 100644 drivers/nvmem/k3-fuse.c

diff --git a/arch/arm/dts/k3-am62l-barebox.dtsi b/arch/arm/dts/k3-am62l-barebox.dtsi
index 2c1cbb3871..949e2746d5 100644
--- a/arch/arm/dts/k3-am62l-barebox.dtsi
+++ b/arch/arm/dts/k3-am62l-barebox.dtsi
@@ -64,4 +64,8 @@ secure_ddr: optee@80200000 {
 			no-map;
 		};
 	};
+
+	otp: otp {
+		compatible = "ti,am62l-otp";
+	};
 };
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 49f90452df..7b78f53909 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -136,4 +136,10 @@ config NVMEM_ATMEL_I2C
 	bool
 	select BITREVERSE
 
+config TI_K3_OTP
+	bool "TI K3 OTP"
+	depends on ARCH_K3
+	help
+	  This adds support for the TI K3 SMC call based OTP found on AM62L SoCs.
+
 endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 9cdc669a96..cb5e6d6330 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -36,3 +36,4 @@ obj-$(CONFIG_STARFIVE_OTP)	+= starfive-otp.o
 obj-$(CONFIG_IMX_OCOTP_ELE)	+= imx-ocotp-ele.o
 obj-$(CONFIG_NVMEM_ATMEL_I2C)	+= atmel-i2c.o
 obj-$(CONFIG_NVMEM_ATMEL_SHA204A) += atmel-sha204a.o
+obj-$(CONFIG_TI_K3_OTP)		+= k3-fuse.o
diff --git a/drivers/nvmem/k3-fuse.c b/drivers/nvmem/k3-fuse.c
new file mode 100644
index 0000000000..60d5706b1c
--- /dev/null
+++ b/drivers/nvmem/k3-fuse.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <driver.h>
+#include <malloc.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <linux/regmap.h>
+#include <linux/nvmem-provider.h>
+#include <linux/arm-smccc.h>
+
+#define K3_SIP_OTP_READ		0xC2000002
+#define K3_SIP_OTP_WRITE	0xC2000001
+
+struct ti_k3_otp {
+	struct device *dev;
+};
+
+/*
+ * offset and size are assumed aligned to the size of the fuses (32-bit).
+ */
+static int ti_k3_otp_read(void *ctx, unsigned int offset, unsigned int *val)
+{
+	struct arm_smccc_res res;
+	unsigned int bank = 0;
+	unsigned int word = offset >> 2;
+
+	/* TF-A ignores bank argument */
+	arm_smccc_smc(K3_SIP_OTP_READ, bank, word,
+		      0, 0, 0, 0, 0, &res);
+
+	if (res.a0 != 0) {
+		*val = 0xdeadbeef;
+		return 0;
+	}
+
+	*val = res.a1;
+
+	return 0;
+}
+
+static int ti_k3_otp_write(void *ctx, unsigned int offset, unsigned int val)
+{
+	struct ti_k3_otp *priv = ctx;
+	struct arm_smccc_res res;
+	unsigned int bank = 0;
+	unsigned int word = offset >> 2;
+	unsigned int mask = val;
+
+	/*
+	 * At least on AM62L there is an inconsistency between reading and writing
+	 * fuse bits, see
+	 * https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1590396/am62l-am62l-extended-otp
+	 * Until this is resolved we only allow to write the first 24 bits of word 0
+	 */
+	if (word != 0 || (val & GENMASK(31, 25))) {
+		dev_err(priv->dev, "Tried to write non supported word/bit");
+		return -EINVAL;
+	}
+
+	arm_smccc_smc(K3_SIP_OTP_WRITE, bank, word,
+		      val, mask, 0, 0, 0, &res);
+
+	if (res.a0 != 0) {
+		dev_err(priv->dev, "Writing fuse 0x%08x failed with: %u\n", res.a0);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static struct regmap_bus ti_k3_otp_regmap_bus = {
+	.reg_read = ti_k3_otp_read,
+	.reg_write = ti_k3_otp_write,
+};
+
+static int ti_k3_otp_probe(struct device *dev)
+{
+	struct ti_k3_otp *priv;
+	struct regmap_config config = {};
+	struct regmap *map;
+
+	config.name = "k3-otp";
+	config.reg_bits = 32;
+	config.val_bits = 32;
+	config.reg_stride = 4;
+	config.max_register = 127;
+
+	priv = xzalloc(sizeof(*priv));
+	priv->dev = dev;
+
+	map = regmap_init(dev, &ti_k3_otp_regmap_bus, priv, &config);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+
+	return PTR_ERR_OR_ZERO(nvmem_regmap_register(map, "ti-k3-otp"));
+}
+
+static struct of_device_id ti_k3_otp_dt_ids[] = {
+	{ .compatible = "ti,am62l-otp" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ti_k3_otp_dt_ids);
+
+static struct driver ti_k3_otp_driver = {
+	.name	= "ti-k3-otp",
+	.probe	= ti_k3_otp_probe,
+	.of_compatible = ti_k3_otp_dt_ids,
+};
+device_platform_driver(ti_k3_otp_driver);
-- 
2.47.3




                 reply	other threads:[~2025-11-21 14:46 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251121144601.3183308-1-s.hauer@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox