coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
ramstage.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <console/console.h>
7 #include <drivers/vpd/vpd.h>
9 #include <soc/ramstage.h>
10 #include <soc/soc_util.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <smbios.h>
14 #include <device/pci_def.h>
15 #include <device/pci_ops.h>
16 #include <soc/util.h>
17 #include <hob_iiouds.h>
18 #include <hob_memmap.h>
19 #include <cpxsp_dl_gpio.h>
20 
21 #include "ipmi.h"
22 #include "vpd.h"
23 
24 #define SLOT_ID_LEN 2
25 
26 extern struct fru_info_str fru_strings;
27 static char slot_id_str[SLOT_ID_LEN];
28 
29 /*
30  * Update SMBIOS type 0 ec version.
31  * In deltalake, BMC version is used to represent ec version.
32  * In current version of OpenBMC, it follows IPMI v2.0 to define minor revision as BCD
33  * encoded, so the format of it must be transferred before send to SMBIOS.
34  */
35 void smbios_ec_revision(uint8_t *ec_major_revision, uint8_t *ec_minor_revision)
36 {
37  uint8_t bmc_major_revision, bmc_minor_revision;
38 
39  ipmi_bmc_version(&bmc_major_revision, &bmc_minor_revision);
40  *ec_major_revision = bmc_major_revision & 0x7f; /* bit[6:0] Major Firmware Revision */
41  *ec_minor_revision = ((bmc_minor_revision / 16) * 10) + (bmc_minor_revision % 16);
42 }
43 
44 /* Override SMBIOS 2 Location In Chassis from BMC */
46 {
47  uint8_t slot_id = 0;
48 
49  if (ipmi_get_slot_id(&slot_id) != CB_SUCCESS) {
50  printk(BIOS_ERR, "IPMI get slot_id failed\n");
51  return "";
52  }
53  /* Sanity check, slot_id can only be 1~4 since there are 4 slots in YV3 */
54  if (slot_id < PCIE_CONFIG_A || slot_id > PCIE_CONFIG_D) {
55  printk(BIOS_ERR, "slot_id %d is not between 1~4\n", slot_id);
56  return "";
57  }
58  snprintf(slot_id_str, SLOT_ID_LEN, "%d", slot_id);
59  return slot_id_str;
60 }
61 
62 /* Override SMBIOS type 2 Feature Flags */
64 {
66 }
67 
68 /*
69  * Override SMBIOS type 4 cpu voltage.
70  * BIT7 will set to 1 after value return. If BIT7 is set to 1, the remaining seven
71  * bits of this field are set to contain the processor's current voltage times 10.
72  */
73 unsigned int smbios_cpu_get_voltage(void)
74 {
75  /* This will return 1.6V which is expected value for Delta Lake
76  10h = (1.6 * 10) = 16 */
77  return 0x10;
78 }
79 
80 /* System Slot Socket, Stack, Type and Data bus width Information */
81 typedef struct {
86  const char *slot_designator;
87 } slot_info;
88 
89 /* Array index + 1 would be used as Slot ID */
91  {CSTACK, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0xE8, "SSD1_M2_Data_Drive"},
92  {PSTACK1, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x10, "SSD0_M2_Boot_Drive"},
93  {PSTACK1, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x18, "BB_OCP_NIC"},
94  {PSTACK2, SlotTypePciExpressGen3X16, SlotDataBusWidth16X, 0x00, "1OU_OCP_NIC"},
95  {PSTACK0, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x00, "2OU_JD1_M2_0"},
96  {PSTACK0, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x08, "2OU_JD1_M2_1"},
97  {PSTACK1, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x08, "2OU_JD2_M2_2"},
98  {PSTACK1, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x00, "2OU_JD2_M2_3"},
99  {PSTACK0, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x10, "2OU_JD3_M2_4"},
100  {PSTACK0, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x18, "2OU_JD3_M2_5"},
101  {PSTACK2, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x18, "1OU_JD1_M2_0"},
102  {PSTACK2, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x10, "1OU_JD1_M2_1"},
103  {PSTACK2, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x08, "1OU_JD2_M2_2"},
104  {PSTACK2, SlotTypePciExpressGen3X4, SlotDataBusWidth4X, 0x00, "1OU_JD2_M2_3"},
105 };
106 
107 #define SPD_REGVID_LEN 6
108 /* A 4-digit long number plus a space */
109 static void write_oem_word(uint16_t val, char *str)
110 {
111  snprintf(str, SPD_REGVID_LEN, "%04x ", val);
112 }
113 
114 static void dl_oem_smbios_strings(struct device *dev, struct smbios_type11 *t)
115 {
116  uint8_t pcie_config = 0;
117  const struct SystemMemoryMapHob *hob;
118  char spd_reg_vid[SPD_REGVID_LEN];
119  char empty[1] = "";
120  char *oem_str7 = empty;
121 
122  /* OEM string 1 to 6 */
123  ocp_oem_smbios_strings(dev, t);
124 
125  /* OEM string 7 is the register vendor ID in SPD for each DIMM strung together */
126  hob = get_system_memory_map();
127  assert(hob != NULL);
128  /* There are at most 6 channels and 2 DIMMs per channel, but Delta Lake has 6 DIMMs,
129  e.g. b300 0000 b300 0000 b300 0000 b300 0000 b300 0000 b300 0000 */
130  for (int ch = 0; ch < MAX_CH; ch++) {
131  for (int dimm = 0; dimm < MAX_IMC; dimm++) {
132  write_oem_word(hob->Socket[0].ChannelInfo[ch].DimmInfo[dimm].SPDRegVen,
133  spd_reg_vid);
134  oem_str7 = strconcat(oem_str7, spd_reg_vid);
135  }
136  }
137  t->count = smbios_add_oem_string(t->eos, oem_str7);
138 
139  /* Add OEM string 8 */
140  if (ipmi_get_pcie_config(&pcie_config) == CB_SUCCESS) {
141  switch (pcie_config) {
142  case PCIE_CONFIG_UNKNOWN:
143  t->count = smbios_add_oem_string(t->eos, "0x0: Unknown");
144  break;
145  case PCIE_CONFIG_A:
146  t->count = smbios_add_oem_string(t->eos, "0x1: YV3 Config-A");
147  break;
148  case PCIE_CONFIG_B:
149  t->count = smbios_add_oem_string(t->eos, "0x2: YV3 Config-B");
150  break;
151  case PCIE_CONFIG_C:
152  t->count = smbios_add_oem_string(t->eos, "0x3: YV3 Config-C");
153  break;
154  case PCIE_CONFIG_D:
155  t->count = smbios_add_oem_string(t->eos, "0x4: YV3 Config-D");
156  break;
157  default:
158  t->count = smbios_add_oem_string(t->eos, "Check BMC return data");
159  }
160  } else {
161  printk(BIOS_ERR, "Failed to get IPMI PCIe config\n");
162  }
163 }
164 
165 static const struct port_information smbios_type8_info[] = {
166  {
167  .internal_reference_designator = "JCN18 - CPU MIPI60",
168  .internal_connector_type = CONN_OTHER,
169  .external_reference_designator = "",
170  .external_connector_type = CONN_NONE,
171  .port_type = TYPE_OTHER_PORT
172  },
173  {
174  .internal_reference_designator = "JCN32 - TPM_CONN",
175  .internal_connector_type = CONN_OTHER,
176  .external_reference_designator = "",
177  .external_connector_type = CONN_NONE,
178  .port_type = TYPE_OTHER_PORT
179  },
180  {
181  .internal_reference_designator = "JCN7 - USB type C",
182  .internal_connector_type = CONN_USB_TYPE_C,
183  .external_reference_designator = "",
184  .external_connector_type = CONN_NONE,
185  .port_type = TYPE_USB
186  },
187 };
188 
189 static int create_smbios_type9(int *handle, unsigned long *current)
190 {
191  int index;
192  int length = 0;
193  uint8_t slot_length;
194  uint8_t sec_bus;
195  uint8_t slot_usage;
196  uint8_t pcie_config = 0;
197  uint32_t vendor_device_id;
198  uint8_t stack_busnos[MAX_IIO_STACK];
199  pci_devfn_t pci_dev_slot, pci_dev = 0;
200  unsigned int cap;
201  uint16_t sltcap;
202 
203  if (ipmi_get_pcie_config(&pcie_config) != CB_SUCCESS)
204  printk(BIOS_ERR, "Failed to get IPMI PCIe config\n");
205 
206  for (index = 0; index < ARRAY_SIZE(stack_busnos); index++)
207  stack_busnos[index] = get_stack_busno(index);
208 
209  for (index = 0; index < ARRAY_SIZE(slotinfo); index++) {
210  uint8_t characteristics_1 = 0;
211  uint8_t characteristics_2 = 0;
212 
213  if (pcie_config == PCIE_CONFIG_A) {
214  if (index == 0 || index == 1 || index == 2)
215  printk(BIOS_INFO, "Find Config-A slot: %s\n",
216  slotinfo[index].slot_designator);
217  else
218  continue;
219  }
220  if (pcie_config == PCIE_CONFIG_B) {
221  switch (index) {
222  case 0 ... 2:
223  case 10 ... 13:
224  printk(BIOS_INFO, "Find Config-B slot: %s\n",
225  slotinfo[index].slot_designator);
226  break;
227  default:
228  continue;
229  }
230  }
231  if (pcie_config == PCIE_CONFIG_C) {
232  switch (index) {
233  case 0 ... 1:
234  case 3 ... 9:
235  printk(BIOS_INFO, "Find Config-C slot: %s\n",
236  slotinfo[index].slot_designator);
237  break;
238  default:
239  continue;
240  }
241  }
242  if (pcie_config == PCIE_CONFIG_D) {
243  if (index != 3)
244  printk(BIOS_INFO, "Find Config-D slot: %s\n",
245  slotinfo[index].slot_designator);
246  else
247  continue;
248  }
249 
250  if (slotinfo[index].slot_data_bus_width == SlotDataBusWidth16X)
251  slot_length = SlotLengthLong;
252  else
253  slot_length = SlotLengthShort;
254 
255  pci_dev_slot = PCI_DEV(stack_busnos[slotinfo[index].stack],
256  slotinfo[index].dev_func >> 3, slotinfo[index].dev_func & 0x7);
257  sec_bus = pci_s_read_config8(pci_dev_slot, PCI_SECONDARY_BUS);
258 
259  if (sec_bus == 0xFF) {
260  slot_usage = SlotUsageUnknown;
261  } else {
262  /* Checking for downstream device availability */
263  pci_dev = PCI_DEV(sec_bus, 0, 0);
264  vendor_device_id = pci_s_read_config32(pci_dev, 0);
265  if (vendor_device_id == 0xFFFFFFFF)
266  slot_usage = SlotUsageAvailable;
267  else
268  slot_usage = SlotUsageInUse;
269  }
270 
271  characteristics_1 |= SMBIOS_SLOT_3P3V; // Provides33Volts
272  characteristics_2 |= SMBIOS_SLOT_PME; // PmeSiganalSupported
273  /* Read IIO root port device CSR for slot capabilities */
274  cap = pci_s_find_capability(pci_dev_slot, PCI_CAP_ID_PCIE);
275  sltcap = pci_s_read_config16(pci_dev_slot, cap + PCI_EXP_SLTCAP);
276  if (sltcap & PCI_EXP_SLTCAP_HPC)
277  characteristics_2 |= SMBIOS_SLOT_HOTPLUG;
278 
279  const uint16_t slot_id = index + 1;
280  /* According to SMBIOS spec, the BDF number should be the end
281  point on the slot, for now we keep using the root port's BDF to
282  be aligned with our UEFI reference BIOS. */
283  length += smbios_write_type9(current, handle,
284  slotinfo[index].slot_designator,
285  slotinfo[index].slot_type,
286  slotinfo[index].slot_data_bus_width,
287  slot_usage,
288  slot_length,
289  slot_id,
290  characteristics_1,
291  characteristics_2,
292  stack_busnos[slotinfo[index].stack],
293  slotinfo[index].dev_func);
294  }
295 
296  return length;
297 }
298 
299 static int mainboard_smbios_data(struct device *dev, int *handle, unsigned long *current)
300 {
301  int len = 0;
302 
303  // add port information
304  len += smbios_write_type8(
305  current, handle,
308  );
309 
310  len += create_smbios_type9(handle, current);
311 
312  return len;
313 }
314 
315 void smbios_fill_dimm_locator(const struct dimm_info *dimm, struct smbios_type17 *t)
316 {
317  char buf[40];
318 
319  snprintf(buf, sizeof(buf), "DIMM_%c0", 'A' + dimm->channel_num);
321 
322  snprintf(buf, sizeof(buf), "_Node0_Channel%d_Dimm0", dimm->channel_num);
324 }
325 
326 unsigned int smbios_processor_family(struct cpuid_result res)
327 {
328  return 0xb3; /* Xeon */
329 }
330 
332 {
333  /* 64-bit Capable, Multi-Core, Power/Performance Control */
334  return 0x8c; /* BIT2 + BIT3 + BIT7 */
335 }
336 
337 static void mainboard_enable(struct device *dev)
338 {
339  dev->ops->get_smbios_strings = dl_oem_smbios_strings,
340  read_fru_areas(CONFIG_BMC_KCS_BASE, CONFIG_FRU_DEVICE_ID, 0, &fru_strings);
341  dev->ops->get_smbios_data = mainboard_smbios_data;
342 }
343 
345 {
346  /* configure Lewisburg PCH GPIO controller after FSP-M */
348 }
349 
350 static void mainboard_final(void *chip_info)
351 {
352 }
353 
356  .final = mainboard_final,
357 };
358 
360 {
361  static bool fetched_vpd = 0;
362  static uint8_t skip_txt = SKIP_INTEL_TXT_LOCKDOWN_DEFAULT;
363 
364  if (fetched_vpd)
365  return (bool)skip_txt;
366 
368  printk(BIOS_INFO, "%s: not able to get VPD %s, default set to %d\n",
370  else
371  printk(BIOS_DEBUG, "%s: VPD %s, got %d\n", __func__, SKIP_INTEL_TXT_LOCKDOWN,
372  skip_txt);
373 
374  fetched_vpd = 1;
375 
376  return (bool)skip_txt;
377 }
int smbios_add_string(u8 *start, const char *str)
Definition: smbios.c:40
int smbios_write_type9(unsigned long *current, int *handle, const char *name, const enum misc_slot_type type, const enum slot_data_bus_bandwidth bandwidth, const enum misc_slot_usage usage, const enum misc_slot_length length, const u16 id, u8 slot_char1, u8 slot_char2, u8 bus, u8 dev_func)
Definition: smbios.c:837
int smbios_write_type8(unsigned long *current, int *handle, const struct port_information *port, size_t num_ports)
Definition: smbios.c:812
#define pci_dev
#define assert(statement)
Definition: assert.h:74
static struct sdram_info params
Definition: sdram_configs.c:83
#define ARRAY_SIZE(a)
Definition: helpers.h:12
@ CB_SUCCESS
Call completed successfully.
Definition: cb_err.h:16
#define printk(level,...)
Definition: stdlib.h:16
enum cb_err ipmi_get_pcie_config(uint8_t *pcie_config)
Definition: ipmi.c:12
enum cb_err ipmi_get_slot_id(uint8_t *slot_id)
Definition: ipmi.c:35
@ PCIE_CONFIG_A
Definition: ipmi.h:14
@ PCIE_CONFIG_C
Definition: ipmi.h:16
@ PCIE_CONFIG_UNKNOWN
Definition: ipmi.h:13
@ PCIE_CONFIG_B
Definition: ipmi.h:15
@ PCIE_CONFIG_D
Definition: ipmi.h:17
__weak void mainboard_silicon_init_params(SILICON_INIT_UPD *params)
Definition: ramstage.c:162
@ VPD_RW_THEN_RO
Definition: vpd.h:14
uint64_t length
Definition: fw_cfg_if.h:1
#define SMBIOS_SLOT_3P3V
Definition: smbios.h:774
@ SlotTypePciExpressGen3X16
Definition: smbios.h:727
@ SlotTypePciExpressGen3X4
Definition: smbios.h:725
@ SlotLengthShort
Definition: smbios.h:767
@ SlotLengthLong
Definition: smbios.h:768
@ SlotUsageUnknown
Definition: smbios.h:757
@ SlotUsageAvailable
Definition: smbios.h:758
@ SlotUsageInUse
Definition: smbios.h:759
#define SMBIOS_SLOT_PME
Definition: smbios.h:781
@ SlotDataBusWidth16X
Definition: smbios.h:750
@ SlotDataBusWidth4X
Definition: smbios.h:747
@ CONN_USB_TYPE_C
Definition: smbios.h:598
@ CONN_OTHER
Definition: smbios.h:604
@ CONN_NONE
Definition: smbios.h:563
#define SMBIOS_FEATURE_FLAGS_HOSTING_BOARD
Definition: smbios.h:338
#define SMBIOS_FEATURE_FLAGS_REPLACEABLE
Definition: smbios.h:341
@ TYPE_USB
Definition: smbios.h:625
@ TYPE_OTHER_PORT
Definition: smbios.h:647
#define SMBIOS_SLOT_HOTPLUG
Definition: smbios.h:782
const struct SystemMemoryMapHob * get_system_memory_map(void)
Definition: soc_util.c:12
void read_fru_areas(const int port, const uint8_t id, uint16_t offset, struct fru_info_str *fru_info_str)
Definition: ipmi_fru.c:422
void ipmi_bmc_version(uint8_t *ipmi_bmc_major_revision, uint8_t *ipmi_bmc_minor_revision)
Definition: ipmi_kcs_ops.c:334
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
static const struct pad_config gpio_table[]
Definition: gpio.h:24
struct chip_operations mainboard_ops
Definition: ramstage.c:11
static uint8_t * buf
Definition: uart.c:7
void smbios_fill_dimm_locator(const struct dimm_info *dimm, struct smbios_type17 *t)
Definition: ramstage.c:8
unsigned int smbios_processor_family(struct cpuid_result res)
Definition: ramstage.c:326
void smbios_ec_revision(uint8_t *ec_major_revision, uint8_t *ec_minor_revision)
Definition: ramstage.c:35
static int create_smbios_type9(int *handle, unsigned long *current)
Definition: ramstage.c:189
unsigned int smbios_processor_characteristics(void)
Definition: ramstage.c:331
static char slot_id_str[SLOT_ID_LEN]
Definition: ramstage.c:27
bool skip_intel_txt_lockdown(void)
Definition: ramstage.c:359
static const struct port_information smbios_type8_info[]
Definition: ramstage.c:165
static void write_oem_word(uint16_t val, char *str)
Definition: ramstage.c:109
slot_info slotinfo[]
Definition: ramstage.c:90
u8 smbios_mainboard_feature_flags(void)
Definition: ramstage.c:63
const char * smbios_mainboard_location_in_chassis(void)
Definition: ramstage.c:45
static int mainboard_smbios_data(struct device *dev, int *handle, unsigned long *current)
Definition: ramstage.c:299
static void dl_oem_smbios_strings(struct device *dev, struct smbios_type11 *t)
Definition: ramstage.c:114
struct fru_info_str fru_strings
Definition: smbios.c:20
unsigned int smbios_cpu_get_voltage(void)
Definition: ramstage.c:73
static void mainboard_final(void *chip_info)
Definition: ramstage.c:350
static void mainboard_enable(struct device *dev)
Definition: ramstage.c:337
#define SPD_REGVID_LEN
Definition: ramstage.c:107
#define SLOT_ID_LEN
Definition: ramstage.c:24
#define SKIP_INTEL_TXT_LOCKDOWN
Definition: vpd.h:50
#define SKIP_INTEL_TXT_LOCKDOWN_DEFAULT
Definition: vpd.h:51
static struct dramc_channel const ch[2]
void ocp_oem_smbios_strings(struct device *dev, struct smbios_type11 *t)
Definition: smbios.c:207
int smbios_add_oem_string(u8 *start, const char *str)
Definition: smbios.c:164
#define PCI_CAP_ID_PCIE
Definition: pci_def.h:202
#define PCI_SECONDARY_BUS
Definition: pci_def.h:101
#define PCI_EXP_SLTCAP
Definition: pci_def.h:434
#define PCI_EXP_SLTCAP_HPC
Definition: pci_def.h:435
static __always_inline uint32_t pci_s_read_config32(pci_devfn_t dev, uint16_t reg)
Definition: pci_io_cfg.h:92
static __always_inline uint16_t pci_s_read_config16(pci_devfn_t dev, uint16_t reg)
Definition: pci_io_cfg.h:86
static __always_inline uint8_t pci_s_read_config8(pci_devfn_t dev, uint16_t reg)
Definition: pci_io_cfg.h:80
u16 pci_s_find_capability(pci_devfn_t dev, u16 cap)
Given a device, and a capability type, return the next matching capability.
Definition: pci_ops.c:72
#define PCI_DEV(SEGBUS, DEV, FN)
Definition: pci_type.h:14
u32 pci_devfn_t
Definition: pci_type.h:8
void gpio_configure_pads(const struct soc_amd_gpio *gpio_list_ptr, size_t size)
program a particular set of GPIO
Definition: gpio.c:307
uint8_t get_stack_busno(const uint8_t stack)
Definition: util.c:16
#define NULL
Definition: stddef.h:19
unsigned short uint16_t
Definition: stdint.h:11
unsigned int uint32_t
Definition: stdint.h:14
uint8_t u8
Definition: stdint.h:45
unsigned char uint8_t
Definition: stdint.h:8
char * strconcat(const char *s1, const char *s2)
Definition: string.c:19
void(* enable_dev)(struct device *dev)
Definition: device.h:24
Definition: device.h:107
struct device_operations * ops
Definition: device.h:143
If this table is filled and put in CBMEM, then these info in CBMEM will be used to generate smbios ty...
Definition: memory_info.h:19
uint8_t channel_num
Definition: memory_info.h:36
const char * internal_reference_designator
Definition: smbios.h:651
u8 dev_func
Definition: ramstage.c:85
u8 stack
Definition: ramstage.c:82
u8 slot_type
Definition: ramstage.c:83
const char * slot_designator
Definition: ramstage.c:86
u8 slot_data_bus_width
Definition: ramstage.c:84
u8 eos[2]
Definition: smbios.h:815
u8 device_locator
Definition: smbios.h:869
u8 bank_locator
Definition: smbios.h:870
u8 eos[2]
Definition: smbios.h:884
u8 val
Definition: sys.c:300
bool vpd_get_bool(const char *key, enum vpd_region region, uint8_t *val)
Definition: vpd.c:252
int snprintf(char *buf, size_t size, const char *fmt,...)
Note: This file is only for POSIX compatibility, and is meant to be chain-included via string....
Definition: vsprintf.c:35