blob: 579a9f4711dbb86b021d334ab773956dd712fe7c [file] [log] [blame]
Baocheng Su1d7a0ca2025-02-18 10:36:13 +08001// 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
18struct 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 */
37struct sysinfo_iot2050_priv {
38 struct iot2050_info *info;
39 u8 uuid_smbios[16];
40};
41
42static 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
52static 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
88static 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
101static 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
116static 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
128static 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
146static 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 */
161static 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
176static 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
190static const struct udevice_id sysinfo_iot2050_ids[] = {
191 { .compatible = "siemens,sysinfo-iot2050" },
192 { /* sentinel */ }
193};
194
195U_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};