soc/intel/alderlake: Add ADL-P 4+4 with 28W TDP
[coreboot.git] / src / drivers / ocp / dmi / smbios.c
blob0ac33347519b050d24c371ab66a03b11ba256152
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <console/console.h>
4 #include <device/device.h>
5 #include <drivers/ipmi/ipmi_ops.h>
6 #include <delay.h>
7 #include <cpu/x86/mp.h>
8 #include <timer.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <soc/soc_util.h>
12 #include <soc/util.h>
13 #include <smbios.h>
14 #include <types.h>
16 #include "ocp_dmi.h"
18 #define PPIN_STR_LEN 17
20 struct fru_info_str fru_strings = {0};
21 /* The spec defines only at most 2 sockets */
22 msr_t xeon_sp_ppin[2] = {0};
23 static bool remote_ppin_done = false;
26 * Update SMBIOS type 0 ec version.
27 * For OCP platforms, BMC version is used to represent ec version.
28 * Refer to IPMI v2.0 spec, minor revision is defined as BCD encoded,
29 * format it accordingly.
31 void smbios_ec_revision(uint8_t *ec_major_revision, uint8_t *ec_minor_revision)
33 uint8_t bmc_major_revision, bmc_minor_revision;
35 ipmi_bmc_version(&bmc_major_revision, &bmc_minor_revision);
36 *ec_major_revision = bmc_major_revision & 0x7f; /* bit[6:0] Major Firmware Revision */
37 *ec_minor_revision = ((bmc_minor_revision / 16) * 10) + (bmc_minor_revision % 16);
40 /* Override SMBIOS type 1 data. */
41 const char *smbios_system_manufacturer(void)
43 if (fru_strings.prod_info.manufacturer != NULL)
44 return (const char *)fru_strings.prod_info.manufacturer;
45 else
46 return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER;
49 const char *smbios_system_product_name(void)
51 if (fru_strings.board_info.product_name != NULL)
52 return (const char *)fru_strings.prod_info.product_name;
53 else
54 return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME;
57 const char *smbios_system_serial_number(void)
59 if (fru_strings.prod_info.serial_number != NULL)
60 return (const char *)fru_strings.prod_info.serial_number;
61 else
62 return CONFIG_MAINBOARD_SERIAL_NUMBER;
65 const char *smbios_system_version(void)
67 if (fru_strings.prod_info.product_version != NULL)
68 return (const char *)fru_strings.prod_info.product_version;
69 else
70 return CONFIG_MAINBOARD_VERSION;
73 /* Override SMBIOS type 1 uuid from the value from BMC. */
74 void smbios_system_set_uuid(u8 *uuid)
76 ipmi_get_system_guid(CONFIG_BMC_KCS_BASE, uuid);
79 /* Override SMBIOS type 2 data. */
80 const char *smbios_mainboard_version(void)
82 if (fru_strings.board_info.part_number != NULL)
83 return (const char *)fru_strings.board_info.part_number;
84 else
85 return CONFIG_MAINBOARD_VERSION;
88 const char *smbios_mainboard_manufacturer(void)
90 if (fru_strings.board_info.manufacturer != NULL)
91 return (const char *)fru_strings.board_info.manufacturer;
92 else
93 return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER;
96 const char *smbios_mainboard_product_name(void)
98 if (fru_strings.board_info.product_name != NULL)
99 return (const char *)fru_strings.board_info.product_name;
100 else
101 return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME;
104 const char *smbios_mainboard_serial_number(void)
106 if (fru_strings.board_info.serial_number != NULL)
107 return (const char *)fru_strings.board_info.serial_number;
108 else
109 return CONFIG_MAINBOARD_SERIAL_NUMBER;
112 /* Override SMBIOS type 2 and 3 asset_tag data. */
113 const char *smbios_mainboard_asset_tag(void)
115 if (fru_strings.prod_info.asset_tag != NULL)
116 return (const char *)fru_strings.prod_info.asset_tag;
117 else
118 return "";
121 /* Override SMBIOS type 3 data. */
122 smbios_enclosure_type smbios_mainboard_enclosure_type(void)
124 /* SMBIOS System Enclosure or Chassis Types are values from 0 to 20h. */
125 if (fru_strings.chassis_info.chassis_type <= 0x20)
126 return fru_strings.chassis_info.chassis_type;
127 else
128 return SMBIOS_ENCLOSURE_RACK_MOUNT_CHASSIS;
131 const char *smbios_chassis_version(void)
133 if (fru_strings.chassis_info.chassis_partnumber != NULL)
134 return fru_strings.chassis_info.chassis_partnumber;
135 else
136 return "";
139 const char *smbios_chassis_serial_number(void)
141 if (fru_strings.chassis_info.serial_number != NULL)
142 return fru_strings.chassis_info.serial_number;
143 else
144 return "";
147 /* Override SMBIOS type 4 processor serial numbers from FRU Chassis custom data. */
148 const char *smbios_processor_serial_number(void)
150 /* For now type 4 only creates for one CPU, so it can only write the serial number
151 * of CPU0.
153 if (*fru_strings.chassis_info.chassis_custom != NULL)
154 return *fru_strings.chassis_info.chassis_custom;
155 else
156 return "";
159 static void read_remote_ppin(void *data)
161 *(msr_t *)data = read_msr_ppin();
162 remote_ppin_done = true;
165 static void wait_for_remote_ppin(void)
167 struct stopwatch sw;
169 stopwatch_init_msecs_expire(&sw, 500);
170 while (!stopwatch_expired(&sw)) {
171 if (remote_ppin_done)
172 break;
173 mdelay(100);
175 if (stopwatch_expired(&sw))
176 printk(BIOS_ERR, "Wait for read_remote_ppin() timeout\n");
179 int smbios_add_oem_string(u8 *start, const char *str)
181 int i = 1;
182 char *p = (char *)start;
184 if (*str == '\0')
185 return 0;
187 for (;;) {
188 if (!*p) {
189 strcpy(p, str);
190 p += strlen(str);
191 *p++ = '\0';
192 *p++ = '\0';
193 return i;
196 p += strlen(p)+1;
197 i++;
201 /* When the most significant 4 bits of PPIN hi/lo are 0, add '0' to the beginning */
202 static void ppin_string_fixup(int i, char *ppin)
204 if ((xeon_sp_ppin[i].hi & 0xf0000000) == 0) {
205 if ((xeon_sp_ppin[i].lo & 0xf0000000) == 0)
206 snprintf(ppin, PPIN_STR_LEN, "0%x0%x", xeon_sp_ppin[i].hi,
207 xeon_sp_ppin[i].lo);
208 else
209 snprintf(ppin, PPIN_STR_LEN, "0%x%x", xeon_sp_ppin[i].hi,
210 xeon_sp_ppin[i].lo);
211 } else if ((xeon_sp_ppin[i].lo & 0xf0000000) == 0) {
212 snprintf(ppin, PPIN_STR_LEN, "%x0%x", xeon_sp_ppin[i].hi, xeon_sp_ppin[i].lo);
213 } else {
214 snprintf(ppin, PPIN_STR_LEN, "%x%x", xeon_sp_ppin[i].hi, xeon_sp_ppin[i].lo);
219 * Override SMBIOS type 11 OEM string 1 to string 6, the rest are project dependent
220 * and can be added in the mainboard code.
222 void ocp_oem_smbios_strings(struct device *dev, struct smbios_type11 *t)
224 char ppin[PPIN_STR_LEN];
226 /* Add OEM string 1 to 4 */
227 if (fru_strings.board_info.custom_count > 0 &&
228 *fru_strings.board_info.board_custom != NULL)
229 t->count = smbios_add_oem_string(t->eos, *fru_strings.board_info.board_custom);
230 else
231 t->count = smbios_add_oem_string(t->eos, TBF);
233 if (fru_strings.prod_info.custom_count > 0 &&
234 *fru_strings.prod_info.product_custom != NULL)
235 t->count = smbios_add_oem_string(t->eos, *fru_strings.prod_info.product_custom);
236 else
237 t->count = smbios_add_oem_string(t->eos, TBF);
239 if (fru_strings.prod_info.custom_count > 1 &&
240 *(fru_strings.prod_info.product_custom + 1) != NULL)
241 t->count = smbios_add_oem_string(t->eos,
242 *(fru_strings.prod_info.product_custom + 1));
243 else
244 t->count = smbios_add_oem_string(t->eos, TBF);
246 if (fru_strings.prod_info.custom_count > 2 &&
247 *(fru_strings.prod_info.product_custom + 2) != NULL) {
248 t->count = smbios_add_oem_string(t->eos,
249 *(fru_strings.prod_info.product_custom + 2));
250 } else {
251 t->count = smbios_add_oem_string(t->eos, TBF);
254 /* Add CPU0 PPIN to OEM string 5 */
255 xeon_sp_ppin[0] = read_msr_ppin();
256 ppin_string_fixup(0, ppin);
257 t->count = smbios_add_oem_string(t->eos, ppin);
259 /* Add CPU1 PPIN to OEM string 6 */
260 if (CONFIG_MAX_SOCKET == 2 && CONFIG(PARALLEL_MP_AP_WORK)) {
261 /* Read the last CPU MSR */
262 if (mp_run_on_aps(read_remote_ppin, (void *)&xeon_sp_ppin[1],
263 get_platform_thread_count() - 1, 100 * USECS_PER_MSEC) !=
264 CB_SUCCESS) {
265 printk(BIOS_ERR, "Failed to read remote PPIN.\n");
266 t->count = smbios_add_oem_string(t->eos, TBF);
267 } else {
268 /* Wait for read_remote_ppin() to finish because it's executed
269 in parallel */
270 wait_for_remote_ppin();
271 ppin_string_fixup(1, ppin);
272 t->count = smbios_add_oem_string(t->eos, ppin);
274 } else {
275 t->count = smbios_add_oem_string(t->eos, "0000");