[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