public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
From: Kuan-Wei Chiu <visitorckw@gmail.com>
To: andrew@codeconstruct.com.au, avifishman70@gmail.com,
	tmaimon77@gmail.com, tali.perry1@gmail.com, srini@kernel.org,
	robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org
Cc: venture@google.com, yuenn@google.com, benjaminfair@google.com,
	jserv@ccns.ncku.edu.tw, eleanor15x@gmail.com,
	linux-arm-kernel@lists.infradead.org, openbmc@lists.ozlabs.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	Kuan-Wei Chiu <visitorckw@gmail.com>
Subject: [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver
Date: Wed, 18 Mar 2026 19:35:37 +0000	[thread overview]
Message-ID: <20260318193538.246853-3-visitorckw@gmail.com> (raw)
In-Reply-To: <20260318193538.246853-1-visitorckw@gmail.com>

Add a new NVMEM driver for the OTP memory controllers found on Nuvoton
NPCM SoCs.

This OTP is read-only and manages two independent arrays: Key Storage
and Fuse Array, which contain cryptographic keys, hardware strapping,
and calibration data.

Each array provides 1024 bytes of storage.

It can be accessed by writing the target address and a read command
to the control registers, and then polling a status register until
the data is ready. Concurrent accesses are protected by a mutex.

Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
---
 MAINTAINERS              |   7 +++
 drivers/nvmem/Kconfig    |  10 +++
 drivers/nvmem/Makefile   |   2 +
 drivers/nvmem/npcm-otp.c | 129 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 148 insertions(+)
 create mode 100644 drivers/nvmem/npcm-otp.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 61bf550fd37c..e391e2bcb5f6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18894,6 +18894,13 @@ F:	drivers/nubus/
 F:	include/linux/nubus.h
 F:	include/uapi/linux/nubus.h
 
+NUVOTON NPCM OTP NVMEM DRIVER
+M:	Kuan-Wei Chiu <visitorckw@gmail.com>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	Documentation/devicetree/bindings/nvmem/nuvoton,npcm750-otp.yaml
+F:	drivers/nvmem/npcm-otp.c
+
 NUVOTON NCT6694 MFD DRIVER
 M:	Ming Yu <tmyu0@nuvoton.com>
 S:	Supported
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 74ddbd0f79b0..5d065b7448ff 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -483,4 +483,14 @@ config NVMEM_QORIQ_EFUSE
 	  This driver can also be built as a module. If so, the module
 	  will be called nvmem_qoriq_efuse.
 
+config NVMEM_NPCM_OTP
+	tristate "Nuvoton NPCM7xx OTP Controller"
+	depends on ARCH_NPCM || COMPILE_TEST
+	help
+	  This option enables support for the OTP (One-Time Programmable)
+	  controller found on Nuvoton NPCM7xx BMCs.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called npcm-otp.
+
 endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 7252b8ec88d4..63c23b304d64 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -95,3 +95,5 @@ obj-$(CONFIG_NVMEM_ZYNQMP)		+= nvmem_zynqmp_nvmem.o
 nvmem_zynqmp_nvmem-y			:= zynqmp_nvmem.o
 obj-$(CONFIG_NVMEM_QORIQ_EFUSE)		+= nvmem-qoriq-efuse.o
 nvmem-qoriq-efuse-y			:= qoriq-efuse.o
+obj-$(CONFIG_NVMEM_NPCM_OTP)		+= nvmem-npcm-otp.o
+nvmem-npcm-otp-y			:= npcm-otp.o
diff --git a/drivers/nvmem/npcm-otp.c b/drivers/nvmem/npcm-otp.c
new file mode 100644
index 000000000000..abe4bab66c06
--- /dev/null
+++ b/drivers/nvmem/npcm-otp.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Nuvoton NPCM7xx OTP (One-Time Programmable) NVMEM driver
+ *
+ * Copyright (C) 2026 Kuan-Wei Chiu <visitorckw@gmail.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+/* Register offsets and bitmasks */
+#define NPCM_OTP_FST		0x00
+#define NPCM_OTP_FADDR		0x04
+#define NPCM_OTP_FDATA		0x08
+#define NPCM_OTP_FCTL		0x14
+
+#define FST_RDY			BIT(0)
+#define FST_RDST		BIT(1)
+#define FCTL_READ_CMD		0x02
+
+/* OTP total capacity is 8192 bits (1024 Bytes) */
+#define NPCM_OTP_SIZE		1024
+
+struct npcm_otp {
+	void __iomem *base;
+	struct mutex lock; /* protects concurrent OTP accesses */
+};
+
+static int npcm_otp_read_byte(struct npcm_otp *otp, unsigned int offset, u8 *val)
+{
+	u32 fst;
+	int ret;
+
+	writel(offset, otp->base + NPCM_OTP_FADDR);
+	writel(FCTL_READ_CMD, otp->base + NPCM_OTP_FCTL);
+
+	ret = readl_poll_timeout(otp->base + NPCM_OTP_FST, fst,
+				 (fst & FST_RDY), 10, 10000);
+	if (ret)
+		return ret;
+
+	*val = (u8)(readl(otp->base + NPCM_OTP_FDATA) & 0xFF);
+
+	/* Clear the status bit to prepare for the next read */
+	writel(FST_RDST, otp->base + NPCM_OTP_FST);
+
+	return 0;
+}
+
+static int npcm_otp_read(void *context, unsigned int offset,
+			 void *val, size_t bytes)
+{
+	struct npcm_otp *otp = context;
+	u8 *buf = val;
+	int ret = 0;
+	size_t i;
+
+	mutex_lock(&otp->lock);
+
+	for (i = 0; i < bytes; i++) {
+		ret = npcm_otp_read_byte(otp, offset + i, &buf[i]);
+		if (ret)
+			break;
+	}
+
+	mutex_unlock(&otp->lock);
+
+	return ret;
+}
+
+static int npcm_otp_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct npcm_otp *otp;
+	struct nvmem_config config = { 0 };
+	struct nvmem_device *nvmem;
+
+	otp = devm_kzalloc(dev, sizeof(*otp), GFP_KERNEL);
+	if (!otp)
+		return -ENOMEM;
+
+	otp->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(otp->base))
+		return PTR_ERR(otp->base);
+
+	mutex_init(&otp->lock);
+
+	config.dev = dev;
+	config.name = dev_name(dev);
+	config.read_only = true;
+	config.word_size = 1;
+	config.stride = 1;
+	config.reg_read = npcm_otp_read;
+	config.priv = otp;
+	config.size = NPCM_OTP_SIZE;
+
+	nvmem = devm_nvmem_register(dev, &config);
+	if (IS_ERR(nvmem))
+		return dev_err_probe(dev, PTR_ERR(nvmem), "Failed to register nvmem\n");
+
+	return 0;
+}
+
+static const struct of_device_id npcm_otp_dt_ids[] = {
+	{ .compatible = "nuvoton,npcm750-key-storage" },
+	{ .compatible = "nuvoton,npcm750-fuse-array" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, npcm_otp_dt_ids);
+
+static struct platform_driver npcm_otp_driver = {
+	.probe		= npcm_otp_probe,
+	.driver		= {
+		.name	= "npcm-otp",
+		.of_match_table = npcm_otp_dt_ids,
+	},
+};
+module_platform_driver(npcm_otp_driver);
+
+MODULE_AUTHOR("Kuan-Wei Chiu <visitorckw@gmail.com>");
+MODULE_DESCRIPTION("Nuvoton NPCM7xx OTP NVMEM driver");
+MODULE_LICENSE("GPL");
-- 
2.53.0.851.ga537e3e6e9-goog



  parent reply	other threads:[~2026-03-18 19:37 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-18 19:35 [PATCH 0/3] nvmem: Add Nuvoton NPCM OTP driver Kuan-Wei Chiu
2026-03-18 19:35 ` [PATCH 1/3] dt-bindings: nvmem: add nuvoton,npcm750-otp Kuan-Wei Chiu
2026-03-18 20:17   ` Krzysztof Kozlowski
2026-03-18 20:24     ` Kuan-Wei Chiu
2026-03-18 19:35 ` Kuan-Wei Chiu [this message]
2026-03-19 10:57   ` [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver Tomer Maimon
2026-03-19 16:17     ` Kuan-Wei Chiu
2026-03-18 19:35 ` [PATCH 3/3] ARM: dts: nuvoton: Add OTP nodes for NPCM7xx Kuan-Wei Chiu

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=20260318193538.246853-3-visitorckw@gmail.com \
    --to=visitorckw@gmail.com \
    --cc=andrew@codeconstruct.com.au \
    --cc=avifishman70@gmail.com \
    --cc=benjaminfair@google.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=eleanor15x@gmail.com \
    --cc=jserv@ccns.ncku.edu.tw \
    --cc=krzk+dt@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=openbmc@lists.ozlabs.org \
    --cc=robh@kernel.org \
    --cc=srini@kernel.org \
    --cc=tali.perry1@gmail.com \
    --cc=tmaimon77@gmail.com \
    --cc=venture@google.com \
    --cc=yuenn@google.com \
    /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