{"id":2226118,"url":"http://patchwork.ozlabs.org/api/patches/2226118/?format=json","web_url":"http://patchwork.ozlabs.org/project/uboot/patch/20260422093658.15723-1-othacehe@gnu.org/","project":{"id":18,"url":"http://patchwork.ozlabs.org/api/projects/18/?format=json","name":"U-Boot","link_name":"uboot","list_id":"u-boot.lists.denx.de","list_email":"u-boot@lists.denx.de","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260422093658.15723-1-othacehe@gnu.org>","list_archive_url":null,"date":"2026-04-22T09:36:56","name":"[v3] misc: Add RZG2L OTP support","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"f1a3e8432baa13510b52b20453e0e3ac741f671b","submitter":{"id":87750,"url":"http://patchwork.ozlabs.org/api/people/87750/?format=json","name":"Mathieu Othacehe","email":"othacehe@gnu.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/uboot/patch/20260422093658.15723-1-othacehe@gnu.org/mbox/","series":[{"id":500955,"url":"http://patchwork.ozlabs.org/api/series/500955/?format=json","web_url":"http://patchwork.ozlabs.org/project/uboot/list/?series=500955","date":"2026-04-22T09:36:56","name":"[v3] misc: Add RZG2L OTP support","version":3,"mbox":"http://patchwork.ozlabs.org/series/500955/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2226118/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2226118/checks/","tags":{},"related":[],"headers":{"Return-Path":"<u-boot-bounces@lists.denx.de>","X-Original-To":"incoming@patchwork.ozlabs.org","Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gnu.org header.i=@gnu.org header.a=rsa-sha256\n header.s=fencepost-gnu-org header.b=jqiWxPJY;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de\n (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de;\n envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org)","phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=gnu.org","phobos.denx.de;\n spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de","phobos.denx.de;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gnu.org header.i=@gnu.org header.b=\"jqiWxPJY\";\n\tdkim-atps=neutral","phobos.denx.de;\n dmarc=pass (p=none dis=none) header.from=gnu.org","phobos.denx.de;\n spf=pass smtp.mailfrom=othacehe@gnu.org"],"Received":["from phobos.denx.de (phobos.denx.de\n [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g0vKC2hyNz1yD5\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 19:37:51 +1000 (AEST)","from h2850616.stratoserver.net (localhost [IPv6:::1])\n\tby phobos.denx.de (Postfix) with ESMTP id 9B9E9840CB;\n\tWed, 22 Apr 2026 11:37:48 +0200 (CEST)","by phobos.denx.de (Postfix, from userid 109)\n id 0715C840D8; Wed, 22 Apr 2026 11:37:47 +0200 (CEST)","from eggs.gnu.org (eggs.gnu.org [IPv6:2001:470:142:3::10])\n (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n (No client certificate requested)\n by phobos.denx.de (Postfix) with ESMTPS id 9960583936\n for <u-boot@lists.denx.de>; Wed, 22 Apr 2026 11:37:44 +0200 (CEST)","from fencepost.gnu.org ([2001:470:142:3::e])\n by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)\n (Exim 4.90_1) (envelope-from <othacehe@gnu.org>)\n id 1wFU1e-0001WZ-FW; Wed, 22 Apr 2026 05:37:42 -0400"],"X-Spam-Checker-Version":"SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de","X-Spam-Level":"","X-Spam-Status":"No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,\n DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,\n RCVD_IN_DNSWL_BLOCKED,SPF_HELO_PASS,SPF_PASS autolearn=ham\n autolearn_force=no version=3.4.2","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;\n s=fencepost-gnu-org; h=MIME-Version:Date:Subject:To:From:in-reply-to:\n references; bh=kWGw8C6KvoTnsxil6SU3VyxxCzZxioErmoAo49tmaZE=; b=jqiWxPJYZWk/Dg\n d5MdjLlqCs97c3zBQukxA50bWTIH+iTRh77m9WgZgrLM0q6E56KQzLyO0B/4wwB6IwJC9cNVzKpZJ\n jRCgSKq5rBIw5gOjeo86ZtMZjZccvc8PvklvkKtNqVg/9I3IDLfG9+HrO9BpN+43FBqUhOrdwEqNa\n u/YHlaKPCaWVNeVJhC3SBUXSaiTlFO75K57WuipNuOAbAD1GrDzLLYodGmvIqjVGFGph1dteGms27\n CC6WzzmSuvIOOljONOm+6G+hhTDCD8fjEN4DU4Q0kcMO/McdWwNxPNPuRBfl+rNzTchA6kWsX637t\n fbIpdgTkgq3v34GBbvsA==;","From":"Mathieu Othacehe <othacehe@gnu.org>","To":"Tom Rini <trini@konsulko.com>,\n Marek Vasut <marek.vasut+renesas@mailbox.org>,\n Paul Barker <paul@pbarker.dev>, Nobuhiro Iwamatsu <iwamatsu@nigauri.org>","Cc":"Mathieu Othacehe <othacehe@gnu.org>,\n\tu-boot@lists.denx.de","Subject":"[PATCH v3] misc: Add RZG2L OTP support","Date":"Wed, 22 Apr 2026 11:36:56 +0200","Message-ID":"<20260422093658.15723-1-othacehe@gnu.org>","X-Mailer":"git-send-email 2.52.0","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","X-BeenThere":"u-boot@lists.denx.de","X-Mailman-Version":"2.1.39","Precedence":"list","List-Id":"U-Boot discussion <u-boot.lists.denx.de>","List-Unsubscribe":"<https://lists.denx.de/options/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=unsubscribe>","List-Archive":"<https://lists.denx.de/pipermail/u-boot/>","List-Post":"<mailto:u-boot@lists.denx.de>","List-Help":"<mailto:u-boot-request@lists.denx.de?subject=help>","List-Subscribe":"<https://lists.denx.de/listinfo/u-boot>,\n <mailto:u-boot-request@lists.denx.de?subject=subscribe>","Errors-To":"u-boot-bounces@lists.denx.de","Sender":"\"U-Boot\" <u-boot-bounces@lists.denx.de>","X-Virus-Scanned":"clamav-milter 0.103.8 at phobos.denx.de","X-Virus-Status":"Clean"},"content":"Add OTP support through the fuse command. Fusing is directly performed by\nU-Boot, which means that the trusted-firmware must allow the non-secure\nworld to perform fusing operations.\n\nSigned-off-by: Mathieu Othacehe <othacehe@gnu.org>\n---\nChangelog\nv3: Read the OTP_BASE address from the device-tree.\nv2: Depend on CMD_FUSE. Use readl_poll_sleep_timeout and clrbits_le32 functions.\n\n arch/arm/dts/r9a07g044-u-boot.dtsi         |  15 ++\n arch/arm/dts/r9a07g044l2-smarc-u-boot.dtsi |   6 +\n drivers/misc/Kconfig                       |   7 +\n drivers/misc/Makefile                      |   1 +\n drivers/misc/rzg2l_otp.c                   | 255 +++++++++++++++++++++\n 5 files changed, 284 insertions(+)\n create mode 100644 arch/arm/dts/r9a07g044-u-boot.dtsi\n create mode 100644 arch/arm/dts/r9a07g044l2-smarc-u-boot.dtsi\n create mode 100644 drivers/misc/rzg2l_otp.c","diff":"diff --git a/arch/arm/dts/r9a07g044-u-boot.dtsi b/arch/arm/dts/r9a07g044-u-boot.dtsi\nnew file mode 100644\nindex 00000000000..a64ef16fa7f\n--- /dev/null\n+++ b/arch/arm/dts/r9a07g044-u-boot.dtsi\n@@ -0,0 +1,15 @@\n+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)\n+/*\n+ * Copyright (C) 2026 Mathieu Othacehe <m.othacehe@gmail.com>\n+ */\n+\n+/ {\n+\tsoc: soc {\n+\t\totp: otp@11860000 {\n+\t\t\tcompatible = \"renesas,r9a07g044-otp\";\n+\t\t\treg = <0 0x11860000 0 0x20>;\n+\t\t\tstatus = \"okay\";\n+\t\t\tbootph-all;\n+\t\t};\n+\t};\n+};\ndiff --git a/arch/arm/dts/r9a07g044l2-smarc-u-boot.dtsi b/arch/arm/dts/r9a07g044l2-smarc-u-boot.dtsi\nnew file mode 100644\nindex 00000000000..5fe2e6c54a2\n--- /dev/null\n+++ b/arch/arm/dts/r9a07g044l2-smarc-u-boot.dtsi\n@@ -0,0 +1,6 @@\n+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)\n+/*\n+ * Copyright (C) 2026 Mathieu Othacehe <m.othacehe@gmail.com>\n+ */\n+\n+#include \"r9a07g044-u-boot.dtsi\"\ndiff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig\nindex ea785793d18..324a88c9494 100644\n--- a/drivers/misc/Kconfig\n+++ b/drivers/misc/Kconfig\n@@ -132,6 +132,13 @@ config SPL_ROCKCHIP_IODOMAIN\n \t  for the IO-domain setting of the SoC to match the voltage supplied\n \t  by the regulators.\n \n+config RZG2L_OTP\n+\tbool \"Renesas RZ/G2L OTP support\"\n+\tdepends on MISC && CMD_FUSE\n+\thelp\n+\t  Enable support for the OTP controller on\n+\t  Renesas RZ/G2L SoCs.\n+\n config SIFIVE_OTP\n \tbool \"SiFive eMemory OTP driver\"\n \tdepends on MISC\ndiff --git a/drivers/misc/Makefile b/drivers/misc/Makefile\nindex e2170212e5a..64b2701b672 100644\n--- a/drivers/misc/Makefile\n+++ b/drivers/misc/Makefile\n@@ -69,6 +69,7 @@ obj-$(CONFIG_QCOM_GENI) += qcom_geni.o\n obj-$(CONFIG_$(PHASE_)ROCKCHIP_EFUSE) += rockchip-efuse.o\n obj-$(CONFIG_$(PHASE_)ROCKCHIP_OTP) += rockchip-otp.o\n obj-$(CONFIG_$(PHASE_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o\n+obj-$(CONFIG_RZG2L_OTP) += rzg2l_otp.o\n obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o\n obj-$(CONFIG_SIFIVE_OTP) += sifive-otp.o\n obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o\ndiff --git a/drivers/misc/rzg2l_otp.c b/drivers/misc/rzg2l_otp.c\nnew file mode 100644\nindex 00000000000..a1a8b8e9df6\n--- /dev/null\n+++ b/drivers/misc/rzg2l_otp.c\n@@ -0,0 +1,255 @@\n+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)\n+/*\n+ * Copyright (C) 2026 Mathieu Othacehe <m.othacehe@gmail.com>\n+ */\n+#include <dm.h>\n+#include <fuse.h>\n+#include <malloc.h>\n+#include <asm/io.h>\n+#include <linux/delay.h>\n+#include <linux/iopoll.h>\n+\n+/*\n+ * XXX: To enable direct fusing through U-Boot, the trusted-firmware must\n+ * allow the non-secure world to perform fusing operations. This is controlled\n+ * by the SYS_SLVACCCTL7 register.\n+ */\n+\n+/* OTP register offsets (relative to OTP base) */\n+#define RZ_OTP_PWR\t\t0x0000\n+#define RZ_OTP_STR\t\t0x0004\n+#define RZ_OTP_STAWR\t\t0x0008\n+#define RZ_OTP_ADRWR\t\t0x000c\n+#define RZ_OTP_DATAWR\t\t0x0010\n+#define RZ_OTP_ADRRD\t\t0x0014\n+#define RZ_OTP_DATARD\t\t0x0018\n+#define RZ_OTP_FLAG\t\t0x001c\n+\n+#define OTP_PWR\t\t\tBIT(0)\n+#define OTP_RDY\t\t\tBIT(0)\n+#define ERR_WR_1\t\tBIT(1)\n+#define ERR_WR_2\t\tBIT(2)\n+#define ERR_WP\t\t\tBIT(3)\n+#define OTP_ACCL\t\tBIT(4)\n+#define ERR_RDY_WR\t\tBIT(8)\n+#define OTP_DUMMY_READ_OFF\t0x100\n+\n+#define RZ_OTP_POLL(base, reg, val, cond) \\\n+\treadl_poll_sleep_timeout((base) + (reg), (val), (cond), 1000, 1000000)\n+\n+struct rzg2l_otp_priv {\n+\tphys_addr_t\totp_base;\n+};\n+\n+static struct rzg2l_otp_priv *otp_priv;\n+\n+static int rzg2l_otp_open(void)\n+{\n+\tphys_addr_t base = otp_priv->otp_base;\n+\tu32 val;\n+\tint ret;\n+\n+\tif (readl(base + RZ_OTP_PWR) & OTP_PWR) {\n+\t\tdebug(\"OTP already powered up\\n\");\n+\t\treturn 0;\n+\t}\n+\n+\tret = RZ_OTP_POLL(base, RZ_OTP_STR, val, !(val & OTP_RDY));\n+\tif (ret) {\n+\t\tprintf(\"OTP power-up timeout\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = RZ_OTP_POLL(base, RZ_OTP_FLAG, val, val & OTP_RDY);\n+\tif (ret) {\n+\t\tprintf(\"OTP power-up timeout\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\twritel(readl(base + RZ_OTP_PWR) | OTP_PWR | OTP_ACCL,\n+\t       base + RZ_OTP_PWR);\n+\n+\treturn 0;\n+}\n+\n+static int rzg2l_otp_dummy_read(void)\n+{\n+\tphys_addr_t base = otp_priv->otp_base;\n+\tu32 val;\n+\tint ret;\n+\n+\tret = RZ_OTP_POLL(base, RZ_OTP_STR, val, val & OTP_RDY);\n+\tif (ret) {\n+\t\tprintf(\"Timeout polling ready for OTP read\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\twritel(base + OTP_DUMMY_READ_OFF, base + RZ_OTP_ADRRD);\n+\treadl(base + RZ_OTP_DATARD);\n+\n+\treturn 0;\n+}\n+\n+static int rzg2l_otp_close(void)\n+{\n+\tphys_addr_t base = otp_priv->otp_base;\n+\tu32 val;\n+\tint ret;\n+\n+\trzg2l_otp_dummy_read();\n+\n+\tclrbits_le32(base + RZ_OTP_PWR, OTP_PWR | OTP_ACCL);\n+\n+\tret = RZ_OTP_POLL(base, RZ_OTP_STR, val, !(val & OTP_RDY));\n+\tif (ret) {\n+\t\tprintf(\"Timeout leaving OTP ready state\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int rzg2l_otp_read_word(u32 offset, u32 *val)\n+{\n+\tphys_addr_t base = otp_priv->otp_base;\n+\tu32 str;\n+\tint ret;\n+\n+\tret = rzg2l_otp_open();\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = RZ_OTP_POLL(base, RZ_OTP_STR, str, str & OTP_RDY);\n+\tif (ret) {\n+\t\tprintf(\"Timeout polling ready for OTP read\\n\");\n+\t\trzg2l_otp_close();\n+\t\treturn ret;\n+\t}\n+\n+\twritel(base + offset, base + RZ_OTP_ADRRD);\n+\t*val = readl(base + RZ_OTP_DATARD);\n+\n+\tret = rzg2l_otp_close();\n+\n+\treturn ret;\n+}\n+\n+static int rzg2l_otp_program_word(u32 offset, u32 val)\n+{\n+\tphys_addr_t base = otp_priv->otp_base;\n+\tu32 str, otpval;\n+\tint ret;\n+\n+\tret = rzg2l_otp_open();\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = RZ_OTP_POLL(base, RZ_OTP_STR, str, str & OTP_RDY);\n+\tif (ret) {\n+\t\tprintf(\"Timeout polling ready for OTP write\\n\");\n+\t\tgoto close;\n+\t}\n+\n+\twritel(base + offset, base + RZ_OTP_ADRWR);\n+\twritel(val, base + RZ_OTP_DATAWR);\n+\n+\twritel(1, base + RZ_OTP_STAWR);\n+\n+\tif (readl(base + RZ_OTP_STR) & ERR_RDY_WR) {\n+\t\tprintf(\"OTP not ready for write\\n\");\n+\t\twritel(readl(base + RZ_OTP_STR) & ERR_RDY_WR, base + RZ_OTP_STR);\n+\t\tgoto close;\n+\t}\n+\n+\tret = RZ_OTP_POLL(base, RZ_OTP_STR, str, str & OTP_RDY);\n+\tif (ret) {\n+\t\tprintf(\"Timeout polling OTP write finished\\n\");\n+\t\tgoto close;\n+\t}\n+\n+\tret = RZ_OTP_POLL(base, RZ_OTP_STAWR, str, !(str & OTP_RDY));\n+\tif (ret) {\n+\t\tprintf(\"Timeout polling OTP write finished\\n\");\n+\t\tgoto close;\n+\t}\n+\n+\tif ((readl(base + RZ_OTP_STR) & ERR_WP) ||\n+\t    (readl(base + RZ_OTP_STR) & ERR_WR_1) ||\n+\t    (readl(base + RZ_OTP_STR) & ERR_WR_2)) {\n+\t\tprintf(\"OTP write error (protected or invalid)\\n\");\n+\t\tgoto close;\n+\t}\n+\n+\twritel(base + offset, base + RZ_OTP_ADRRD);\n+\totpval = readl(base + RZ_OTP_DATARD);\n+\n+\tif (otpval != val) {\n+\t\tprintf(\"OTP verify failed: wrote 0x%08x read 0x%08x\\n\",\n+\t\t       val, otpval);\n+\t\tgoto close;\n+\t}\n+\n+close:\n+\tret = rzg2l_otp_close();\n+\treturn ret;\n+}\n+\n+/* ---------------------------------------------------------------- */\n+/* U-Boot fuse API                                                   */\n+\n+int fuse_read(u32 bank, u32 word, u32 *val)\n+{\n+\treturn rzg2l_otp_read_word(word >> 2, val);\n+}\n+\n+int fuse_prog(u32 bank, u32 word, u32 val)\n+{\n+\treturn rzg2l_otp_program_word(word >> 2, val);\n+}\n+\n+int fuse_sense(u32 bank, u32 word, u32 *val)\n+{\n+\t/* not supported */\n+\treturn -ENOSYS;\n+}\n+\n+int fuse_override(u32 bank, u32 word, u32 val)\n+{\n+\t/* not supported */\n+\treturn -ENOSYS;\n+}\n+\n+/* ---------------------------------------------------------------- */\n+/* DM driver                                                         */\n+\n+static int rzg2l_otp_bind(struct udevice *dev)\n+{\n+\tphys_addr_t base;\n+\n+\totp_priv = calloc(1, sizeof(struct rzg2l_otp_priv));\n+\tif (!otp_priv)\n+\t\treturn -ENOMEM;\n+\n+\tbase = dev_read_addr(dev);\n+\tif (base == FDT_ADDR_T_NONE) {\n+\t\tprintf(\"Cannot find OTP reg address, binding failed\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\totp_priv->otp_base = base;\n+\n+\tprintf(\"OTP: RZ/G2L OTP module bound\\n\");\n+\n+\treturn 0;\n+}\n+\n+static const struct udevice_id rzg2l_otp_ids[] = {\n+\t{ .compatible = \"renesas,r9a07g044-otp\" },\n+\t{ }\n+};\n+\n+U_BOOT_DRIVER(rzg2l_otp) = {\n+\t.name\t\t= \"rzg2l_otp\",\n+\t.id\t\t= UCLASS_MISC,\n+\t.of_match\t= rzg2l_otp_ids,\n+\t.bind\t\t= rzg2l_otp_bind,\n+};\n","prefixes":["v3"]}