Linux device trees describe calibration and configuration values as cells in the Allwinner Security ID block. U-Boot has an NVMEM consumer API but no provider for the direct-read SID variants.
Add a read-only misc driver for the A10, A20, A83T, D1, A64, H5 and H6 register layouts so firmware consumers can use those standard nvmem-cells descriptions. Signed-off-by: James Hilliard <[email protected]> --- MAINTAINERS | 1 + drivers/misc/Kconfig | 10 ++++ drivers/misc/Makefile | 1 + drivers/misc/sunxi_sid.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 95b1f3b5ab3..e724357419b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -702,6 +702,7 @@ F: arch/arm/include/asm/arch-sunxi/ F: arch/arm/mach-sunxi/ F: board/sunxi/ F: drivers/clk/sunxi/ +F: drivers/misc/sunxi_sid.c F: drivers/phy/allwinner/ F: drivers/pinctrl/sunxi/ F: drivers/video/sunxi/ diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 681d5f28ea4..6f6456120d0 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -51,6 +51,16 @@ config NVMEM up hardware configuration data such as MAC addresses and calibration settings. +config SUNXI_SID + bool "Allwinner Security ID NVMEM support" + depends on ARCH_SUNXI + depends on MISC + select NVMEM + help + Enable read-only access to the Security ID efuse area found in + Allwinner SoCs. This allows consumers to use the standard nvmem-cells + properties from Linux-compatible device trees. + config SPL_NVMEM bool "NVMEM support in SPL" help diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index f20c989ffc6..3ec2bc2b201 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o obj-$(CONFIG_STM32_RCC) += stm32_rcc.o +obj-$(CONFIG_SUNXI_SID) += sunxi_sid.o obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o obj-$(CONFIG_TEGRA_CAR) += tegra_car.o diff --git a/drivers/misc/sunxi_sid.c b/drivers/misc/sunxi_sid.c new file mode 100644 index 00000000000..86a1379d07e --- /dev/null +++ b/drivers/misc/sunxi_sid.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Allwinner Security ID NVMEM provider + * + * Copyright (C) 2026 James Hilliard <[email protected]> + */ + +#include <dm.h> +#include <dm/read.h> +#include <misc.h> +#include <asm/io.h> + +struct sunxi_sid_data { + unsigned int value_offset; + unsigned int size; +}; + +struct sunxi_sid_priv { + const struct sunxi_sid_data *data; + u8 __iomem *base; +}; + +static int sunxi_sid_read(struct udevice *dev, int offset, void *buf, int size) +{ + struct sunxi_sid_priv *priv = dev_get_priv(dev); + u8 *out = buf; + int i; + + if (offset < 0 || !buf || size < 0 || offset > priv->data->size || + size > priv->data->size - offset) + return -EINVAL; + + for (i = 0; i < size; i++) { + unsigned int byte_offset = offset + i; + u32 value; + + value = readl(priv->base + priv->data->value_offset + + (byte_offset & ~3)); + out[i] = value >> (8 * (byte_offset & 3)); + } + + return size; +} + +static int sunxi_sid_probe(struct udevice *dev) +{ + struct sunxi_sid_priv *priv = dev_get_priv(dev); + + priv->data = (const void *)dev_get_driver_data(dev); + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -EINVAL; + + return 0; +} + +static const struct misc_ops sunxi_sid_ops = { + .read = sunxi_sid_read, +}; + +static const struct sunxi_sid_data sun4i_a10_sid_data = { + .size = 0x10, +}; + +static const struct sunxi_sid_data sun7i_a20_sid_data = { + .size = 0x200, +}; + +static const struct sunxi_sid_data sun50i_a64_sid_data = { + .value_offset = 0x200, + .size = 0x100, +}; + +static const struct sunxi_sid_data sun50i_h6_sid_data = { + .value_offset = 0x200, + .size = 0x200, +}; + +static const struct udevice_id sunxi_sid_ids[] = { + { + .compatible = "allwinner,sun4i-a10-sid", + .data = (ulong)&sun4i_a10_sid_data, + }, + { + .compatible = "allwinner,sun7i-a20-sid", + .data = (ulong)&sun7i_a20_sid_data, + }, + { + .compatible = "allwinner,sun8i-a83t-sid", + .data = (ulong)&sun50i_a64_sid_data, + }, + { + .compatible = "allwinner,sun20i-d1-sid", + .data = (ulong)&sun50i_a64_sid_data, + }, + { + .compatible = "allwinner,sun50i-a64-sid", + .data = (ulong)&sun50i_a64_sid_data, + }, + { + .compatible = "allwinner,sun50i-h5-sid", + .data = (ulong)&sun50i_a64_sid_data, + }, + { + .compatible = "allwinner,sun50i-h6-sid", + .data = (ulong)&sun50i_h6_sid_data, + }, + { } +}; + +U_BOOT_DRIVER(sunxi_sid) = { + .name = "sunxi_sid", + .id = UCLASS_MISC, + .of_match = sunxi_sid_ids, + .probe = sunxi_sid_probe, + .ops = &sunxi_sid_ops, + .priv_auto = sizeof(struct sunxi_sid_priv), +}; -- 2.53.0
