--- /dev/null
+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.
--- /dev/null
+// 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");
+}
--- /dev/null
+/* 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 */