public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] nvmem: Add Nuvoton NPCM OTP driver
@ 2026-03-18 19:35 Kuan-Wei Chiu
  2026-03-18 19:35 ` [PATCH 1/3] dt-bindings: nvmem: add nuvoton,npcm750-otp Kuan-Wei Chiu
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Kuan-Wei Chiu @ 2026-03-18 19:35 UTC (permalink / raw)
  To: andrew, avifishman70, tmaimon77, tali.perry1, srini, robh,
	krzk+dt, conor+dt
  Cc: venture, yuenn, benjaminfair, jserv, eleanor15x, linux-arm-kernel,
	openbmc, devicetree, linux-kernel, Kuan-Wei Chiu

Add support for the OTP memory controllers found on Nuvoton NPCM7 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.

You can use qemu-system-arm -M npcm750-evb to play around with it.

Kuan-Wei Chiu (3):
  dt-bindings: nvmem: add nuvoton,npcm750-otp
  nvmem: npcm-otp: Add Nuvoton NPCM OTP driver
  ARM: dts: nuvoton: Add OTP nodes for NPCM7xx

 .../bindings/nvmem/nuvoton,npcm750-otp.yaml   |  35 +++++
 MAINTAINERS                                   |   7 +
 .../dts/nuvoton/nuvoton-common-npcm7xx.dtsi   |  10 ++
 drivers/nvmem/Kconfig                         |  10 ++
 drivers/nvmem/Makefile                        |   2 +
 drivers/nvmem/npcm-otp.c                      | 129 ++++++++++++++++++
 6 files changed, 193 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/nvmem/nuvoton,npcm750-otp.yaml
 create mode 100644 drivers/nvmem/npcm-otp.c

-- 
2.53.0.851.ga537e3e6e9-goog


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] dt-bindings: nvmem: add nuvoton,npcm750-otp
  2026-03-18 19:35 [PATCH 0/3] nvmem: Add Nuvoton NPCM OTP driver Kuan-Wei Chiu
@ 2026-03-18 19:35 ` Kuan-Wei Chiu
  2026-03-18 20:17   ` Krzysztof Kozlowski
  2026-03-18 19:35 ` [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver Kuan-Wei Chiu
  2026-03-18 19:35 ` [PATCH 3/3] ARM: dts: nuvoton: Add OTP nodes for NPCM7xx Kuan-Wei Chiu
  2 siblings, 1 reply; 8+ messages in thread
From: Kuan-Wei Chiu @ 2026-03-18 19:35 UTC (permalink / raw)
  To: andrew, avifishman70, tmaimon77, tali.perry1, srini, robh,
	krzk+dt, conor+dt
  Cc: venture, yuenn, benjaminfair, jserv, eleanor15x, linux-arm-kernel,
	openbmc, devicetree, linux-kernel, Kuan-Wei Chiu

Add device tree bindings for the OTP memory controllers found on
Nuvoton NPCM7xx SoCs.

The NPCM7xx SoCs contain two independent OTP memory arrays:
- Key Storage (OTP1): used for cryptographic keys.
- Fuse Array (OTP2): used for hardware strapping, calibration data,
  and derivative definitions.

Each controller provides up to 1024 bytes of read-only storage.

Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
---
 .../bindings/nvmem/nuvoton,npcm750-otp.yaml   | 35 +++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/nvmem/nuvoton,npcm750-otp.yaml

diff --git a/Documentation/devicetree/bindings/nvmem/nuvoton,npcm750-otp.yaml b/Documentation/devicetree/bindings/nvmem/nuvoton,npcm750-otp.yaml
new file mode 100644
index 000000000000..45bcf72d7c78
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/nuvoton,npcm750-otp.yaml
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/nuvoton,npcm750-otp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nuvoton NPCM7xx OTP (One-Time Programmable) Memory
+
+maintainers:
+  - Kuan-Wei Chiu <visitorckw@gmail.com>
+
+allOf:
+  - $ref: nvmem.yaml#
+
+properties:
+  compatible:
+    enum:
+      - nuvoton,npcm750-key-storage
+      - nuvoton,npcm750-fuse-array
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    otp@f0189000 {
+        compatible = "nuvoton,npcm750-key-storage";
+        reg = <0xf0189000 0x1000>;
+    };
-- 
2.53.0.851.ga537e3e6e9-goog


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver
  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 19:35 ` Kuan-Wei Chiu
  2026-03-19 10:57   ` Tomer Maimon
  2026-03-18 19:35 ` [PATCH 3/3] ARM: dts: nuvoton: Add OTP nodes for NPCM7xx Kuan-Wei Chiu
  2 siblings, 1 reply; 8+ messages in thread
From: Kuan-Wei Chiu @ 2026-03-18 19:35 UTC (permalink / raw)
  To: andrew, avifishman70, tmaimon77, tali.perry1, srini, robh,
	krzk+dt, conor+dt
  Cc: venture, yuenn, benjaminfair, jserv, eleanor15x, linux-arm-kernel,
	openbmc, devicetree, linux-kernel, Kuan-Wei Chiu

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


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3] ARM: dts: nuvoton: Add OTP nodes for NPCM7xx
  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 19:35 ` [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver Kuan-Wei Chiu
@ 2026-03-18 19:35 ` Kuan-Wei Chiu
  2 siblings, 0 replies; 8+ messages in thread
From: Kuan-Wei Chiu @ 2026-03-18 19:35 UTC (permalink / raw)
  To: andrew, avifishman70, tmaimon77, tali.perry1, srini, robh,
	krzk+dt, conor+dt
  Cc: venture, yuenn, benjaminfair, jserv, eleanor15x, linux-arm-kernel,
	openbmc, devicetree, linux-kernel, Kuan-Wei Chiu

Add device tree nodes for the OTP memory controllers found on Nuvoton
NPCM7xx SoCs.

The controllers (Key Storage and Fuse Array) are attached to the
APB bus. Since they are internal SoC components with no board-level
dependencies, they are enabled by default.

Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
---
 arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi b/arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi
index ab3c3c5713ae..8a28b1f8a4fd 100644
--- a/arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi
+++ b/arch/arm/boot/dts/nuvoton/nuvoton-common-npcm7xx.dtsi
@@ -480,6 +480,16 @@ &fanin12_pins &fanin13_pins
 				status = "disabled";
 			};
 
+			otp1: otp@189000 {
+				compatible = "nuvoton,npcm750-key-storage";
+				reg = <0x189000 0x1000>;
+			};
+
+			otp2: otp@18a000 {
+				compatible = "nuvoton,npcm750-fuse-array";
+				reg = <0x18a000 0x1000>;
+			};
+
 			i2c0: i2c@80000 {
 				reg = <0x80000 0x1000>;
 				compatible = "nuvoton,npcm750-i2c";
-- 
2.53.0.851.ga537e3e6e9-goog


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] dt-bindings: nvmem: add nuvoton,npcm750-otp
  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
  0 siblings, 1 reply; 8+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-18 20:17 UTC (permalink / raw)
  To: Kuan-Wei Chiu, andrew, avifishman70, tmaimon77, tali.perry1,
	srini, robh, krzk+dt, conor+dt
  Cc: venture, yuenn, benjaminfair, jserv, eleanor15x, linux-arm-kernel,
	openbmc, devicetree, linux-kernel

On 18/03/2026 20:35, Kuan-Wei Chiu wrote:
> +maintainers:
> +  - Kuan-Wei Chiu <visitorckw@gmail.com>
> +
> +allOf:
> +  - $ref: nvmem.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - nuvoton,npcm750-key-storage
> +      - nuvoton,npcm750-fuse-array

Your driver says these are exactly the same devices, so you got only one
compatible. Otherwise explain in commit msg why these are different
(current message speaks about purpose, but is not what is needed here).

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] dt-bindings: nvmem: add nuvoton,npcm750-otp
  2026-03-18 20:17   ` Krzysztof Kozlowski
@ 2026-03-18 20:24     ` Kuan-Wei Chiu
  0 siblings, 0 replies; 8+ messages in thread
From: Kuan-Wei Chiu @ 2026-03-18 20:24 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: andrew, avifishman70, tmaimon77, tali.perry1, srini, robh,
	krzk+dt, conor+dt, venture, yuenn, benjaminfair, jserv,
	eleanor15x, linux-arm-kernel, openbmc, devicetree, linux-kernel

Hi Krzysztof,

On Wed, Mar 18, 2026 at 09:17:19PM +0100, Krzysztof Kozlowski wrote:
> On 18/03/2026 20:35, Kuan-Wei Chiu wrote:
> > +maintainers:
> > +  - Kuan-Wei Chiu <visitorckw@gmail.com>
> > +
> > +allOf:
> > +  - $ref: nvmem.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - nuvoton,npcm750-key-storage
> > +      - nuvoton,npcm750-fuse-array
> 
> Your driver says these are exactly the same devices, so you got only one
> compatible. Otherwise explain in commit msg why these are different
> (current message speaks about purpose, but is not what is needed here).
> 
Thanks for the prompt review.

I will drop the content-specific compatible strings and unify them into
a single "nuvoton,npcm750-otp" in the upcoming v2 series.

Regards,
Kuan-Wei

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver
  2026-03-18 19:35 ` [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver Kuan-Wei Chiu
@ 2026-03-19 10:57   ` Tomer Maimon
  2026-03-19 16:17     ` Kuan-Wei Chiu
  0 siblings, 1 reply; 8+ messages in thread
From: Tomer Maimon @ 2026-03-19 10:57 UTC (permalink / raw)
  To: Kuan-Wei Chiu
  Cc: andrew, avifishman70, tali.perry1, srini, robh, krzk+dt, conor+dt,
	venture, yuenn, benjaminfair, jserv, eleanor15x, linux-arm-kernel,
	openbmc, devicetree, linux-kernel

Hi Kuan-Wei,

Thanks for the upstream Nuvoton OTP driver.

On Wed, 18 Mar 2026 at 21:36, Kuan-Wei Chiu <visitorckw@gmail.com> wrote:
>
> 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);
Since the driver already opens and manages the OTP registers, it
should also be responsible for handling the OTP index.
The NPCM AES driver can make use of keys stored in OTP.
We would be happy to help add support for OTP‑stored keys to the
upstream driver.
If you’d like, we can set up a meeting to discuss how this can be implemented.
> +
> +       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;
Suggest setting the size according to the BMC SoC,
The NPCM7xx has 2 8Kbyte OTP, and the NPCM8xx 64KB size.OPT
> +
> +       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
>

Thanks,

Tomer

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver
  2026-03-19 10:57   ` Tomer Maimon
@ 2026-03-19 16:17     ` Kuan-Wei Chiu
  0 siblings, 0 replies; 8+ messages in thread
From: Kuan-Wei Chiu @ 2026-03-19 16:17 UTC (permalink / raw)
  To: Tomer Maimon
  Cc: andrew, avifishman70, tali.perry1, srini, robh, krzk+dt, conor+dt,
	venture, yuenn, benjaminfair, jserv, eleanor15x, linux-arm-kernel,
	openbmc, devicetree, linux-kernel

Hi Tomer,

On Thu, Mar 19, 2026 at 12:57:04PM +0200, Tomer Maimon wrote:
> Hi Kuan-Wei,
> 
> Thanks for the upstream Nuvoton OTP driver.
> 
> On Wed, 18 Mar 2026 at 21:36, Kuan-Wei Chiu <visitorckw@gmail.com> wrote:
> >
> > 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);
> Since the driver already opens and manages the OTP registers, it
> should also be responsible for handling the OTP index.
> The NPCM AES driver can make use of keys stored in OTP.
> We would be happy to help add support for OTP‑stored keys to the
> upstream driver.
> If you’d like, we can set up a meeting to discuss how this can be implemented.

I would be very happy to collaborate. :)

Regarding scheduling a meeting, I will be traveling abroad from 03/22
to 04/01 with very limited and unstable network access, so I would
prefer to avoid that window. We can coordinate the exact date and time
off-list.

Regards,
Kuan-Wei

> > +
> > +       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;
> Suggest setting the size according to the BMC SoC,
> The NPCM7xx has 2 8Kbyte OTP, and the NPCM8xx 64KB size.OPT
> > +
> > +       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
> >
> 
> Thanks,
> 
> Tomer

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-03-19 16:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver Kuan-Wei Chiu
2026-03-19 10:57   ` 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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox