1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) Siemens AG, 2025
4  */
5 
6 #include <dm.h>
7 #include <sysinfo.h>
8 #include <net.h>
9 #include <u-boot/uuid.h>
10 #include <asm/arch/hardware.h>
11 
12 #include "iot2050.h"
13 
14 #define IOT2050_INFO_MAGIC		0x20502050
15 
16 #define IOT2050_UUID_STR_LEN		(32)
17 
18 struct iot2050_info {
19 	u32 magic;
20 	u16 size;
21 	char name[20 + 1];
22 	char serial[16 + 1];
23 	char mlfb[18 + 1];
24 	char uuid[IOT2050_UUID_STR_LEN + 1];
25 	char a5e[18 + 1];
26 	u8 mac_addr_cnt;
27 	u8 mac_addr[8][ARP_HLEN];
28 	char seboot_version[40 + 1];
29 	u8 padding[3];
30 	u32 ddr_size_mb;
31 } __packed;
32 
33 /**
34  * struct sysinfo_iot2050_priv - sysinfo private data
35  * @info: iot2050 board info
36  */
37 struct sysinfo_iot2050_priv {
38 	struct iot2050_info *info;
39 	u8 uuid_smbios[16];
40 };
41 
sysinfo_iot2050_detect(struct udevice * dev)42 static int sysinfo_iot2050_detect(struct udevice *dev)
43 {
44 	struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
45 
46 	if (!priv->info || priv->info->magic != IOT2050_INFO_MAGIC)
47 		return -EFAULT;
48 
49 	return 0;
50 }
51 
sysinfo_iot2050_get_str(struct udevice * dev,int id,size_t size,char * val)52 static int sysinfo_iot2050_get_str(struct udevice *dev, int id, size_t size,
53 				   char *val)
54 {
55 	struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
56 
57 	switch (id) {
58 	case BOARD_NAME:
59 	case SYSID_SM_BASEBOARD_VERSION:
60 		strlcpy(val, priv->info->name, size);
61 		break;
62 	case SYSID_SM_SYSTEM_SERIAL:
63 		strlcpy(val, priv->info->serial, size);
64 		break;
65 	case BOARD_MLFB:
66 	case SYSID_SM_SYSTEM_VERSION:
67 		strlcpy(val, priv->info->mlfb, size);
68 		break;
69 	case BOARD_UUID:
70 		strlcpy(val, priv->info->uuid, size);
71 		break;
72 	case BOARD_A5E:
73 	case SYSID_SM_BASEBOARD_PRODUCT:
74 		strlcpy(val, priv->info->a5e, size);
75 		break;
76 	case BOARD_SEBOOT_VER:
77 	case SYSID_PRIOR_STAGE_VERSION:
78 		strlcpy(val, priv->info->seboot_version, size);
79 		break;
80 	default:
81 		return -EINVAL;
82 	};
83 
84 	val[size - 1] = '\0';
85 	return 0;
86 }
87 
sysinfo_iot2050_get_int(struct udevice * dev,int id,int * val)88 static int sysinfo_iot2050_get_int(struct udevice *dev, int id, int *val)
89 {
90 	struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
91 
92 	switch (id) {
93 	case SYSID_BOARD_RAM_SIZE_MB:
94 		*val = priv->info->ddr_size_mb;
95 		return 0;
96 	default:
97 		return -EINVAL;
98 	};
99 }
100 
sysinfo_iot2050_get_data(struct udevice * dev,int id,void ** data,size_t * size)101 static int sysinfo_iot2050_get_data(struct udevice *dev, int id, void **data,
102 				    size_t *size)
103 {
104 	struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
105 
106 	switch (id) {
107 	case SYSID_SM_SYSTEM_UUID:
108 		*data = priv->uuid_smbios;
109 		*size = 16;
110 		return 0;
111 	default:
112 		return -EINVAL;
113 	};
114 }
115 
sysinfo_iot2050_get_item_count(struct udevice * dev,int id)116 static int sysinfo_iot2050_get_item_count(struct udevice *dev, int id)
117 {
118 	struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
119 
120 	switch (id) {
121 	case SYSID_BOARD_MAC_ADDR:
122 		return priv->info->mac_addr_cnt;
123 	default:
124 		return -EINVAL;
125 	};
126 }
127 
sysinfo_iot2050_get_data_by_index(struct udevice * dev,int id,int index,void ** data,size_t * size)128 static int sysinfo_iot2050_get_data_by_index(struct udevice *dev, int id,
129 					     int index, void **data,
130 					     size_t *size)
131 {
132 	struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
133 
134 	switch (id) {
135 	case SYSID_BOARD_MAC_ADDR:
136 		if (index >= priv->info->mac_addr_cnt)
137 			return -EINVAL;
138 		*data = priv->info->mac_addr[index];
139 		*size = ARP_HLEN;
140 		return 0;
141 	default:
142 		return -EINVAL;
143 	};
144 }
145 
146 static const struct sysinfo_ops sysinfo_iot2050_ops = {
147 	.detect = sysinfo_iot2050_detect,
148 	.get_str = sysinfo_iot2050_get_str,
149 	.get_int = sysinfo_iot2050_get_int,
150 	.get_data = sysinfo_iot2050_get_data,
151 	.get_item_count = sysinfo_iot2050_get_item_count,
152 	.get_data_by_index = sysinfo_iot2050_get_data_by_index,
153 };
154 
155 /**
156  * @brief Convert the IOT2050 UUID string to the SMBIOS format
157  *
158  * @param uuid_raw The IOT2050 UUID string parsed from the eeprom
159  * @param uuid_smbios The buffer to hold the SMBIOS formatted UUID
160  */
sysinfo_iot2050_convert_uuid(const char * uuid_iot2050,u8 * uuid_smbios)161 static void sysinfo_iot2050_convert_uuid(const char *uuid_iot2050,
162 					 u8 *uuid_smbios)
163 {
164 	char uuid_rfc4122_str[IOT2050_UUID_STR_LEN + 4 + 1] = {0};
165 	char *tmp = uuid_rfc4122_str;
166 
167 	for (int i = 0; i < 16; i++) {
168 		memcpy(tmp, uuid_iot2050 + i * 2, 2);
169 		tmp += 2;
170 		if (i == 3 || i == 5 || i == 7 || i == 9)
171 			*tmp++ = '-';
172 	}
173 	uuid_str_to_bin(uuid_rfc4122_str, uuid_smbios, UUID_STR_FORMAT_GUID);
174 }
175 
sysinfo_iot2050_probe(struct udevice * dev)176 static int sysinfo_iot2050_probe(struct udevice *dev)
177 {
178 	struct sysinfo_iot2050_priv *priv = dev_get_priv(dev);
179 	unsigned long offset;
180 
181 	offset = dev_read_u32_default(dev, "offset",
182 				      TI_SRAM_SCRATCH_BOARD_EEPROM_START);
183 	priv->info = (struct iot2050_info *)offset;
184 
185 	sysinfo_iot2050_convert_uuid(priv->info->uuid, priv->uuid_smbios);
186 
187 	return 0;
188 }
189 
190 static const struct udevice_id sysinfo_iot2050_ids[] = {
191 	{ .compatible = "siemens,sysinfo-iot2050" },
192 	{ /* sentinel */ }
193 };
194 
195 U_BOOT_DRIVER(sysinfo_iot2050) = {
196 	.name           = "sysinfo_iot2050",
197 	.id             = UCLASS_SYSINFO,
198 	.of_match       = sysinfo_iot2050_ids,
199 	.ops		= &sysinfo_iot2050_ops,
200 	.priv_auto	= sizeof(struct sysinfo_iot2050_priv),
201 	.probe          = sysinfo_iot2050_probe,
202 };
203