[PATCH 2/4] imx: kontron: Add common function to get HW UIDs from OTPs
Frieder Schrempf
frieder at fris.de
Tue Nov 4 13:54:26 CET 2025
From: Frieder Schrempf <frieder.schrempf at kontron.de>
The factory provides a CPU UID in the OTPs and the SoM module
and the carrier board might provide additional UIDs in the GP
registers of the OTPs.
Provide a common function to load UIDs from arbitrary OTP
registers and generate a serial number string that is saved
in the "serial#" env variable.
Signed-off-by: Frieder Schrempf <frieder.schrempf at kontron.de>
---
board/kontron/common/Kconfig | 14 +++++++
board/kontron/common/Makefile | 1 +
board/kontron/common/hw-uid.c | 75 +++++++++++++++++++++++++++++++++++
board/kontron/common/hw-uid.h | 26 ++++++++++++
4 files changed, 116 insertions(+)
create mode 100644 board/kontron/common/Kconfig
create mode 100644 board/kontron/common/Makefile
create mode 100644 board/kontron/common/hw-uid.c
create mode 100644 board/kontron/common/hw-uid.h
diff --git a/board/kontron/common/Kconfig b/board/kontron/common/Kconfig
new file mode 100644
index 00000000000..d581006c203
--- /dev/null
+++ b/board/kontron/common/Kconfig
@@ -0,0 +1,14 @@
+menuconfig KONTRON_HW_UID
+ bool "Enable reading Kontron HW UID from OTP fuses"
+ help
+ Enable support for reading Kontron hardware UIDs from OTP fuse registers.
+ The UIDs are factory-programmed for SoMs and boards and are printed to the
+ console and used as serial numbers if this option is enabled.
+
+menuconfig KONTRON_HW_UID_USE_SOC_FALLBACK
+ bool "Use the unique ID of the SoC as fallback serial number"
+ depends on KONTRON_HW_UID
+ default n
+ help
+ Enable the fallback to the UID of the SoC programmed by the SoC
+ manufacturer if no Kontron UID is found in the OTP fuses.
diff --git a/board/kontron/common/Makefile b/board/kontron/common/Makefile
new file mode 100644
index 00000000000..634744dc542
--- /dev/null
+++ b/board/kontron/common/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_KONTRON_HW_UID) += hw-uid.o
diff --git a/board/kontron/common/hw-uid.c b/board/kontron/common/hw-uid.c
new file mode 100644
index 00000000000..5358b1dfcf1
--- /dev/null
+++ b/board/kontron/common/hw-uid.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2024 Kontron Electronics GmbH
+ */
+
+#include <linux/errno.h>
+#include <compiler.h>
+#include <asm/io.h>
+#include <env.h>
+#include <string.h>
+#include <vsprintf.h>
+
+#include "hw-uid.h"
+
+int get_serial_str_from_otp(struct uid_otp_loc loc, char *str, size_t str_len)
+{
+ u64 uid;
+ int ret;
+
+ if (loc.len < 1 || loc.len > 2) {
+ printf("Invalid number of UID OTP registers set!\n");
+ return -EINVAL;
+ }
+
+ uid = readl(loc.addr);
+
+ if (loc.len == 2)
+ uid |= (u64)readl(loc.addr + 0x4) << 32;
+
+ if (!uid)
+ return -ENOENT;
+
+ if (uid) {
+ switch (loc.format) {
+ case UID_OTP_FORMAT_DEC:
+ ret = snprintf(str, str_len, "%010llu", uid);
+ break;
+ case UID_OTP_FORMAT_HEX:
+ ret = snprintf(str, str_len, "%016llX", uid);
+ break;
+ }
+ if (ret < 0 || ret >= str_len) {
+ printf("Failed to convert UID!\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+void get_serial_number(struct uid_otp_loc *locs, unsigned int num)
+{
+ char serial_string[17];
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < num; i++) {
+ ret = get_serial_str_from_otp(locs[i], serial_string, sizeof(serial_string));
+ if (ret == 0)
+ break;
+ }
+
+ /* No valid UID in the OTP fuses, skip. */
+ if (ret) {
+ printf("Serial Number: None\n");
+ return;
+ }
+
+ printf("Serial Number: %s (%s)\n", serial_string, locs[i].desc);
+
+ if (!env_get("serial#"))
+ env_set("serial#", serial_string);
+ else if (strcmp(env_get("serial#"), serial_string))
+ printf("Warning: mismatch of UIDs in env and OTPs!\n");
+}
diff --git a/board/kontron/common/hw-uid.h b/board/kontron/common/hw-uid.h
new file mode 100644
index 00000000000..7eaf2cc9b6c
--- /dev/null
+++ b/board/kontron/common/hw-uid.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2024 Kontron Electronics GmbH
+ */
+
+#ifndef _KONTRON_HW_UID_H
+#define _KONTRON_HW_UID_H
+
+#include <compiler.h>
+#include <stddef.h>
+
+enum {
+ UID_OTP_FORMAT_DEC = 0,
+ UID_OTP_FORMAT_HEX,
+};
+
+struct uid_otp_loc {
+ u32 *addr;
+ size_t len;
+ unsigned int format;
+ char *desc;
+};
+
+void get_serial_number(struct uid_otp_loc *locs, unsigned int num);
+
+#endif /* _KONTRON_HW_UID_H */
--
2.51.0
More information about the U-Boot
mailing list