imx: kontron: Add common function to get HW UIDs from OTPs

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@kontron.de>
This commit is contained in:
Frieder Schrempf
2025-11-04 13:54:26 +01:00
committed by Fabio Estevam
parent 0089270b45
commit f00b09abbf
4 changed files with 116 additions and 0 deletions

View File

@@ -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.

View File

@@ -0,0 +1 @@
obj-$(CONFIG_KONTRON_HW_UID) += hw-uid.o

View File

@@ -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");
}

View File

@@ -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 */