Re: [PATCH v2 3/4] nvmem: layouts: Add Rockchip OTP CPUID layout driver
From: Srinivas Kandagatla
Date: Mon Sep 14 2026 - 18:27:30 EST
On 9/2/26 2:07 PM, Alexey Charkov 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.
>
> Reviewed-by: Miquel Raynal <miquel.raynal@xxxxxxxxxxx>
> Signed-off-by: Alexey Charkov <alchark@xxxxxxxxxxx>
> ---
> 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 f3d07ce7b3c8..73e0531445be 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23727,6 +23727,7 @@ M: Alexey Charkov <alchark@xxxxxxxxxxx>
> L: linux-rockchip@xxxxxxxxxxxxxxxxxxx
> 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@xxxxxxxxxxxxxx>
> 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>
...
> +
> +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;
isn't this a dead check?
> +
> + 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;
same here, this is dead check as we can never reach to this point
without matching compatible.
> +
> + 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;
> +}
> +...
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Alexey Charkov <alchark@xxxxxxxxxxx>");
> +MODULE_DESCRIPTION("NVMEM layout driver for the CPU ID in Rockchip OTP memory");
>