From: Kuan-Wei Chiu <visitorckw@gmail.com>
To: Tomer Maimon <tmaimon77@gmail.com>
Cc: andrew@codeconstruct.com.au, avifishman70@gmail.com,
tali.perry1@gmail.com, srini@kernel.org, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org, 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
Subject: Re: [PATCH 2/3] nvmem: npcm-otp: Add Nuvoton NPCM OTP driver
Date: Fri, 20 Mar 2026 00:17:37 +0800 [thread overview]
Message-ID: <abwhoY0vlmgQ0J1P@google.com> (raw)
In-Reply-To: <CAP6Zq1gJOrEii97X2XjXexZeEQ5SN4F-wW334BN7SOrGbiVQxg@mail.gmail.com>
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
next prev parent reply other threads:[~2026-03-19 16:17 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 ` [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 [this message]
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=abwhoY0vlmgQ0J1P@google.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