[PATCH 1/2] nvmem: Add R-Car E-FUSE driver

Marek Vasut marek.vasut+renesas at mailbox.org
Sat Jan 3 01:21:10 CET 2026


From: Geert Uytterhoeven <geert+renesas at glider.be>

R-Car Gen4 SoCs contain fuses indicating hardware support or hardware
(e.g. tuning) parameters.  Add a driver to access the state of the
fuses.  This supports two types of hardware fuse providers:
  1. E-FUSE non-volatile memory accessible through the Pin Function
     Controller on R-Car V3U and S4-8,
  2. E-FUSE non-volatile memory accessible through OTP_MEM on R-Car V4H
     and V4M.

The state of the cells can be read using the MISC framework, either
from U-Boot space (e.g. by the Renesas UFSHCD driver), or from
command line (e.g. by the 'misc' command).

Ported from Linux kernel commit
1530b923a514 ("nvmem: Add R-Car E-FUSE driver")

Signed-off-by: Geert Uytterhoeven <geert+renesas at glider.be>
Signed-off-by: Marek Vasut <marek.vasut+renesas at mailbox.org>
Link: https://lore.kernel.org/r/20241030140315.40562-3-srinivas.kandagatla@linaro.org
---
Cc: Bhupesh Sharma <bhupesh.linux at gmail.com>
Cc: Neil Armstrong <neil.armstrong at linaro.org>
Cc: Nobuhiro Iwamatsu <iwamatsu at nigauri.org>
Cc: Tom Rini <trini at konsulko.com>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh at renesas.com>
Cc: u-boot at lists.denx.de
---
 drivers/misc/Kconfig      |  8 ++++
 drivers/misc/Makefile     |  1 +
 drivers/misc/rcar-efuse.c | 94 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 103 insertions(+)
 create mode 100644 drivers/misc/rcar-efuse.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index dde773ab6b1..9b75b002b92 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -92,6 +92,14 @@ config QCOM_GENI
 	  for providing a common interface for various peripherals like UART, I2C, SPI,
 	  etc.
 
+config RCAR_EFUSE
+	tristate "Renesas R-Car Gen4 E-FUSE support"
+	depends on RCAR_GEN4
+	depends on MISC
+	help
+	  Enable support for reading the fuses in the E-FUSE or OTP
+	  non-volatile memory block on Renesas R-Car Gen4 SoCs.
+
 config ROCKCHIP_EFUSE
         bool "Rockchip e-fuse support"
 	depends on MISC
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 1d950f7a0ab..14b15079e1a 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_QFW_SMBIOS) += qfw_smbios.o
 obj-$(CONFIG_SANDBOX) += qfw_sandbox.o
 endif
 obj-$(CONFIG_QCOM_GENI) += qcom_geni.o
+obj-$(CONFIG_RCAR_EFUSE) += rcar-efuse.o
 obj-$(CONFIG_$(PHASE_)ROCKCHIP_EFUSE) += rockchip-efuse.o
 obj-$(CONFIG_$(PHASE_)ROCKCHIP_OTP) += rockchip-otp.o
 obj-$(CONFIG_$(PHASE_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
diff --git a/drivers/misc/rcar-efuse.c b/drivers/misc/rcar-efuse.c
new file mode 100644
index 00000000000..8d6109d2249
--- /dev/null
+++ b/drivers/misc/rcar-efuse.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Renesas R-Car E-FUSE/OTP Driver
+ *
+ * Copyright (C) 2024 Glider bv
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <misc.h>
+
+struct rcar_fuse {
+	void __iomem *base;
+};
+
+struct rcar_fuse_data {
+	unsigned int bank;	/* 0: PFC + E-FUSE, 1: OPT_MEM + E-FUSE */
+	unsigned int start;	/* inclusive */
+	unsigned int end;	/* exclusive */
+};
+
+static int rcar_fuse_reg_read(struct udevice *dev, int offset, void *val, int bytes)
+{
+	const struct rcar_fuse_data *data = (void *)dev_get_driver_data(dev);
+	struct rcar_fuse *plat = dev_get_plat(dev);
+	u32 *v32 = (u32 *)val;
+	int i, ret = 0;
+
+	for (i = 0; i < bytes; i += 4) {
+		if (((offset + i) < data->start) || ((offset + i) >= data->end))
+			continue;
+
+		v32[i / 4] = readl(plat->base + offset + i);
+		ret += 4;	/* Count only non-skipped OTP data */
+	}
+
+	return ret;
+}
+
+static const struct rcar_fuse_data rcar_fuse_v3u = {
+	.bank = 0,
+	.start = 0x0c0,
+	.end = 0x0e8,
+};
+
+static const struct rcar_fuse_data rcar_fuse_s4 = {
+	.bank = 0,
+	.start = 0x0c0,
+	.end = 0x14c,
+};
+
+static const struct rcar_fuse_data rcar_fuse_v4h = {
+	.bank = 1,
+	.start = 0x100,
+	.end = 0x1a0,
+};
+
+static const struct rcar_fuse_data rcar_fuse_v4m = {
+	.bank = 1,
+	.start = 0x100,
+	.end = 0x110,
+};
+
+static const struct udevice_id rcar_efuse_ids[] = {
+	{ .compatible = "renesas,r8a779a0-efuse", .data = (ulong)&rcar_fuse_v3u },
+	{ .compatible = "renesas,r8a779f0-efuse", .data = (ulong)&rcar_fuse_s4 },
+	{ .compatible = "renesas,r8a779g0-otp", .data = (ulong)&rcar_fuse_v4h },
+	{ .compatible = "renesas,r8a779h0-otp", .data = (ulong)&rcar_fuse_v4m },
+	{ /* sentinel */ }
+};
+
+static const struct misc_ops rcar_efuse_ops = {
+	.read = rcar_fuse_reg_read,
+};
+
+static int rcar_efuse_of_to_plat(struct udevice *dev)
+{
+	const struct rcar_fuse_data *data = (void *)dev_get_driver_data(dev);
+	struct rcar_fuse *plat = dev_get_plat(dev);
+	fdt_size_t size;
+
+	plat->base = dev_read_addr_size_index_ptr(dev, data->bank, &size);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(rcar_efuse) = {
+	.name = "rcar_efuse",
+	.id = UCLASS_MISC,
+	.of_match = rcar_efuse_ids,
+	.of_to_plat = rcar_efuse_of_to_plat,
+	.plat_auto = sizeof(struct rcar_fuse),
+	.ops = &rcar_efuse_ops,
+};
-- 
2.51.0



More information about the U-Boot mailing list