Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] nvmem: Derive Rockchip MAC addresses from the OTP CPU ID
@ 2026-09-01 15:33 Alexey Charkov
  2026-09-01 15:33 ` [PATCH 1/4] nvmem: rockchip-otp: Serialize reads Alexey Charkov
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Alexey Charkov @ 2026-09-01 15:33 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Miquel Raynal,
	Finley Xiao, Greg Kroah-Hartman
  Cc: devicetree, linux-kernel, linux-rockchip, linux-arm-kernel,
	Alexey Charkov, stable

Rockchip SoCs are shipped with a unique CPU ID in their internal OTP
memory, and Rockchip bootloaders use it to give boards which have no
dedicated storage for a MAC address a stable one anyway: they hash the CPU
ID and patch the resulting addresses into the device tree they hand over.

Kernels started without that fixup, e.g. straight from the SPL in Falcon
mode or by any other loader which does not implement Rockchip's derivation,
fall back to random MAC addresses which change on every boot.

Formalize the derivation in the DT binding and add a Linux kernel driver
implementing it, so that a Linux image can use the same stable addresses
regardless of the boot flow.

Only RK3576 is wired up here, that being the SoC I can test on. Other
Rockchip SoCs keep the same CPU ID at a different OTP offset - 0x7 rather
than 0xa on RK3588, for instance - which makes supporting them a two-line
addition to the driver's match table plus the layout node.

Patch 1 is a prerequisite fix. The OTP hardware has its own internal state
machine which only works correctly with serial access, but the current
driver serializes nothing, which results in timeouts and/or corrupted
reads (e.g. returning splicing a TSADC trim value into the buffer of a
caller asking for the CPU ID, or mixing up trim values of different TSADC
callers). Hence the Fixes: tag and Cc: stable.

Cross-checked on an RK3576 board: the addresses fixed up into the FDT by
U-Boot match the ones derived by the new driver, and the driver correctly
assigns them to the network interfaces when the kernel is booted without
U-Boot proper at all (via Falcon mode).

Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
Alexey Charkov (4):
      nvmem: rockchip-otp: Serialize reads
      dt-bindings: nvmem: layouts: Add Rockchip OTP CPUID layout
      nvmem: layouts: Add Rockchip OTP CPUID layout driver
      arm64: dts: rockchip: Derive GMAC MAC addresses from OTP on RK3576

 .../bindings/nvmem/layouts/nvmem-layout.yaml       |   1 +
 .../nvmem/layouts/rockchip,rk3576-otp-cpuid.yaml   |  73 +++++++++++++
 MAINTAINERS                                        |   7 ++
 arch/arm64/boot/dts/rockchip/rk3576.dtsi           |  12 +++
 drivers/nvmem/layouts/Kconfig                      |  13 +++
 drivers/nvmem/layouts/Makefile                     |   1 +
 drivers/nvmem/layouts/rockchip-otp-cpuid.c         | 119 +++++++++++++++++++++
 drivers/nvmem/rockchip-otp.c                       |  10 ++
 8 files changed, 236 insertions(+)
---
base-commit: 89c07d98716a13454ec3fd9f97689e812cc71bd4
change-id: 20260901-rk3576-otp-cpuid-mac-3c90243d0884

Best regards,
--  
Alexey Charkov <alchark@flipper.net>



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

* [PATCH 1/4] nvmem: rockchip-otp: Serialize reads
  2026-09-01 15:33 [PATCH 0/4] nvmem: Derive Rockchip MAC addresses from the OTP CPU ID Alexey Charkov
@ 2026-09-01 15:33 ` Alexey Charkov
  2026-09-02  9:10   ` Miquel Raynal
  2026-09-01 15:33 ` [PATCH 2/4] dt-bindings: nvmem: layouts: Add Rockchip OTP CPUID layout Alexey Charkov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Alexey Charkov @ 2026-09-01 15:33 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Miquel Raynal,
	Finley Xiao, Greg Kroah-Hartman
  Cc: devicetree, linux-kernel, linux-rockchip, linux-arm-kernel,
	Alexey Charkov, stable

The OTP controller is driven through a single set of registers holding a
state machine which has to be stepped through for every word read, yet
nothing keeps two readers out of each other's way. Concurrent reads
interleave, and the outcome is either a reader bailing out:

  rockchip-otp 2a580000.otp: timeout during read setup

or, worse, one of them silently taking delivery of the other's data.

Reading two cells in parallel from userspace on RK3576 reproduces both
within 150 iterations - 53 read errors and 9 corrupted results, the latter
either losing their first word or, in one case, ending in the two bytes
which belong to the other reader's cell - whereas the same reads issued
sequentially never fail. Concurrency is not hypothetical here, as six
thermal sensors source their trim values from the OTP and reach the driver
straight from asynchronous driver probing.

Guard the read path with a mutex. Reads are the only way into the hardware,
as the driver registers no write callback, and they always run in process
context, so a plain mutex spanning the whole clock-enable, read,
clock-disable sequence is enough.

Fixes: 755864feb729 ("nvmem: add Rockchip OTP driver")
Cc: stable@vger.kernel.org
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
 drivers/nvmem/rockchip-otp.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/nvmem/rockchip-otp.c b/drivers/nvmem/rockchip-otp.c
index 2c0feb036f3f..b034b7455016 100644
--- a/drivers/nvmem/rockchip-otp.c
+++ b/drivers/nvmem/rockchip-otp.c
@@ -12,6 +12,7 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/nvmem-provider.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
@@ -80,6 +81,8 @@ struct rockchip_otp {
 	void __iomem *base;
 	struct reset_control *rst;
 	const struct rockchip_data *data;
+	/* Serializes access to the OTP controller state machine */
+	struct mutex mutex;
 	struct clk_bulk_data clks[];
 };
 
@@ -272,6 +275,8 @@ static int rockchip_otp_read(void *context, unsigned int offset,
 	if (!otp->data || !otp->data->reg_read)
 		return -EINVAL;
 
+	guard(mutex)(&otp->mutex);
+
 	ret = clk_bulk_prepare_enable(otp->data->num_clks, otp->clks);
 	if (ret < 0) {
 		dev_err(otp->dev, "failed to prepare/enable clks\n");
@@ -431,6 +436,11 @@ static int rockchip_otp_probe(struct platform_device *pdev)
 
 	otp->data = data;
 	otp->dev = dev;
+
+	ret = devm_mutex_init(dev, &otp->mutex);
+	if (ret)
+		return ret;
+
 	otp->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(otp->base))
 		return dev_err_probe(dev, PTR_ERR(otp->base),

-- 
2.54.0



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

* [PATCH 2/4] dt-bindings: nvmem: layouts: Add Rockchip OTP CPUID layout
  2026-09-01 15:33 [PATCH 0/4] nvmem: Derive Rockchip MAC addresses from the OTP CPU ID Alexey Charkov
  2026-09-01 15:33 ` [PATCH 1/4] nvmem: rockchip-otp: Serialize reads Alexey Charkov
@ 2026-09-01 15:33 ` Alexey Charkov
  2026-09-01 15:33 ` [PATCH 3/4] nvmem: layouts: Add Rockchip OTP CPUID layout driver Alexey Charkov
  2026-09-01 15:33 ` [PATCH 4/4] arm64: dts: rockchip: Derive GMAC MAC addresses from OTP on RK3576 Alexey Charkov
  3 siblings, 0 replies; 11+ messages in thread
From: Alexey Charkov @ 2026-09-01 15:33 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Miquel Raynal,
	Finley Xiao, Greg Kroah-Hartman
  Cc: devicetree, linux-kernel, linux-rockchip, linux-arm-kernel,
	Alexey Charkov

Rockchip SoCs ship with a unique CPU ID programmed into their internal OTP
memory, and Rockchip bootloaders derive Ethernet MAC addresses from it so
that boards with no dedicated storage for one still get a stable address.

Describe that derivation as an NVMEM layout, so that the resulting
addresses become available through the standard nvmem "mac-address" cell
whether or not the firmware got a chance to patch them into the device
tree. Keep the compatible SoC specific, as the location of the CPU ID
within the OTP memory differs between SoCs.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
 .../bindings/nvmem/layouts/nvmem-layout.yaml       |  1 +
 .../nvmem/layouts/rockchip,rk3576-otp-cpuid.yaml   | 73 ++++++++++++++++++++++
 MAINTAINERS                                        |  6 ++
 3 files changed, 80 insertions(+)

diff --git a/Documentation/devicetree/bindings/nvmem/layouts/nvmem-layout.yaml b/Documentation/devicetree/bindings/nvmem/layouts/nvmem-layout.yaml
index 382507060651..ab94dbb41aac 100644
--- a/Documentation/devicetree/bindings/nvmem/layouts/nvmem-layout.yaml
+++ b/Documentation/devicetree/bindings/nvmem/layouts/nvmem-layout.yaml
@@ -21,6 +21,7 @@ oneOf:
   - $ref: fixed-layout.yaml
   - $ref: kontron,sl28-vpd.yaml
   - $ref: onie,tlv-layout.yaml
+  - $ref: rockchip,rk3576-otp-cpuid.yaml
   - $ref: u-boot,env.yaml
 
 properties:
diff --git a/Documentation/devicetree/bindings/nvmem/layouts/rockchip,rk3576-otp-cpuid.yaml b/Documentation/devicetree/bindings/nvmem/layouts/rockchip,rk3576-otp-cpuid.yaml
new file mode 100644
index 000000000000..85153d480950
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/layouts/rockchip,rk3576-otp-cpuid.yaml
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/nvmem/layouts/rockchip,rk3576-otp-cpuid.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVMEM layout of the CPU ID in Rockchip OTP memory
+
+maintainers:
+  - Alexey Charkov <alchark@flipper.net>
+
+description: |
+  Rockchip SoCs are shipped with a unique CPU ID programmed into their
+  internal OTP memory. Rockchip bootloaders derive Ethernet MAC addresses
+  from it, so that boards which have no dedicated storage for a MAC address
+  still get a stable one. The addresses are computed by hashing the lowercase
+  hexadecimal representation of the CPU ID with SHA-256 and taking the first
+  six octets of the digest, with the multicast bit cleared and the locally
+  administered bit set.
+
+  The location of the CPU ID within the OTP memory differs between SoCs,
+  hence the SoC specific compatible.
+
+select: false
+
+properties:
+  compatible:
+    const: rockchip,rk3576-otp-cpuid
+
+  mac-address:
+    type: object
+    description:
+      MAC address derived from the CPU ID. The first argument of the phandle
+      selects one of the two addresses that can be derived (can be 0 or 1).
+
+    properties:
+      "#nvmem-cell-cells":
+        const: 1
+
+    additionalProperties: false
+
+required:
+  - compatible
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/rockchip,rk3576-cru.h>
+    #include <dt-bindings/reset/rockchip,rk3576-cru.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        otp@2a580000 {
+            compatible = "rockchip,rk3576-otp";
+            reg = <0x0 0x2a580000 0x0 0x400>;
+            clocks = <&cru CLK_OTPC_NS>, <&cru PCLK_OTPC_NS>,
+                     <&cru CLK_OTP_PHY_G>;
+            clock-names = "otp", "apb_pclk", "phy";
+            resets = <&cru SRST_OTPC_NS>, <&cru SRST_P_OTPC_NS>;
+            reset-names = "otp", "apb";
+
+            nvmem-layout {
+                compatible = "rockchip,rk3576-otp-cpuid";
+
+                otp_mac_address: mac-address {
+                    #nvmem-cell-cells = <1>;
+                };
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index b91655b34f0e..b35b3677bf0b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23713,6 +23713,12 @@ F:	Documentation/userspace-api/media/v4l/metafmt-rkisp1.rst
 F:	drivers/media/platform/rockchip/rkisp1
 F:	include/uapi/linux/rkisp1-config.h
 
+ROCKCHIP OTP CPUID NVMEM LAYOUT DRIVER
+M:	Alexey Charkov <alchark@flipper.net>
+L:	linux-rockchip@lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/nvmem/layouts/rockchip,rk3576-otp-cpuid.yaml
+
 ROCKCHIP RK3568 RANDOM NUMBER GENERATOR SUPPORT
 M:	Daniel Golle <daniel@makrotopia.org>
 M:	Aurelien Jarno <aurelien@aurel32.net>

-- 
2.54.0



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

* [PATCH 3/4] nvmem: layouts: Add Rockchip OTP CPUID layout driver
  2026-09-01 15:33 [PATCH 0/4] nvmem: Derive Rockchip MAC addresses from the OTP CPU ID Alexey Charkov
  2026-09-01 15:33 ` [PATCH 1/4] nvmem: rockchip-otp: Serialize reads Alexey Charkov
  2026-09-01 15:33 ` [PATCH 2/4] dt-bindings: nvmem: layouts: Add Rockchip OTP CPUID layout Alexey Charkov
@ 2026-09-01 15:33 ` Alexey Charkov
  2026-09-02  9:40   ` Miquel Raynal
  2026-09-01 15:33 ` [PATCH 4/4] arm64: dts: rockchip: Derive GMAC MAC addresses from OTP on RK3576 Alexey Charkov
  3 siblings, 1 reply; 11+ messages in thread
From: Alexey Charkov @ 2026-09-01 15:33 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Miquel Raynal,
	Finley Xiao, Greg Kroah-Hartman
  Cc: devicetree, linux-kernel, linux-rockchip, linux-arm-kernel,
	Alexey Charkov

Rockchip SoCs customarily use the CPU ID programmed into their on-chip OTP
memory to derive stable Ethernet MAC addresses even when a board doesn't
otherwise have dedicated storage for those. The derivation depends on the
particular bootloader implementation (e.g. it is done by upstream U-Boot,
which patches the derived MAC addresses at runtime into the device tree it
hands to the kernel). Using less featureful bootloaders, such as direct
boot to Linux from SPL, leaves the kernel with only a random MAC address
instead, even though everything required for the derivation is equally
available to Linux as it is to U-Boot.

Reproduce the same derivation in the kernel and expose the result as an
nvmem cell named "mac-address", so that of_get_mac_address() picks it up
through its standard nvmem fallback. The address index comes from the DT
phandle argument, which lets both interfaces of a dual Ethernet board
share a single cell.

Enable the layout by default on Rockchip, as consumers of its cells would
otherwise defer their probe indefinitely.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
 MAINTAINERS                                |   1 +
 drivers/nvmem/layouts/Kconfig              |  13 ++++
 drivers/nvmem/layouts/Makefile             |   1 +
 drivers/nvmem/layouts/rockchip-otp-cpuid.c | 119 +++++++++++++++++++++++++++++
 4 files changed, 134 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b35b3677bf0b..ae98e1fc6121 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23718,6 +23718,7 @@ M:	Alexey Charkov <alchark@flipper.net>
 L:	linux-rockchip@lists.infradead.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/nvmem/layouts/rockchip,rk3576-otp-cpuid.yaml
+F:	drivers/nvmem/layouts/rockchip-otp-cpuid.c
 
 ROCKCHIP RK3568 RANDOM NUMBER GENERATOR SUPPORT
 M:	Daniel Golle <daniel@makrotopia.org>
diff --git a/drivers/nvmem/layouts/Kconfig b/drivers/nvmem/layouts/Kconfig
index 5e586dfebe47..6e2511ac6f7e 100644
--- a/drivers/nvmem/layouts/Kconfig
+++ b/drivers/nvmem/layouts/Kconfig
@@ -26,6 +26,19 @@ config NVMEM_LAYOUT_ONIE_TLV
 
 	  If unsure, say N.
 
+config NVMEM_LAYOUT_ROCKCHIP_OTP_CPUID
+	tristate "Rockchip OTP CPU ID layout support"
+	default ARCH_ROCKCHIP
+	select CRYPTO_LIB_SHA256
+	help
+	  Say Y here if you want to expose the MAC addresses that Rockchip
+	  bootloaders derive from the CPU ID programmed into the OTP memory of
+	  Rockchip SoCs. Boards which have no other source of MAC addresses
+	  need this to get stable ones when the bootloader does not patch them
+	  into the device tree.
+
+	  If unsure, say N.
+
 config NVMEM_LAYOUT_U_BOOT_ENV
 	tristate "U-Boot environment variables layout"
 	select CRC32
diff --git a/drivers/nvmem/layouts/Makefile b/drivers/nvmem/layouts/Makefile
index dd6c6c70b1a9..a0ade4c22c79 100644
--- a/drivers/nvmem/layouts/Makefile
+++ b/drivers/nvmem/layouts/Makefile
@@ -6,4 +6,5 @@
 obj-$(CONFIG_NVMEM_LAYOUTS) += fixed-layout.o
 obj-$(CONFIG_NVMEM_LAYOUT_SL28_VPD) += sl28vpd.o
 obj-$(CONFIG_NVMEM_LAYOUT_ONIE_TLV) += onie-tlv.o
+obj-$(CONFIG_NVMEM_LAYOUT_ROCKCHIP_OTP_CPUID) += rockchip-otp-cpuid.o
 obj-$(CONFIG_NVMEM_LAYOUT_U_BOOT_ENV) += u-boot-env.o
diff --git a/drivers/nvmem/layouts/rockchip-otp-cpuid.c b/drivers/nvmem/layouts/rockchip-otp-cpuid.c
new file mode 100644
index 000000000000..61f509c4a8cf
--- /dev/null
+++ b/drivers/nvmem/layouts/rockchip-otp-cpuid.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-FileCopyrightText: 2026 Flipper FZCO
+/*
+ * NVMEM layout for the CPU ID in Rockchip OTP memory
+ */
+
+#include <crypto/sha2.h>
+#include <linux/device-id/of.h>
+#include <linux/etherdevice.h>
+#include <linux/hex.h>
+#include <linux/module.h>
+#include <linux/nvmem-provider.h>
+#include <linux/of.h>
+#include <uapi/linux/if_ether.h>
+
+#define ROCKCHIP_CPUID_LEN	16
+
+struct rockchip_cpuid_data {
+	unsigned int offset;
+};
+
+static int rockchip_cpuid_mac_pp(void *priv, const char *id, int index,
+				 unsigned int offset, void *buf, size_t bytes)
+{
+	char cpuid[ROCKCHIP_CPUID_LEN * 2];
+	u8 digest[SHA256_DIGEST_SIZE];
+	u8 *mac = buf;
+
+	if (bytes != ROCKCHIP_CPUID_LEN)
+		return -EINVAL;
+
+	if (index < 0 || index > 1)
+		return -EINVAL;
+
+	/* The buffer still holds the raw CPU ID at this point */
+	bin2hex(cpuid, mac, ROCKCHIP_CPUID_LEN);
+
+	sha256(cpuid, sizeof(cpuid), digest);
+
+	memcpy(mac, digest, ETH_ALEN);
+	mac[0] &= 0xfe;		/* clear the multicast bit */
+	mac[0] |= 0x02;		/* set the locally administered bit */
+	mac[5] ^= index;
+
+	if (!is_valid_ether_addr(mac))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int rockchip_cpuid_add_cells(struct nvmem_layout *layout)
+{
+	const struct rockchip_cpuid_data *data;
+	struct nvmem_cell_info info = {0};
+	struct device_node *layout_np;
+	int ret;
+
+	data = of_device_get_match_data(&layout->dev);
+	if (!data)
+		return -EINVAL;
+
+	layout_np = of_nvmem_layout_get_container(layout->nvmem);
+	if (!layout_np)
+		return -ENOENT;
+
+	info.name = "mac-address";
+	info.offset = data->offset;
+	info.raw_len = ROCKCHIP_CPUID_LEN;
+	info.bytes = ETH_ALEN;
+	info.read_post_process = rockchip_cpuid_mac_pp;
+	info.np = of_get_child_by_name(layout_np, info.name);
+
+	of_node_put(layout_np);
+
+	ret = nvmem_add_one_cell(layout->nvmem, &info);
+	if (ret)
+		of_node_put(info.np);
+
+	return ret;
+}
+
+static int rockchip_cpuid_probe(struct nvmem_layout *layout)
+{
+	layout->add_cells = rockchip_cpuid_add_cells;
+
+	return nvmem_layout_register(layout);
+}
+
+static void rockchip_cpuid_remove(struct nvmem_layout *layout)
+{
+	nvmem_layout_unregister(layout);
+}
+
+static const struct rockchip_cpuid_data rk3576_cpuid_data = {
+	.offset = 0x0a,
+};
+
+static const struct of_device_id rockchip_cpuid_of_match_table[] = {
+	{
+		.compatible = "rockchip,rk3576-otp-cpuid",
+		.data = &rk3576_cpuid_data,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, rockchip_cpuid_of_match_table);
+
+static struct nvmem_layout_driver rockchip_cpuid_layout = {
+	.driver = {
+		.name = "rockchip-otp-cpuid-layout",
+		.of_match_table = rockchip_cpuid_of_match_table,
+	},
+	.probe = rockchip_cpuid_probe,
+	.remove = rockchip_cpuid_remove,
+};
+module_nvmem_layout_driver(rockchip_cpuid_layout);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alexey Charkov <alchark@flipper.net>");
+MODULE_DESCRIPTION("NVMEM layout driver for the CPU ID in Rockchip OTP memory");

-- 
2.54.0



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

* [PATCH 4/4] arm64: dts: rockchip: Derive GMAC MAC addresses from OTP on RK3576
  2026-09-01 15:33 [PATCH 0/4] nvmem: Derive Rockchip MAC addresses from the OTP CPU ID Alexey Charkov
                   ` (2 preceding siblings ...)
  2026-09-01 15:33 ` [PATCH 3/4] nvmem: layouts: Add Rockchip OTP CPUID layout driver Alexey Charkov
@ 2026-09-01 15:33 ` Alexey Charkov
  3 siblings, 0 replies; 11+ messages in thread
From: Alexey Charkov @ 2026-09-01 15:33 UTC (permalink / raw)
  To: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Miquel Raynal,
	Finley Xiao, Greg Kroah-Hartman
  Cc: devicetree, linux-kernel, linux-rockchip, linux-arm-kernel,
	Alexey Charkov

Rockchip SoCs derive stable MAC addresses from the CPU ID in OTP memory,
which a bootloader would normally process and patch the live device tree
based on it. This depends on the particular bootloader implementation
though, and the derivation itself is not described in the device tree.

Add explicit nvmem layout for the CPU ID derived MAC addresses on RK3576,
so that any OS can implement the same derivation without depending on the
bootloader used.

Boards which store a MAC address of their own can override the reference
with a cell of their choosing.

Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
 arch/arm64/boot/dts/rockchip/rk3576.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
index b0c0d3c8b1b1..0012b45ef426 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
@@ -1845,6 +1845,8 @@ gmac0: ethernet@2a220000 {
 			interrupts = <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "macirq", "eth_wake_irq";
+			nvmem-cells = <&otp_mac_address 0>;
+			nvmem-cell-names = "mac-address";
 			power-domains = <&power RK3576_PD_SDGMAC>;
 			resets = <&cru SRST_A_GMAC0>;
 			reset-names = "stmmaceth";
@@ -1893,6 +1895,8 @@ gmac1: ethernet@2a230000 {
 			interrupts = <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
 			interrupt-names = "macirq", "eth_wake_irq";
+			nvmem-cells = <&otp_mac_address 1>;
+			nvmem-cell-names = "mac-address";
 			power-domains = <&power RK3576_PD_SDGMAC>;
 			resets = <&cru SRST_A_GMAC1>;
 			reset-names = "stmmaceth";
@@ -2131,6 +2135,14 @@ soc_tsadc_trim: soc-tsadc-trim@64 {
 				reg = <0x64 0x2>;
 				bits = <0 10>;
 			};
+
+			nvmem-layout {
+				compatible = "rockchip,rk3576-otp-cpuid";
+
+				otp_mac_address: mac-address {
+					#nvmem-cell-cells = <1>;
+				};
+			};
 		};
 
 		sai0: sai@2a600000 {

-- 
2.54.0



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

* Re: [PATCH 1/4] nvmem: rockchip-otp: Serialize reads
  2026-09-01 15:33 ` [PATCH 1/4] nvmem: rockchip-otp: Serialize reads Alexey Charkov
@ 2026-09-02  9:10   ` Miquel Raynal
  2026-09-02  9:24     ` Alexey Charkov
  0 siblings, 1 reply; 11+ messages in thread
From: Miquel Raynal @ 2026-09-02  9:10 UTC (permalink / raw)
  To: Alexey Charkov
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Finley Xiao,
	Greg Kroah-Hartman, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel, stable

On 01/09/2026 at 19:33:11 +04, Alexey Charkov <alchark@flipper.net> wrote:

> The OTP controller is driven through a single set of registers holding a
> state machine which has to be stepped through for every word read, yet
> nothing keeps two readers out of each other's way. Concurrent reads
> interleave, and the outcome is either a reader bailing out:
>
>   rockchip-otp 2a580000.otp: timeout during read setup
>
> or, worse, one of them silently taking delivery of the other's data.
>
> Reading two cells in parallel from userspace on RK3576 reproduces both
> within 150 iterations - 53 read errors and 9 corrupted results, the latter
> either losing their first word or, in one case, ending in the two bytes
> which belong to the other reader's cell - whereas the same reads issued
> sequentially never fail. Concurrency is not hypothetical here, as six
> thermal sensors source their trim values from the OTP and reach the driver
> straight from asynchronous driver probing.
>
> Guard the read path with a mutex. Reads are the only way into the hardware,
> as the driver registers no write callback, and they always run in process
> context, so a plain mutex spanning the whole clock-enable, read,
> clock-disable sequence is enough.
>
> Fixes: 755864feb729 ("nvmem: add Rockchip OTP driver")
> Cc: stable@vger.kernel.org
> Signed-off-by: Alexey Charkov <alchark@flipper.net>

Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>



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

* Re: [PATCH 1/4] nvmem: rockchip-otp: Serialize reads
  2026-09-02  9:10   ` Miquel Raynal
@ 2026-09-02  9:24     ` Alexey Charkov
  2026-09-02 10:17       ` Miquel Raynal
  0 siblings, 1 reply; 11+ messages in thread
From: Alexey Charkov @ 2026-09-02  9:24 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Finley Xiao,
	Greg Kroah-Hartman, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel, stable

On Wed, Sep 2, 2026 at 1:10 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> On 01/09/2026 at 19:33:11 +04, Alexey Charkov <alchark@flipper.net> wrote:
>
> > The OTP controller is driven through a single set of registers holding a
> > state machine which has to be stepped through for every word read, yet
> > nothing keeps two readers out of each other's way. Concurrent reads
> > interleave, and the outcome is either a reader bailing out:
> >
> >   rockchip-otp 2a580000.otp: timeout during read setup
> >
> > or, worse, one of them silently taking delivery of the other's data.
> >
> > Reading two cells in parallel from userspace on RK3576 reproduces both
> > within 150 iterations - 53 read errors and 9 corrupted results, the latter
> > either losing their first word or, in one case, ending in the two bytes
> > which belong to the other reader's cell - whereas the same reads issued
> > sequentially never fail. Concurrency is not hypothetical here, as six
> > thermal sensors source their trim values from the OTP and reach the driver
> > straight from asynchronous driver probing.
> >
> > Guard the read path with a mutex. Reads are the only way into the hardware,
> > as the driver registers no write callback, and they always run in process
> > context, so a plain mutex spanning the whole clock-enable, read,
> > clock-disable sequence is enough.
> >
> > Fixes: 755864feb729 ("nvmem: add Rockchip OTP driver")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Alexey Charkov <alchark@flipper.net>
>
> Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>

Thanks for your review Miquel!

Sashiko complained about mixing a scope-based guard into a function
with goto-based error handling, so I am replacing the guard(mutex)
with explicit lock and unlock calls for v2. There won't be any
semantic change though, so if you don't mind I'd like to carry your
tag into the v2 version.

Best regards,
Alexey


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

* Re: [PATCH 3/4] nvmem: layouts: Add Rockchip OTP CPUID layout driver
  2026-09-01 15:33 ` [PATCH 3/4] nvmem: layouts: Add Rockchip OTP CPUID layout driver Alexey Charkov
@ 2026-09-02  9:40   ` Miquel Raynal
  0 siblings, 0 replies; 11+ messages in thread
From: Miquel Raynal @ 2026-09-02  9:40 UTC (permalink / raw)
  To: Alexey Charkov
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Finley Xiao,
	Greg Kroah-Hartman, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel

On 01/09/2026 at 19:33:13 +04, Alexey Charkov <alchark@flipper.net> wrote:

> Rockchip SoCs customarily use the CPU ID programmed into their on-chip OTP
> memory to derive stable Ethernet MAC addresses even when a board doesn't
> otherwise have dedicated storage for those. The derivation depends on the
> particular bootloader implementation (e.g. it is done by upstream U-Boot,
> which patches the derived MAC addresses at runtime into the device tree it
> hands to the kernel). Using less featureful bootloaders, such as direct
> boot to Linux from SPL, leaves the kernel with only a random MAC address
> instead, even though everything required for the derivation is equally
> available to Linux as it is to U-Boot.
>
> Reproduce the same derivation in the kernel and expose the result as an
> nvmem cell named "mac-address", so that of_get_mac_address() picks it up
> through its standard nvmem fallback. The address index comes from the DT
> phandle argument, which lets both interfaces of a dual Ethernet board
> share a single cell.
>
> Enable the layout by default on Rockchip, as consumers of its cells would
> otherwise defer their probe indefinitely.
>
> Signed-off-by: Alexey Charkov <alchark@flipper.net>

Quick review on my side, looks good to me.

Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>


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

* Re: [PATCH 1/4] nvmem: rockchip-otp: Serialize reads
  2026-09-02  9:24     ` Alexey Charkov
@ 2026-09-02 10:17       ` Miquel Raynal
  2026-09-02 12:40         ` Alexey Charkov
  0 siblings, 1 reply; 11+ messages in thread
From: Miquel Raynal @ 2026-09-02 10:17 UTC (permalink / raw)
  To: Alexey Charkov
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Finley Xiao,
	Greg Kroah-Hartman, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel, stable

On 02/09/2026 at 13:24:00 +04, Alexey Charkov <alchark@flipper.net> wrote:

> On Wed, Sep 2, 2026 at 1:10 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>>
>> On 01/09/2026 at 19:33:11 +04, Alexey Charkov <alchark@flipper.net> wrote:
>>
>> > The OTP controller is driven through a single set of registers holding a
>> > state machine which has to be stepped through for every word read, yet
>> > nothing keeps two readers out of each other's way. Concurrent reads
>> > interleave, and the outcome is either a reader bailing out:
>> >
>> >   rockchip-otp 2a580000.otp: timeout during read setup
>> >
>> > or, worse, one of them silently taking delivery of the other's data.
>> >
>> > Reading two cells in parallel from userspace on RK3576 reproduces both
>> > within 150 iterations - 53 read errors and 9 corrupted results, the latter
>> > either losing their first word or, in one case, ending in the two bytes
>> > which belong to the other reader's cell - whereas the same reads issued
>> > sequentially never fail. Concurrency is not hypothetical here, as six
>> > thermal sensors source their trim values from the OTP and reach the driver
>> > straight from asynchronous driver probing.
>> >
>> > Guard the read path with a mutex. Reads are the only way into the hardware,
>> > as the driver registers no write callback, and they always run in process
>> > context, so a plain mutex spanning the whole clock-enable, read,
>> > clock-disable sequence is enough.
>> >
>> > Fixes: 755864feb729 ("nvmem: add Rockchip OTP driver")
>> > Cc: stable@vger.kernel.org
>> > Signed-off-by: Alexey Charkov <alchark@flipper.net>
>>
>> Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
>
> Thanks for your review Miquel!
>
> Sashiko complained about mixing a scope-based guard into a function
> with goto-based error handling, so I am replacing the guard(mutex)
> with explicit lock and unlock calls for v2. There won't be any
> semantic change though, so if you don't mind I'd like to carry your
> tag into the v2 version.

Of course.

I haven't seen Sashiko's answer but isn't the goal of guards to just be
released whatever the actual return path?

Thanks,
Miquèl


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

* Re: [PATCH 1/4] nvmem: rockchip-otp: Serialize reads
  2026-09-02 10:17       ` Miquel Raynal
@ 2026-09-02 12:40         ` Alexey Charkov
  2026-09-03  8:06           ` Miquel Raynal
  0 siblings, 1 reply; 11+ messages in thread
From: Alexey Charkov @ 2026-09-02 12:40 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Finley Xiao,
	Greg Kroah-Hartman, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel, stable

On Wed, Sep 2, 2026 at 2:17 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> On 02/09/2026 at 13:24:00 +04, Alexey Charkov <alchark@flipper.net> wrote:
>
> > On Wed, Sep 2, 2026 at 1:10 PM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >>
> >> On 01/09/2026 at 19:33:11 +04, Alexey Charkov <alchark@flipper.net> wrote:
> >>
> >> > The OTP controller is driven through a single set of registers holding a
> >> > state machine which has to be stepped through for every word read, yet
> >> > nothing keeps two readers out of each other's way. Concurrent reads
> >> > interleave, and the outcome is either a reader bailing out:
> >> >
> >> >   rockchip-otp 2a580000.otp: timeout during read setup
> >> >
> >> > or, worse, one of them silently taking delivery of the other's data.
> >> >
> >> > Reading two cells in parallel from userspace on RK3576 reproduces both
> >> > within 150 iterations - 53 read errors and 9 corrupted results, the latter
> >> > either losing their first word or, in one case, ending in the two bytes
> >> > which belong to the other reader's cell - whereas the same reads issued
> >> > sequentially never fail. Concurrency is not hypothetical here, as six
> >> > thermal sensors source their trim values from the OTP and reach the driver
> >> > straight from asynchronous driver probing.
> >> >
> >> > Guard the read path with a mutex. Reads are the only way into the hardware,
> >> > as the driver registers no write callback, and they always run in process
> >> > context, so a plain mutex spanning the whole clock-enable, read,
> >> > clock-disable sequence is enough.
> >> >
> >> > Fixes: 755864feb729 ("nvmem: add Rockchip OTP driver")
> >> > Cc: stable@vger.kernel.org
> >> > Signed-off-by: Alexey Charkov <alchark@flipper.net>
> >>
> >> Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
> >
> > Thanks for your review Miquel!
> >
> > Sashiko complained about mixing a scope-based guard into a function
> > with goto-based error handling, so I am replacing the guard(mutex)
> > with explicit lock and unlock calls for v2. There won't be any
> > semantic change though, so if you don't mind I'd like to carry your
> > tag into the v2 version.
>
> Of course.

Thank you!

> I haven't seen Sashiko's answer but isn't the goal of guards to just be
> released whatever the actual return path?

I believe it's based on the guidance in [1]. In this particular case,
gotos don't jump outside the scope where I put the guard, so the
scope-based guard is still correct. However, stylistically, it is
indeed uncommon to see scope-based guards in functions using gotos.
Explicit lock/unlock is easy in this case, anyway.

[1] https://elixir.bootlin.com/linux/v7.2.2/source/include/linux/cleanup.h#L148-L153

Best regards,
Alexey


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

* Re: [PATCH 1/4] nvmem: rockchip-otp: Serialize reads
  2026-09-02 12:40         ` Alexey Charkov
@ 2026-09-03  8:06           ` Miquel Raynal
  0 siblings, 0 replies; 11+ messages in thread
From: Miquel Raynal @ 2026-09-03  8:06 UTC (permalink / raw)
  To: Alexey Charkov
  Cc: Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Heiko Stuebner, Michael Walle, Finley Xiao,
	Greg Kroah-Hartman, devicetree, linux-kernel, linux-rockchip,
	linux-arm-kernel, stable

Hi Alexey,

>> I haven't seen Sashiko's answer but isn't the goal of guards to just be
>> released whatever the actual return path?
>
> I believe it's based on the guidance in [1]. In this particular case,
> gotos don't jump outside the scope where I put the guard, so the
> scope-based guard is still correct. However, stylistically, it is
> indeed uncommon to see scope-based guards in functions using gotos.
> Explicit lock/unlock is easy in this case, anyway.
>
> [1] https://elixir.bootlin.com/linux/v7.2.2/source/include/linux/cleanup.h#L148-L153

I never read that paragraph before, but okay, makes sense.

Thanks,
Miquèl


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

end of thread, other threads:[~2026-09-03  8:06 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 15:33 [PATCH 0/4] nvmem: Derive Rockchip MAC addresses from the OTP CPU ID Alexey Charkov
2026-09-01 15:33 ` [PATCH 1/4] nvmem: rockchip-otp: Serialize reads Alexey Charkov
2026-09-02  9:10   ` Miquel Raynal
2026-09-02  9:24     ` Alexey Charkov
2026-09-02 10:17       ` Miquel Raynal
2026-09-02 12:40         ` Alexey Charkov
2026-09-03  8:06           ` Miquel Raynal
2026-09-01 15:33 ` [PATCH 2/4] dt-bindings: nvmem: layouts: Add Rockchip OTP CPUID layout Alexey Charkov
2026-09-01 15:33 ` [PATCH 3/4] nvmem: layouts: Add Rockchip OTP CPUID layout driver Alexey Charkov
2026-09-02  9:40   ` Miquel Raynal
2026-09-01 15:33 ` [PATCH 4/4] arm64: dts: rockchip: Derive GMAC MAC addresses from OTP on RK3576 Alexey Charkov

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