1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2020 Google LLC
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #include <dm.h>
8 #include <smbios_plat.h>
9 #include <sysinfo.h>
10 
11 /* platform information storage */
12 struct processor_info processor_info;
13 struct cache_info cache_info[SYSINFO_CACHE_LVL_MAX];
14 struct sysinfo_plat sysinfo_smbios_p = {
15 	/* Processor Information */
16 	.processor = &processor_info,
17 	/* Cache Information */
18 	.cache = &cache_info[0],
19 };
20 
21 /* structure for smbios private data storage */
22 struct sysinfo_plat_priv {
23 	struct processor_info *t4;
24 	struct smbios_type7 t7[SYSINFO_CACHE_LVL_MAX];
25 	u16 cache_handles[SYSINFO_CACHE_LVL_MAX];
26 	u8 cache_level;
27 };
28 
smbios_cache_info_dump(struct smbios_type7 * cache_info)29 static void smbios_cache_info_dump(struct smbios_type7 *cache_info)
30 {
31 	log_debug("SMBIOS Type 7 (Cache Information):\n");
32 	log_debug("Cache Configuration: 0x%04x\n", cache_info->config.data);
33 	log_debug("Maximum Cache Size: %u KB\n", cache_info->max_size.data);
34 	log_debug("Installed Size: %u KB\n", cache_info->inst_size.data);
35 	log_debug("Supported SRAM Type: 0x%04x\n",
36 		  cache_info->supp_sram_type.data);
37 	log_debug("Current SRAM Type: 0x%04x\n",
38 		  cache_info->curr_sram_type.data);
39 	log_debug("Cache Speed: %u\n", cache_info->speed);
40 	log_debug("Error Correction Type: %u\n", cache_info->err_corr_type);
41 	log_debug("System Cache Type: %u\n", cache_info->sys_cache_type);
42 	log_debug("Associativity: %u\n", cache_info->associativity);
43 	log_debug("Maximum Cache Size 2: %u KB\n", cache_info->max_size2.data);
44 	log_debug("Installed Cache Size 2: %u KB\n",
45 		  cache_info->inst_size2.data);
46 }
47 
48 /* weak function for the platforms not yet supported */
sysinfo_get_cache_info(u8 level,struct cache_info * cache_info)49 __weak int sysinfo_get_cache_info(u8 level, struct cache_info *cache_info)
50 {
51 	return -ENOSYS;
52 }
53 
sysinfo_get_processor_info(struct processor_info * pinfo)54 __weak int sysinfo_get_processor_info(struct processor_info *pinfo)
55 {
56 	return -ENOSYS;
57 }
58 
sysinfo_cache_info_default(struct cache_info * ci)59 void sysinfo_cache_info_default(struct cache_info *ci)
60 {
61 	memset(ci, 0, sizeof(*ci));
62 	ci->config.data = SMBIOS_CACHE_LOCATE_UNKNOWN | SMBIOS_CACHE_OP_UND;
63 	ci->supp_sram_type.fields.unknown = 1;
64 	ci->curr_sram_type.fields.unknown = 1;
65 	ci->speed = SMBIOS_CACHE_SPEED_UNKNOWN;
66 	ci->err_corr_type = SMBIOS_CACHE_ERRCORR_UNKNOWN;
67 	ci->cache_type = SMBIOS_CACHE_SYSCACHE_TYPE_UNKNOWN;
68 }
69 
sysinfo_plat_detect(struct udevice * dev)70 static int sysinfo_plat_detect(struct udevice *dev)
71 {
72 	return 0;
73 }
74 
sysinfo_plat_get_str(struct udevice * dev,int id,size_t size,char * val)75 static int sysinfo_plat_get_str(struct udevice *dev, int id,
76 				size_t size, char *val)
77 {
78 	struct sysinfo_plat_priv *priv = dev_get_priv(dev);
79 	const char *str = NULL;
80 
81 	switch (id) {
82 	case SYSID_SM_PROCESSOR_MANUFACT:
83 		str = priv->t4->manufacturer;
84 		break;
85 	default:
86 		break;
87 	}
88 
89 	if (!str)
90 		return -ENOSYS;
91 
92 	strlcpy(val, str, size);
93 
94 	return 0;
95 }
96 
sysinfo_plat_get_int(struct udevice * dev,int id,int * val)97 static int sysinfo_plat_get_int(struct udevice *dev, int id, int *val)
98 {
99 	struct sysinfo_plat_priv *priv = dev_get_priv(dev);
100 	u8 i;
101 
102 	if (id >= SYSID_SM_CACHE_INFO_START &&
103 	    id <= SYSID_SM_CACHE_INFO_END) {
104 		/* For smbios type 7 */
105 		for (i = 0; i < priv->cache_level; i++) {
106 			switch (id - i) {
107 			case SYSID_SM_CACHE_MAX_SIZE:
108 				*val = priv->t7[i].max_size.data;
109 				return 0;
110 			case SYSID_SM_CACHE_INST_SIZE:
111 				*val = priv->t7[i].inst_size.data;
112 				return 0;
113 			case SYSID_SM_CACHE_SCACHE_TYPE:
114 				*val = priv->t7[i].sys_cache_type;
115 				return 0;
116 			case SYSID_SM_CACHE_ASSOC:
117 				*val = priv->t7[i].associativity;
118 				return 0;
119 			case SYSID_SM_CACHE_MAX_SIZE2:
120 				*val = priv->t7[i].max_size2.data;
121 				return 0;
122 			case SYSID_SM_CACHE_INST_SIZE2:
123 				*val = priv->t7[i].inst_size2.data;
124 				return 0;
125 			default:
126 				break;
127 			}
128 		}
129 		return -ENOSYS;
130 	}
131 
132 	switch (id) {
133 	case SYSID_SM_PROCESSOR_CORE_CNT:
134 		*val = priv->t4->core_count;
135 		break;
136 	case SYSID_SM_PROCESSOR_CORE_EN:
137 		*val = priv->t4->core_enabled;
138 		break;
139 	case SYSID_SM_PROCESSOR_CHARA:
140 		*val = priv->t4->characteristics;
141 		break;
142 	case SYSID_SM_CACHE_LEVEL:
143 		if (!priv->cache_level)	/* No cache detected */
144 			return -ENOSYS;
145 		*val = priv->cache_level - 1;
146 		break;
147 	default:
148 		return -ENOSYS;
149 	}
150 
151 	return 0;
152 }
153 
sysinfo_plat_get_data(struct udevice * dev,int id,void ** buf,size_t * size)154 static int sysinfo_plat_get_data(struct udevice *dev, int id, void **buf,
155 				 size_t *size)
156 {
157 	struct sysinfo_plat_priv *priv = dev_get_priv(dev);
158 
159 	switch (id) {
160 	case SYSID_SM_PROCESSOR_ID:
161 		*buf = priv->t4->id;
162 		*size = sizeof(priv->t4->id);
163 		break;
164 	case SYSID_SM_CACHE_HANDLE:
165 		*buf = &priv->cache_handles[0];
166 		*size = sizeof(priv->cache_handles);
167 		break;
168 	default:
169 		return -EOPNOTSUPP;
170 	}
171 	return 0;
172 }
173 
sysinfo_plat_probe(struct udevice * dev)174 static int sysinfo_plat_probe(struct udevice *dev)
175 {
176 	struct sysinfo_plat_priv *priv = dev_get_priv(dev);
177 	struct sysinfo_plat *plat = &sysinfo_smbios_p;
178 	u8 level;
179 
180 	if (!sysinfo_get_processor_info(plat->processor))
181 		priv->t4 = plat->processor;
182 
183 	for (level = 0; level < SYSINFO_CACHE_LVL_MAX; level++) {
184 		struct cache_info *pcache = plat->cache + level;
185 
186 		if (sysinfo_get_cache_info(level, pcache))
187 			break; /* no more levels */
188 
189 		/*
190 		 * Fill in the SMBIOS type 7 structure,
191 		 * skip the header members (type, length, handle),
192 		 * and the ones in DT smbios node.
193 		 */
194 		priv->t7[level].sys_cache_type = pcache->cache_type;
195 		priv->t7[level].associativity = pcache->associativity;
196 
197 		if (pcache->max_size > SMBIOS_CACHE_SIZE_EXT_KB) {
198 			priv->t7[level].max_size.data = 0xFFFF;
199 			priv->t7[level].max_size2.fields.size =
200 				pcache->max_size / 64;
201 			priv->t7[level].max_size2.fields.granu =
202 				SMBIOS_CACHE_GRANU_64K;
203 		} else {
204 			priv->t7[level].max_size.fields.size = pcache->max_size;
205 			priv->t7[level].max_size.fields.granu =
206 				SMBIOS_CACHE_GRANU_1K;
207 			priv->t7[level].max_size2.data = 0;
208 		}
209 		if (pcache->inst_size > SMBIOS_CACHE_SIZE_EXT_KB) {
210 			priv->t7[level].inst_size.data = 0xFFFF;
211 			priv->t7[level].inst_size2.fields.size =
212 				pcache->inst_size / 64;
213 			priv->t7[level].inst_size2.fields.granu =
214 				SMBIOS_CACHE_GRANU_64K;
215 		} else {
216 			priv->t7[level].inst_size.fields.size =
217 				pcache->inst_size;
218 			priv->t7[level].inst_size.fields.granu =
219 				SMBIOS_CACHE_GRANU_1K;
220 			priv->t7[level].inst_size2.data = 0;
221 		}
222 		smbios_cache_info_dump(&priv->t7[level]);
223 	}
224 	if (!level) /* no cache detected */
225 		return -ENOSYS;
226 
227 	priv->cache_level = level;
228 
229 	return 0;
230 }
231 
232 static const struct udevice_id sysinfo_smbios_ids[] = {
233 	{ .compatible = "u-boot,sysinfo-smbios" },
234 	{ /* sentinel */ }
235 };
236 
237 static const struct sysinfo_ops sysinfo_smbios_ops = {
238 	.detect = sysinfo_plat_detect,
239 	.get_str = sysinfo_plat_get_str,
240 	.get_int = sysinfo_plat_get_int,
241 	.get_data = sysinfo_plat_get_data,
242 };
243 
244 U_BOOT_DRIVER(sysinfo_smbios) = {
245 	.name           = "sysinfo_smbios",
246 	.id             = UCLASS_SYSINFO,
247 	.of_match       = sysinfo_smbios_ids,
248 	.ops		= &sysinfo_smbios_ops,
249 	.priv_auto	= sizeof(struct sysinfo_plat_priv),
250 	.probe		= sysinfo_plat_probe,
251 };
252