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>
7 #include <cpu/x86/mp.h>
11 #include <soc/soc_util.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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
153 if (*fru_strings
.chassis_info
.chassis_custom
!= NULL
)
154 return *fru_strings
.chassis_info
.chassis_custom
;
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)
169 stopwatch_init_msecs_expire(&sw
, 500);
170 while (!stopwatch_expired(&sw
)) {
171 if (remote_ppin_done
)
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
)
182 char *p
= (char *)start
;
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
,
209 snprintf(ppin
, PPIN_STR_LEN
, "0%x%x", xeon_sp_ppin
[i
].hi
,
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
);
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
);
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
);
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));
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));
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
) !=
265 printk(BIOS_ERR
, "Failed to read remote PPIN.\n");
266 t
->count
= smbios_add_oem_string(t
->eos
, TBF
);
268 /* Wait for read_remote_ppin() to finish because it's executed
270 wait_for_remote_ppin();
271 ppin_string_fixup(1, ppin
);
272 t
->count
= smbios_add_oem_string(t
->eos
, ppin
);
275 t
->count
= smbios_add_oem_string(t
->eos
, "0000");