// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Siemens AG, 2025 */ #include #include #include #include #include #include "iot2050.h" #define IOT2050_INFO_MAGIC 0x20502050 #define IOT2050_UUID_STR_LEN (32) struct iot2050_info { u32 magic; u16 size; char name[20 + 1]; char serial[16 + 1]; char mlfb[18 + 1]; char uuid[IOT2050_UUID_STR_LEN + 1]; char a5e[18 + 1]; u8 mac_addr_cnt; u8 mac_addr[8][ARP_HLEN]; char seboot_version[40 + 1]; u8 padding[3]; u32 ddr_size_mb; } __packed; /** * struct sysinfo_iot2050_priv - sysinfo private data * @info: iot2050 board info */ struct sysinfo_iot2050_priv { struct iot2050_info *info; u8 uuid_smbios[16]; }; static int sysinfo_iot2050_detect(struct udevice *dev) { struct sysinfo_iot2050_priv *priv = dev_get_priv(dev); if (!priv->info || priv->info->magic != IOT2050_INFO_MAGIC) return -EFAULT; return 0; } static int sysinfo_iot2050_get_str(struct udevice *dev, int id, size_t size, char *val) { struct sysinfo_iot2050_priv *priv = dev_get_priv(dev); switch (id) { case BOARD_NAME: case SYSID_SM_BASEBOARD_VERSION: strlcpy(val, priv->info->name, size); break; case SYSID_SM_SYSTEM_SERIAL: strlcpy(val, priv->info->serial, size); break; case BOARD_MLFB: case SYSID_SM_SYSTEM_VERSION: strlcpy(val, priv->info->mlfb, size); break; case BOARD_UUID: strlcpy(val, priv->info->uuid, size); break; case BOARD_A5E: case SYSID_SM_BASEBOARD_PRODUCT: strlcpy(val, priv->info->a5e, size); break; case BOARD_SEBOOT_VER: case SYSID_PRIOR_STAGE_VERSION: strlcpy(val, priv->info->seboot_version, size); break; default: return -EINVAL; }; val[size - 1] = '\0'; return 0; } static int sysinfo_iot2050_get_int(struct udevice *dev, int id, int *val) { struct sysinfo_iot2050_priv *priv = dev_get_priv(dev); switch (id) { case SYSID_BOARD_RAM_SIZE_MB: *val = priv->info->ddr_size_mb; return 0; default: return -EINVAL; }; } static int sysinfo_iot2050_get_data(struct udevice *dev, int id, void **data, size_t *size) { struct sysinfo_iot2050_priv *priv = dev_get_priv(dev); switch (id) { case SYSID_SM_SYSTEM_UUID: *data = priv->uuid_smbios; *size = 16; return 0; default: return -EINVAL; }; } static int sysinfo_iot2050_get_item_count(struct udevice *dev, int id) { struct sysinfo_iot2050_priv *priv = dev_get_priv(dev); switch (id) { case SYSID_BOARD_MAC_ADDR: return priv->info->mac_addr_cnt; default: return -EINVAL; }; } static int sysinfo_iot2050_get_data_by_index(struct udevice *dev, int id, int index, void **data, size_t *size) { struct sysinfo_iot2050_priv *priv = dev_get_priv(dev); switch (id) { case SYSID_BOARD_MAC_ADDR: if (index >= priv->info->mac_addr_cnt) return -EINVAL; *data = priv->info->mac_addr[index]; *size = ARP_HLEN; return 0; default: return -EINVAL; }; } static const struct sysinfo_ops sysinfo_iot2050_ops = { .detect = sysinfo_iot2050_detect, .get_str = sysinfo_iot2050_get_str, .get_int = sysinfo_iot2050_get_int, .get_data = sysinfo_iot2050_get_data, .get_item_count = sysinfo_iot2050_get_item_count, .get_data_by_index = sysinfo_iot2050_get_data_by_index, }; /** * @brief Convert the IOT2050 UUID string to the SMBIOS format * * @param uuid_raw The IOT2050 UUID string parsed from the eeprom * @param uuid_smbios The buffer to hold the SMBIOS formatted UUID */ static void sysinfo_iot2050_convert_uuid(const char *uuid_iot2050, u8 *uuid_smbios) { char uuid_rfc4122_str[IOT2050_UUID_STR_LEN + 4 + 1] = {0}; char *tmp = uuid_rfc4122_str; for (int i = 0; i < 16; i++) { memcpy(tmp, uuid_iot2050 + i * 2, 2); tmp += 2; if (i == 3 || i == 5 || i == 7 || i == 9) *tmp++ = '-'; } uuid_str_to_bin(uuid_rfc4122_str, uuid_smbios, UUID_STR_FORMAT_GUID); } static int sysinfo_iot2050_probe(struct udevice *dev) { struct sysinfo_iot2050_priv *priv = dev_get_priv(dev); unsigned long offset; offset = dev_read_u32_default(dev, "offset", TI_SRAM_SCRATCH_BOARD_EEPROM_START); priv->info = (struct iot2050_info *)offset; sysinfo_iot2050_convert_uuid(priv->info->uuid, priv->uuid_smbios); return 0; } static const struct udevice_id sysinfo_iot2050_ids[] = { { .compatible = "siemens,sysinfo-iot2050" }, { /* sentinel */ } }; U_BOOT_DRIVER(sysinfo_iot2050) = { .name = "sysinfo_iot2050", .id = UCLASS_SYSINFO, .of_match = sysinfo_iot2050_ids, .ops = &sysinfo_iot2050_ops, .priv_auto = sizeof(struct sysinfo_iot2050_priv), .probe = sysinfo_iot2050_probe, };