Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/3] Add SG2044 eFUSE driver
@ 2026-10-14  7:45 Inochi Amaoto
  2026-10-14  7:45 ` [PATCH 1/3] dt-bindings: nvmem: Add SG2044 eFuse controller Inochi Amaoto
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Inochi Amaoto @ 2026-10-14  7:45 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen Wang, Inochi Amaoto, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: devicetree, sophgo, linux-kernel, linux-riscv, Yixun Lan,
	Longbin Li

Add SG2044 eFUSE driver, The eFUSE contains factory-programmed data,
and it will be auto loaded into shadow registers while startup. So
only MMIO read is needed.

Inochi Amaoto (3):
  dt-bindings: nvmem: Add SG2044 eFuse controller
  nvmem: Add Sophgo SG2044 eFuse driver
  riscv: dts: sophgo: sg2044: Add eFUSE device

 .../bindings/nvmem/sophgo,efuse.yaml          |  61 ++++++
 .../boot/dts/sophgo/sg2044-sophgo-srd3-10.dts |   4 +
 arch/riscv/boot/dts/sophgo/sg2044.dtsi        |  12 ++
 drivers/nvmem/Kconfig                         |  12 ++
 drivers/nvmem/Makefile                        |   2 +
 drivers/nvmem/sophgo-efuse.c                  | 177 ++++++++++++++++++
 6 files changed, 268 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/nvmem/sophgo,efuse.yaml
 create mode 100644 drivers/nvmem/sophgo-efuse.c

--
2.56.0


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

* [PATCH 1/3] dt-bindings: nvmem: Add SG2044 eFuse controller
  2026-10-14  7:45 [PATCH 0/3] Add SG2044 eFUSE driver Inochi Amaoto
@ 2026-10-14  7:45 ` Inochi Amaoto
  2026-10-14 11:43   ` Krzysztof Kozlowski
  2026-10-14  7:45 ` [PATCH 2/3] nvmem: Add Sophgo SG2044 eFuse driver Inochi Amaoto
  2026-10-14  7:45 ` [PATCH 3/3] riscv: dts: sophgo: sg2044: Add eFUSE device Inochi Amaoto
  2 siblings, 1 reply; 8+ messages in thread
From: Inochi Amaoto @ 2026-10-14  7:45 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen Wang, Inochi Amaoto, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: devicetree, sophgo, linux-kernel, linux-riscv, Yixun Lan,
	Longbin Li

Sophgo SG2044 uses eFuses used to store factory-programmed data
such as ROM patch, public keys and other factory information.

Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
 .../bindings/nvmem/sophgo,efuse.yaml          | 61 +++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/nvmem/sophgo,efuse.yaml

diff --git a/Documentation/devicetree/bindings/nvmem/sophgo,efuse.yaml b/Documentation/devicetree/bindings/nvmem/sophgo,efuse.yaml
new file mode 100644
index 000000000000..d4bffe2724ac
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/sophgo,efuse.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/sophgo,efuse.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sophgo SoC eFuse-based NVMEM
+
+description:
+  Sophgo SoCs contain factory-programmed eFuses used to store ROM patch,
+  public key and other factory information.
+
+maintainers:
+  - Inochi Amaoto <inochiama@gmail.com>
+
+allOf:
+  - $ref: nvmem.yaml#
+
+properties:
+  compatible:
+    enum:
+      - sophgo,sg2044-efuse
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    minItems: 1
+    items:
+      - description: Core clock
+      - description: APB clock
+
+  clock-names:
+    minItems: 1
+    items:
+      - const: core
+      - const: apb
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    efuse@40000000 {
+        compatible = "sophgo,sg2044-efuse";
+        reg = <0x40000000 0x1000>;
+        #address-cells = <1>;
+        #size-cells = <1>;
+        clocks = <&clk 0>,
+                 <&clk 1>;
+        clock-names = "core", "apb";
+    };
+
+...
-- 
2.56.0


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

* [PATCH 2/3] nvmem: Add Sophgo SG2044 eFuse driver
  2026-10-14  7:45 [PATCH 0/3] Add SG2044 eFUSE driver Inochi Amaoto
  2026-10-14  7:45 ` [PATCH 1/3] dt-bindings: nvmem: Add SG2044 eFuse controller Inochi Amaoto
@ 2026-10-14  7:45 ` Inochi Amaoto
  2026-10-14  7:53   ` sashiko-bot
  2026-10-14  7:45 ` [PATCH 3/3] riscv: dts: sophgo: sg2044: Add eFUSE device Inochi Amaoto
  2 siblings, 1 reply; 8+ messages in thread
From: Inochi Amaoto @ 2026-10-14  7:45 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen Wang, Inochi Amaoto, Paul Walmsley, Albert Ou,
	Alexandre Ghiti
  Cc: devicetree, sophgo, linux-kernel, linux-riscv, Yixun Lan,
	Longbin Li

Sophgo SoCs such as SG2044 contain eFuses used to store
factory-programmed data.

As for SG2044, HW automatically loads the eFuse content
into shadow registers which are organized as 32bit values
exposed as MMIO.

Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
 drivers/nvmem/Kconfig        |  12 +++
 drivers/nvmem/Makefile       |   2 +
 drivers/nvmem/sophgo-efuse.c | 176 +++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+)
 create mode 100644 drivers/nvmem/sophgo-efuse.c

diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index c36c2a4c2a0b..a7936dd65bdd 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -465,6 +465,18 @@ config NVMEM_SNVS_LPGPR
 	  This driver can also be built as a module. If so, the module
 	  will be called nvmem-snvs-lpgpr.
 
+config NVMEM_SOPHGO_EFUSE
+	tristate "Sophgo eFuse support"
+	depends on ARCH_SOPHGO || COMPILE_TEST
+	default ARCH_SOPHGO
+	help
+	  Say y here to enable support for reading eFuses on Sophgo SoCs
+	  such as the CV1800B. These are e.g. used to store factory programmed
+	  calibration data required for the builtin ethernet PHY.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called nvmem-sophgo-efuse.
+
 config NVMEM_SPMI_SDAM
 	tristate "SPMI SDAM Support"
 	depends on SPMI
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 2bbfb9ff1885..430ddddf8c3c 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -79,6 +79,8 @@ obj-$(CONFIG_NVMEM_SC27XX_EFUSE)	+= nvmem-sc27xx-efuse.o
 nvmem-sc27xx-efuse-y			:= sc27xx-efuse.o
 obj-$(CONFIG_NVMEM_SNVS_LPGPR)		+= nvmem_snvs_lpgpr.o
 nvmem_snvs_lpgpr-y			:= snvs_lpgpr.o
+obj-$(CONFIG_NVMEM_SOPHGO_EFUSE)	+= nvmem-sophgo-efuse.o
+nvmem-sophgo-efuse-y			:= sophgo-efuse.o
 obj-$(CONFIG_NVMEM_SPMI_SDAM)		+= nvmem_qcom-spmi-sdam.o
 nvmem_qcom-spmi-sdam-y			+= qcom-spmi-sdam.o
 obj-$(CONFIG_NVMEM_SPRD_EFUSE)		+= nvmem_sprd_efuse.o
diff --git a/drivers/nvmem/sophgo-efuse.c b/drivers/nvmem/sophgo-efuse.c
new file mode 100644
index 000000000000..5f90adaf8e4f
--- /dev/null
+++ b/drivers/nvmem/sophgo-efuse.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Sophgo SoC eFuse driver
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/cleanup.h>
+#include <linux/iopoll.h>
+#include <linux/math.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/nvmem-provider.h>
+#include <linux/platform_device.h>
+
+#define SG2044_EFUSE_CONTENT_SIZE		0x400
+
+#define SG2044_EFUSE_MD				0x000
+#define SG2044_EFUSE_ADR			0x004
+#define SG2044_EFUSE_RD_DATA			0x00c
+
+#define SG2044_EFUSE_MODE			GENMASK(1, 0)
+#define SG2044_EFUSE_MODE_READ			2
+
+#define SG2044_EFUSE_BOOT_DONE			BIT(7)
+#define SG2044_BOOT_TIMEOUT			10000
+
+#define SG2044_EFUSE_ADR_ADDR			GENMASK(7, 0)
+
+#define SG2044_EFUSE_ALIGN			4
+
+struct sophgo_efuses {
+	void __iomem *base;
+	struct clk_bulk_data *clks;
+	int num_clks;
+	struct mutex mutex;
+};
+
+static int sg2044_efuse_wait_mode(struct sophgo_efuses *efuse)
+{
+	u32 value;
+
+	return readl_poll_timeout(efuse->base + SG2044_EFUSE_MD, value,
+				  FIELD_GET(SG2044_EFUSE_MODE, value) == 0,
+				  1, SG2044_BOOT_TIMEOUT);
+}
+
+static int sg2044_efuse_set_mode(struct sophgo_efuses *efuse, int mode)
+{
+	u32 val = readl(efuse->base + SG2044_EFUSE_MD);
+
+	val &= ~SG2044_EFUSE_MODE;
+	val |= FIELD_PREP(SG2044_EFUSE_MODE, mode);
+
+	writel(val, efuse->base + SG2044_EFUSE_MD);
+
+	return sg2044_efuse_wait_mode(efuse);
+}
+
+static u32 sg2044_efuses_read_strip(struct sophgo_efuses *efuse,
+				    unsigned int offset, u32 *strip)
+{
+	u32 val = FIELD_PREP(SG2044_EFUSE_ADR_ADDR, offset);
+	int ret;
+
+	guard(mutex)(&efuse->mutex);
+
+	writel(val, efuse->base + SG2044_EFUSE_ADR);
+
+	ret = sg2044_efuse_set_mode(efuse, SG2044_EFUSE_MODE_READ);
+	if (ret < 0)
+		return ret;
+
+	*strip = readl(efuse->base + SG2044_EFUSE_RD_DATA);
+
+	return 0;
+}
+
+static int sg2044_efuses_read(void *context, unsigned int offset, void *val,
+			      size_t bytes)
+{
+	struct sophgo_efuses *efuse = context;
+	unsigned int start, start_offset, end, i;
+	u32 value;
+	u8 *buf;
+	int ret;
+
+	start = rounddown(offset, SG2044_EFUSE_ALIGN);
+	end = roundup(offset + bytes, SG2044_EFUSE_ALIGN);
+	start_offset = offset - start;
+
+	start /= SG2044_EFUSE_ALIGN;
+	end /= SG2044_EFUSE_ALIGN;
+
+	ret = readl_poll_timeout(efuse->base + SG2044_EFUSE_MD, value,
+				 (value & SG2044_EFUSE_BOOT_DONE),
+				 1, SG2044_BOOT_TIMEOUT);
+	if (ret < 0)
+		return ret;
+
+	buf = kzalloc(end - start, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	for (i = start; i < end; i++) {
+		ret = sg2044_efuses_read_strip(efuse, i, &value);
+		if (ret)
+			goto failed;
+
+		memcpy(&buf[(i - start) * 4], &value, SG2044_EFUSE_ALIGN);
+	}
+
+	memcpy(val, buf + start_offset, bytes);
+
+failed:
+	kfree(buf);
+
+	return ret;
+}
+
+static int sophgo_efuses_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct sophgo_efuses *efuse;
+	struct nvmem_config config = {
+		.dev = &pdev->dev,
+		.add_legacy_fixed_of_cells = true,
+		.read_only = true,
+		.reg_read = sg2044_efuses_read,
+		.stride = 1,
+		.word_size = 1,
+		.name = "sophgo-efuse",
+		.id = NVMEM_DEVID_AUTO,
+		.root_only = true,
+	};
+
+	efuse = devm_kzalloc(dev, sizeof(*efuse), GFP_KERNEL);
+	if (!efuse)
+		return -ENOMEM;
+
+	efuse->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(efuse->base))
+		return PTR_ERR(efuse->base);
+
+	efuse->num_clks = devm_clk_bulk_get_all_enabled(&pdev->dev, &efuse->clks);
+	if (efuse->num_clks < 0)
+		return dev_err_probe(dev, efuse->num_clks, "failed to get clocks\n");
+
+	config.priv = efuse;
+	config.size = SG2044_EFUSE_CONTENT_SIZE;
+
+	return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config));
+}
+
+static const struct of_device_id sophgo_efuses_of_match[] = {
+	{ .compatible = "sophgo,sg2044-efuse", },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, sophgo_efuses_of_match);
+
+static struct platform_driver sophgo_efuses_driver = {
+	.driver = {
+		.name = "sophgo_efuse",
+		.of_match_table = sophgo_efuses_of_match,
+	},
+	.probe = sophgo_efuses_probe,
+};
+
+module_platform_driver(sophgo_efuses_driver);
+
+MODULE_AUTHOR("Inochi Amaoto <inochiama@gmail.com>");
+MODULE_DESCRIPTION("Sophgo efuse driver");
+MODULE_LICENSE("GPL");
-- 
2.56.0


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

* [PATCH 3/3] riscv: dts: sophgo: sg2044: Add eFUSE device
  2026-10-14  7:45 [PATCH 0/3] Add SG2044 eFUSE driver Inochi Amaoto
  2026-10-14  7:45 ` [PATCH 1/3] dt-bindings: nvmem: Add SG2044 eFuse controller Inochi Amaoto
  2026-10-14  7:45 ` [PATCH 2/3] nvmem: Add Sophgo SG2044 eFuse driver Inochi Amaoto
@ 2026-10-14  7:45 ` Inochi Amaoto
  2026-10-14  7:54   ` sashiko-bot
  2026-10-14 11:43   ` Krzysztof Kozlowski
  2 siblings, 2 replies; 8+ messages in thread
From: Inochi Amaoto @ 2026-10-14  7:45 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen Wang, Inochi Amaoto, Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: devicetree, sophgo, linux-kernel, linux-riscv, Yixun Lan,
	Longbin Li

Add eFUSE controller node for SG2044.

Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
 arch/riscv/boot/dts/sophgo/sg2044-sophgo-srd3-10.dts |  4 ++++
 arch/riscv/boot/dts/sophgo/sg2044.dtsi               | 12 ++++++++++++
 drivers/nvmem/sophgo-efuse.c                         |  1 +
 3 files changed, 17 insertions(+)

diff --git a/arch/riscv/boot/dts/sophgo/sg2044-sophgo-srd3-10.dts b/arch/riscv/boot/dts/sophgo/sg2044-sophgo-srd3-10.dts
index fed3d9a384a0..1b506972d465 100644
--- a/arch/riscv/boot/dts/sophgo/sg2044-sophgo-srd3-10.dts
+++ b/arch/riscv/boot/dts/sophgo/sg2044-sophgo-srd3-10.dts
@@ -36,6 +36,10 @@ &emmc {
 	status = "okay";
 };
 
+&efuse0 {
+	status = "okay";
+};
+
 &gmac0 {
 	phy-handle = <&phy0>;
 	phy-mode = "rgmii-id";
diff --git a/arch/riscv/boot/dts/sophgo/sg2044.dtsi b/arch/riscv/boot/dts/sophgo/sg2044.dtsi
index 320c4d1d08e6..9577aae08f7f 100644
--- a/arch/riscv/boot/dts/sophgo/sg2044.dtsi
+++ b/arch/riscv/boot/dts/sophgo/sg2044.dtsi
@@ -408,6 +408,18 @@ sd: mmc@703000b000 {
 			status = "disabled";
 		};
 
+		efuse0: efuse@7040000000 {
+			compatible = "sophgo,sg2044-efuse";
+			reg = <0x70 0x40000000 0x0 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			clocks = <&clk CLK_GATE_EFUSE>,
+				 <&clk CLK_GATE_APB_EFUSE>;
+			clock-names = "core", "apb";
+			resets = <&rst RST_EFUSE0>;
+			status = "disabled";
+		};
+
 		i2c0: i2c@7040005000 {
 			compatible = "sophgo,sg2044-i2c", "snps,designware-i2c";
 			reg = <0x70 0x40005000 0x0 0x1000>;
diff --git a/drivers/nvmem/sophgo-efuse.c b/drivers/nvmem/sophgo-efuse.c
index 5f90adaf8e4f..568d17b88ff6 100644
--- a/drivers/nvmem/sophgo-efuse.c
+++ b/drivers/nvmem/sophgo-efuse.c
@@ -14,6 +14,7 @@
 #include <linux/mutex.h>
 #include <linux/nvmem-provider.h>
 #include <linux/platform_device.h>
+#include <linux/slab.h>
 
 #define SG2044_EFUSE_CONTENT_SIZE		0x400
 
-- 
2.56.0


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

* Re: [PATCH 2/3] nvmem: Add Sophgo SG2044 eFuse driver
  2026-10-14  7:45 ` [PATCH 2/3] nvmem: Add Sophgo SG2044 eFuse driver Inochi Amaoto
@ 2026-10-14  7:53   ` sashiko-bot
  0 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-10-14  7:53 UTC (permalink / raw)
  To: Inochi Amaoto; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [Critical] mm: heap buffer overflow in sg2044_efuses_read allocation
- [High] nvmem: sophgo-efuse: heap buffer overflow due to word-to-byte calculation error
- [High] nvmem: sophgo-efuse: uninitialized mutex triggers kernel panic or undefined behavior
- [High] locking: uninitialized mutex efuse->mutex causes crash
- [Low] nvmem: sophgo-efuse: sg2044_efuses_read_strip() returns negative error code as u32
- [Low] endianness: byte order reversal on big-endian via memcpy
--

commit ff98cc30d6e5cb08398ecc6957a9d51875c1b34b
Author: Inochi Amaoto <inochiama@gmail.com>

nvmem: Add Sophgo SG2044 eFuse driver

This patch adds a new nvmem driver for Sophgo eFuses used on system-on-chips
such as the SG2044. The driver exposes the shadow registers, which are
organized as 32-bit values, as memory-mapped io.

> diff --git a/drivers/nvmem/sophgo-efuse.c b/drivers/nvmem/sophgo-efuse.c
> new file mode 100644
> index 0000000000000..5f90adaf8e4fc
> --- /dev/null
> +++ b/drivers/nvmem/sophgo-efuse.c
[ ... ]
> +static u32 sg2044_efuses_read_strip(struct sophgo_efuses *efuse,
> +				    unsigned int offset, u32 *strip)
> +{
> +	u32 val = FIELD_PREP(SG2044_EFUSE_ADR_ADDR, offset);
> +	int ret;
> +
> +	guard(mutex)(&efuse->mutex);
> +
> +	writel(val, efuse->base + SG2044_EFUSE_ADR);
> +
> +	ret = sg2044_efuse_set_mode(efuse, SG2044_EFUSE_MODE_READ);
> +	if (ret < 0)
> +		return ret;

[Severity: Low]
Does this code return a negative error code as a u32?

sg2044_efuse_set_mode() returns an int (such as -ETIMEDOUT), which gets cast
to a large unsigned integer when returned here. Even though the caller
assigns it back to an int ret, returning negative values via an unsigned type
is poor practice and obscures the logic.

Should the return type of sg2044_efuses_read_strip() be int instead of u32?

[ ... ]
> +static int sg2044_efuses_read(void *context, unsigned int offset, void *val,
> +			      size_t bytes)
> +{
> +	struct sophgo_efuses *efuse = context;
> +	unsigned int start, start_offset, end, i;
> +	u32 value;
> +	u8 *buf;
> +	int ret;
> +
> +	start = rounddown(offset, SG2044_EFUSE_ALIGN);
> +	end = roundup(offset + bytes, SG2044_EFUSE_ALIGN);
> +	start_offset = offset - start;
> +
> +	start /= SG2044_EFUSE_ALIGN;
> +	end /= SG2044_EFUSE_ALIGN;
> +
> +	ret = readl_poll_timeout(efuse->base + SG2044_EFUSE_MD, value,
> +				 (value & SG2044_EFUSE_BOOT_DONE),
> +				 1, SG2044_BOOT_TIMEOUT);
> +	if (ret < 0)
> +		return ret;
> +
> +	buf = kzalloc(end - start, GFP_KERNEL);

[Severity: Critical]
Does this allocate an undersized buffer?

The variables start and end were divided by SG2044_EFUSE_ALIGN (4), changing
them from byte offsets to 32-bit word indices. The allocation size is exactly
end - start bytes, effectively allocating only 1 byte per 4-byte word instead
of (end - start) * SG2044_EFUSE_ALIGN.

> +	if (!buf)
> +		return -ENOMEM;
> +
> +	for (i = start; i < end; i++) {
> +		ret = sg2044_efuses_read_strip(efuse, i, &value);
> +		if (ret)
> +			goto failed;
> +
> +		memcpy(&buf[(i - start) * 4], &value, SG2044_EFUSE_ALIGN);

[Severity: Critical]
Because the buffer allocation size is implicitly treated as words but
allocated as bytes, this loop writes 4 bytes per word iteration into the
undersized buffer, leading to an out-of-bounds heap write.

[Severity: Low]
Additionally, can this cause a byte order reversal on big-endian
architectures?

readl() returns a 32-bit integer in native endianness. The loop then uses
memcpy() to write this native integer's bytes into a byte buffer.

On big-endian systems, this places the most-significant byte at the lowest
address, reversing the intended nvmem byte-stream order.

[ ... ]
> +static int sophgo_efuses_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct sophgo_efuses *efuse;
> +	struct nvmem_config config = {
> +		.dev = &pdev->dev,
> +		.add_legacy_fixed_of_cells = true,
> +		.read_only = true,
> +		.reg_read = sg2044_efuses_read,
> +		.stride = 1,
> +		.word_size = 1,
> +		.name = "sophgo-efuse",
> +		.id = NVMEM_DEVID_AUTO,
> +		.root_only = true,
> +	};
> +
> +	efuse = devm_kzalloc(dev, sizeof(*efuse), GFP_KERNEL);

[Severity: High]
Is efuse->mutex left uninitialized?

This allocates the efuse structure (zero-initialized), but mutex_init() is
never called on efuse->mutex anywhere in the probe function.

Later, reading from the eFuse calls sg2044_efuses_read_strip() which attempts
to acquire the lock:

    guard(mutex)(&efuse->mutex);

Locking a zero-initialized mutex will cause a null-pointer dereference crash
on lock contention because the internal wait lists are not initialized.

Should mutex_init(&efuse->mutex) be added after allocation?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261014074516.240247-1-inochiama@gmail.com?part=2

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

* Re: [PATCH 3/3] riscv: dts: sophgo: sg2044: Add eFUSE device
  2026-10-14  7:45 ` [PATCH 3/3] riscv: dts: sophgo: sg2044: Add eFUSE device Inochi Amaoto
@ 2026-10-14  7:54   ` sashiko-bot
  2026-10-14 11:43   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-10-14  7:54 UTC (permalink / raw)
  To: Inochi Amaoto; +Cc: devicetree, robh, conor+dt

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] nvmem: sophgo: heap buffer overflow in sg2044_efuses_read()
- [High] nvmem: sophgo-efuse: uninitialized mutex usage
- [High] nvmem: sophgo-efuse: missing reset line deassertion
- [Low] patch: undocumented driver code modification in a Device Tree patch
- [Low] nvmem: sophgo-efuse: sg2044_efuses_read_strip() return type mismatch
--

commit 9dc44262e764574361fe929e8bb24ed2e5ee7f12
Author: Inochi Amaoto <inochiama@gmail.com>

riscv: dts: sophgo: sg2044: Add eFUSE device

Add eFUSE controller node for SG2044.

> diff --git a/arch/riscv/boot/dts/sophgo/sg2044.dtsi b/arch/riscv/boot/dts/sophgo/sg2044.dtsi
> --- a/arch/riscv/boot/dts/sophgo/sg2044.dtsi
> +++ b/arch/riscv/boot/dts/sophgo/sg2044.dtsi

[ ... ]

> @@ -408,6 +408,18 @@ sd: mmc@703000b000 {
>  			status = "disabled";
>  		};
>  
> +		efuse0: efuse@7040000000 {
> +			compatible = "sophgo,sg2044-efuse";
> +			reg = <0x70 0x40000000 0x0 0x1000>;
> +			#address-cells = <1>;
> +			#size-cells = <1>;
> +			clocks = <&clk CLK_GATE_EFUSE>,
> +				 <&clk CLK_GATE_APB_EFUSE>;
> +			clock-names = "core", "apb";
> +			resets = <&rst RST_EFUSE0>;

[Severity: High]
Does the driver need to deassert this reset line during probe?

The device tree node specifies a reset line, indicating the hardware requires
it.

However, looking at the probe function:

drivers/nvmem/sophgo-efuse.c:sophgo_efuses_probe() {
	...
	efuse->num_clks = devm_clk_bulk_get_all_enabled(&pdev->dev, &efuse->clks);
	if (efuse->num_clks < 0)
		return dev_err_probe(dev, efuse->num_clks, "failed to get clocks\n");

	config.priv = efuse;
	...
}

It seems the reset control is omitted entirely.

If the bootloader leaves the device in a reset state, subsequent MMIO accesses
in sg2044_efuse_wait_mode() could cause a bus hang or timeout.

> +			status = "disabled";
> +		};
> +
>  		i2c0: i2c@7040005000 {

[ ... ]

> diff --git a/drivers/nvmem/sophgo-efuse.c b/drivers/nvmem/sophgo-efuse.c
> --- a/drivers/nvmem/sophgo-efuse.c
> +++ b/drivers/nvmem/sophgo-efuse.c
> @@ -14,6 +14,7 @@
>  #include <linux/mutex.h>
>  #include <linux/nvmem-provider.h>
>  #include <linux/platform_device.h>
> +#include <linux/slab.h>

[Severity: Low]
This isn't a bug, but is it intended to include an undocumented driver
modification in a Device Tree patch?

The patch is scoped as a Device Tree update for the eFUSE DT node, but
silently modifies drivers/nvmem/sophgo-efuse.c to add this include.

Separating driver modifications from DTS patches helps maintain clean subsystem
boundaries and facilitates bisection.

[Severity: High]
Does this code overflow the allocation for the read buffer?

When sg2044_efuses_read() calculates start and end indices:

drivers/nvmem/sophgo-efuse.c:sg2044_efuses_read() {
	...
	start /= SG2044_EFUSE_ALIGN;
	end /= SG2044_EFUSE_ALIGN;
	...
	buf = kzalloc(end - start, GFP_KERNEL);
	...
}

It converts start and end from byte offsets to word counts, but then allocates
the buffer using the word count rather than multiplying by 4.

Later in the loop:

drivers/nvmem/sophgo-efuse.c:sg2044_efuses_read() {
	...
	for (i = start; i < end; i++) {
		ret = sg2044_efuses_read_strip(efuse, i, &value);
		if (ret)
			goto failed;

		memcpy(&buf[(i - start) * 4], &value, SG2044_EFUSE_ALIGN);
	}
	...
}

The memcpy writes 4 bytes per word into the under-allocated buffer.

Could this write past the end of the allocation and cause memory corruption?

[Severity: High]
Is the mutex inside the efuse structure properly initialized?

In the probe function, the structure is allocated and zero-initialized:

drivers/nvmem/sophgo-efuse.c:sophgo_efuses_probe() {
	...
	efuse = devm_kzalloc(dev, sizeof(*efuse), GFP_KERNEL);
	if (!efuse)
		return -ENOMEM;
	...
}

However, it appears devm_mutex_init() or mutex_init() is never called for
efuse->mutex.

When the sysfs read callback executes:

drivers/nvmem/sophgo-efuse.c:sg2044_efuses_read_strip() {
	...
	guard(mutex)(&efuse->mutex);
	...
}

Could locking this uninitialized mutex trigger lockdep warnings or system
crashes due to the uninitialized internal wait lock and wait list?

[Severity: Low]
This isn't a bug, but could the return type of sg2044_efuses_read_strip()
cause issues if negative error codes are implicitly cast?

The function is declared to return a u32:

drivers/nvmem/sophgo-efuse.c:
static u32 sg2044_efuses_read_strip(struct sophgo_efuses *efuse,
				    unsigned int offset, u32 *strip)

But it returns negative error codes directly:

	ret = sg2044_efuse_set_mode(efuse, SG2044_EFUSE_MODE_READ);
	if (ret < 0)
		return ret;

While the single caller sg2044_efuses_read() assigns this back to an int and
checks it correctly, returning negative errors as unsigned integers might lead
to unexpected behavior if future callers check for less than zero.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261014074516.240247-1-inochiama@gmail.com?part=3

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

* Re: [PATCH 1/3] dt-bindings: nvmem: Add SG2044 eFuse controller
  2026-10-14  7:45 ` [PATCH 1/3] dt-bindings: nvmem: Add SG2044 eFuse controller Inochi Amaoto
@ 2026-10-14 11:43   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 8+ messages in thread
From: Krzysztof Kozlowski @ 2026-10-14 11:43 UTC (permalink / raw)
  To: Inochi Amaoto
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen Wang, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, devicetree, sophgo, linux-kernel, linux-riscv,
	Yixun Lan, Longbin Li

On Wed, Oct 14, 2026 at 03:45:13PM +0800, Inochi Amaoto wrote:
> Sophgo SG2044 uses eFuses used to store factory-programmed data
> such as ROM patch, public keys and other factory information.
> 
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> ---
>  .../bindings/nvmem/sophgo,efuse.yaml          | 61 +++++++++++++++++++
>  1 file changed, 61 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/nvmem/sophgo,efuse.yaml

Filename should match compatible.

> 
> diff --git a/Documentation/devicetree/bindings/nvmem/sophgo,efuse.yaml b/Documentation/devicetree/bindings/nvmem/sophgo,efuse.yaml
> new file mode 100644
> index 000000000000..d4bffe2724ac
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/nvmem/sophgo,efuse.yaml
> @@ -0,0 +1,61 @@
> +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/nvmem/sophgo,efuse.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Sophgo SoC eFuse-based NVMEM
> +
> +description:
> +  Sophgo SoCs contain factory-programmed eFuses used to store ROM patch,
> +  public key and other factory information.
> +
> +maintainers:
> +  - Inochi Amaoto <inochiama@gmail.com>
> +
> +allOf:
> +  - $ref: nvmem.yaml#
> +
> +properties:
> +  compatible:
> +    enum:
> +      - sophgo,sg2044-efuse
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    minItems: 1

Why is this flexible?

Best regards,
Krzysztof


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

* Re: [PATCH 3/3] riscv: dts: sophgo: sg2044: Add eFUSE device
  2026-10-14  7:45 ` [PATCH 3/3] riscv: dts: sophgo: sg2044: Add eFUSE device Inochi Amaoto
  2026-10-14  7:54   ` sashiko-bot
@ 2026-10-14 11:43   ` Krzysztof Kozlowski
  1 sibling, 0 replies; 8+ messages in thread
From: Krzysztof Kozlowski @ 2026-10-14 11:43 UTC (permalink / raw)
  To: Inochi Amaoto
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Chen Wang, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, devicetree, sophgo, linux-kernel, linux-riscv,
	Yixun Lan, Longbin Li

On Wed, Oct 14, 2026 at 03:45:15PM +0800, Inochi Amaoto wrote:
> Add eFUSE controller node for SG2044.
> 
> Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> ---
>  arch/riscv/boot/dts/sophgo/sg2044-sophgo-srd3-10.dts |  4 ++++
>  arch/riscv/boot/dts/sophgo/sg2044.dtsi               | 12 ++++++++++++
>  drivers/nvmem/sophgo-efuse.c                         |  1 +

Review code before sending.

Best regards,
Krzysztof


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

end of thread, other threads:[~2026-10-14 11:43 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-14  7:45 [PATCH 0/3] Add SG2044 eFUSE driver Inochi Amaoto
2026-10-14  7:45 ` [PATCH 1/3] dt-bindings: nvmem: Add SG2044 eFuse controller Inochi Amaoto
2026-10-14 11:43   ` Krzysztof Kozlowski
2026-10-14  7:45 ` [PATCH 2/3] nvmem: Add Sophgo SG2044 eFuse driver Inochi Amaoto
2026-10-14  7:53   ` sashiko-bot
2026-10-14  7:45 ` [PATCH 3/3] riscv: dts: sophgo: sg2044: Add eFUSE device Inochi Amaoto
2026-10-14  7:54   ` sashiko-bot
2026-10-14 11:43   ` Krzysztof Kozlowski

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