coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
dmi.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 /**
4  * This code was adapted from src/soc/amd/common/block/pi/amd_late_init.c
5  */
6 
7 #include <fsp/util.h>
8 #include <memory_info.h>
9 #include <console/console.h>
10 #include <cbmem.h>
11 #include <string.h>
12 #include <ec/google/chromeec/ec.h>
13 #include <bootstate.h>
14 #include <lib.h>
15 #include <dimm_info_util.h>
16 #include <dmi_info.h>
17 #include <device/dram/ddr4.h>
18 #include <device/dram/lpddr4.h>
19 
20 /**
21  * Convert DDR clock speed (based on memory type) in MHz to the standard reported speed in MT/s
22  */
24 {
25  switch (ddr_type) {
26  case MEMORY_TYPE_DDR4:
27  return ddr4_speed_mhz_to_reported_mts(speed);
28  case MEMORY_TYPE_LPDDR4:
30  default:
31  printk(BIOS_ERR, "Unknown memory type %x", ddr_type);
32  return 0;
33  }
34 }
35 
36 /**
37  * Populate dimm_info using AGESA TYPE17_DMI_INFO.
38  */
39 static void transfer_memory_info(const TYPE17_DMI_INFO *dmi17,
40  struct dimm_info *dimm)
41 {
42  hexstrtobin(dmi17->SerialNumber, dimm->serial, sizeof(dimm->serial));
43 
44  dimm->dimm_size = smbios_memory_size_to_mib(dmi17->MemorySize, dmi17->ExtSize);
45 
46  dimm->ddr_type = dmi17->MemoryType;
47 
49  dmi17->MemoryType, dmi17->ConfigSpeed);
50 
51  dimm->max_speed_mts = ddr_speed_mhz_to_reported_mts(dmi17->MemoryType, dmi17->Speed);
52 
53  dimm->rank_per_dimm = dmi17->Attributes;
54 
56  (smbios_memory_type)dmi17->MemoryType,
57  (smbios_memory_form_factor)dmi17->FormFactor);
58 
59  dimm->bus_width = smbios_bus_width_to_spd_width(dmi17->MemoryType, dmi17->TotalWidth,
60  dmi17->DataWidth);
61 
62  dimm->mod_id = dmi17->ManufacturerIdCode;
63 
64  dimm->bank_locator = 0;
65 
66  strncpy((char *)dimm->module_part_number, dmi17->PartNumber,
67  sizeof(dimm->module_part_number) - 1);
68 }
69 
70 static void print_dimm_info(const struct dimm_info *dimm)
71 {
73  "CBMEM_ID_MEMINFO:\n"
74  " dimm_size: %u\n"
75  " ddr_type: 0x%hx\n"
76  " ddr_frequency: %hu\n"
77  " rank_per_dimm: %hhu\n"
78  " channel_num: %hhu\n"
79  " dimm_num: %hhu\n"
80  " bank_locator: %hhu\n"
81  " mod_id: %hx\n"
82  " mod_type: 0x%hhx\n"
83  " bus_width: %hhu\n"
84  " serial: %02hhx%02hhx%02hhx%02hhx\n"
85  " module_part_number(%zu): %s\n",
86  dimm->dimm_size,
87  dimm->ddr_type,
88  dimm->ddr_frequency,
89  dimm->rank_per_dimm,
90  dimm->channel_num,
91  dimm->dimm_num,
92  dimm->bank_locator,
93  dimm->mod_id,
94  dimm->mod_type,
95  dimm->bus_width,
96  dimm->serial[0],
97  dimm->serial[1],
98  dimm->serial[2],
99  dimm->serial[3],
100  strlen((const char *)dimm->module_part_number),
101  (char *)dimm->module_part_number);
102 }
103 
104 static void print_dmi_info(const TYPE17_DMI_INFO *dmi17)
105 {
107  "AGESA TYPE 17 DMI INFO:\n"
108  " Handle: %hu\n"
109  " TotalWidth: %hu\n"
110  " DataWidth: %hu\n"
111  " MemorySize: %hu\n"
112  " DeviceSet: %hhu\n"
113  " Speed: %hu\n"
114  " ManufacturerIdCode: %llx\n"
115  " Attributes: %hhu\n"
116  " ExtSize: %u\n"
117  " ConfigSpeed: %hu\n"
118  " MemoryType: 0x%x\n"
119  " FormFactor: 0x%x\n"
120  " DeviceLocator: %8s\n"
121  " BankLocator: %10s\n"
122  " SerialNumber(%zu): %9s\n"
123  " PartNumber(%zu): %19s\n",
124  dmi17->Handle,
125  dmi17->TotalWidth,
126  dmi17->DataWidth,
127  dmi17->MemorySize,
128  dmi17->DeviceSet,
129  dmi17->Speed,
130  dmi17->ManufacturerIdCode,
131  dmi17->Attributes,
132  dmi17->ExtSize,
133  dmi17->ConfigSpeed,
134  dmi17->MemoryType,
135  dmi17->FormFactor,
136  dmi17->DeviceLocator,
137  dmi17->BankLocator,
138  strlen((const char *)dmi17->SerialNumber),
139  dmi17->SerialNumber,
140  strlen((const char *)dmi17->PartNumber),
141  dmi17->PartNumber);
142 }
143 
144 /**
145  * Marshalls dimm info from AMD_FSP_DMI_HOB into CBMEM_ID_MEMINFO
146  */
147 static void prepare_dmi_17(void *unused)
148 {
149  const DMI_INFO *dmi_table;
150  const TYPE17_DMI_INFO *type17_dmi_info;
151  struct memory_info *mem_info;
152  struct dimm_info *dimm_info;
153  char cbi_part_number[DIMM_INFO_PART_NUMBER_SIZE];
154  bool use_cbi_part_number = false;
155  size_t dimm_cnt = 0;
156  size_t amd_fsp_dmi_hob_size;
157  const EFI_GUID amd_fsp_dmi_hob_guid = AMD_FSP_DMI_HOB_GUID;
158 
159  printk(BIOS_DEBUG, "Saving dimm info for smbios type 17\n");
160 
161  /* Allocate meminfo in cbmem. */
162  mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(struct memory_info));
163  if (!mem_info) {
165  "Failed to add memory info to CBMEM, DMI tables will be incomplete\n");
166  return;
167  }
168  memset(mem_info, 0, sizeof(struct memory_info));
169 
170  /* Locate the memory info HOB. */
171  dmi_table = fsp_find_extension_hob_by_guid(
172  (const uint8_t *)&amd_fsp_dmi_hob_guid, &amd_fsp_dmi_hob_size);
173 
174  if (dmi_table == NULL || amd_fsp_dmi_hob_size == 0) {
176  "AMD_FSP_DMI_HOB not found, DMI table 17 will be incomplete\n");
177  return;
178  }
179  printk(BIOS_DEBUG, "AMD_FSP_DMI_HOB found\n");
180 
181  if (CONFIG(EC_GOOGLE_CHROMEEC)) {
182  /* Prefer DRAM part number from CBI. */
184  cbi_part_number, sizeof(cbi_part_number)) == 0) {
185  use_cbi_part_number = true;
186  } else {
187  printk(BIOS_ERR, "Could not obtain DRAM part number from CBI\n");
188  }
189  }
190 
191  for (unsigned int channel = 0; channel < MAX_CHANNELS_PER_SOCKET; channel++) {
192  for (unsigned int dimm = 0; dimm < MAX_DIMMS_PER_CHANNEL; dimm++) {
193  type17_dmi_info = &dmi_table->T17[0][channel][dimm];
194  /* DIMMs that are present will have a non-zero
195  handle. */
196  if (type17_dmi_info->Handle == 0)
197  continue;
198  print_dmi_info(type17_dmi_info);
199  dimm_info = &mem_info->dimm[dimm_cnt];
200  dimm_info->channel_num = channel;
201  dimm_info->dimm_num = channel;
202  transfer_memory_info(type17_dmi_info, dimm_info);
203  if (use_cbi_part_number) {
204  /* mem_info is memset to 0 above, so it's
205  safe to assume module_part_number will be
206  null terminated */
207  strncpy((char *)dimm_info->module_part_number, cbi_part_number,
208  sizeof(dimm_info->module_part_number) - 1);
209  }
211  dimm_cnt++;
212  }
213  }
214  mem_info->dimm_cnt = dimm_cnt;
215 }
216 
217 /* AMD_FSP_DMI_HOB is initialized very late, so check it just in time for writing tables. */
void * memset(void *dstpp, int c, size_t len)
Definition: memset.c:12
@ BS_WRITE_TABLES
Definition: bootstate.h:87
@ BS_ON_ENTRY
Definition: bootstate.h:95
void * cbmem_add(u32 id, u64 size)
Definition: imd_cbmem.c:144
#define CBMEM_ID_MEMINFO
Definition: cbmem_id.h:33
#define printk(level,...)
Definition: stdlib.h:16
uint16_t ddr4_speed_mhz_to_reported_mts(uint16_t speed_mhz)
Converts DDR4 clock speed in MHz to the standard reported speed in MT/s.
Definition: ddr4.c:137
Utilities for decoding DDR4 SPDs.
uint8_t smbios_form_factor_to_spd_mod_type(smbios_memory_type memory_type, smbios_memory_form_factor form_factor)
Convert the SMBIOS form factor to the SPD module type.
uint32_t smbios_memory_size_to_mib(uint16_t memory_size, uint32_t extended_size)
Convert the SMBIOS size values into the total number of MiB.
uint8_t smbios_bus_width_to_spd_width(uint8_t ddr_type, uint16_t total_width, uint16_t data_width)
Convert the SMBIOS bit widths into an SPD encoded width.
Definition: dimm_info_util.c:9
static void prepare_dmi_17(void *unused)
Marshalls dimm info from AMD_FSP_DMI_HOB into CBMEM_ID_MEMINFO.
Definition: dmi.c:147
static uint16_t ddr_speed_mhz_to_reported_mts(uint16_t ddr_type, uint16_t speed)
This code was adapted from src/soc/amd/common/block/pi/amd_late_init.c.
Definition: dmi.c:23
static void print_dmi_info(const TYPE17_DMI_INFO *dmi17)
Definition: dmi.c:104
static void print_dimm_info(const struct dimm_info *dimm)
Definition: dmi.c:70
BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, prepare_dmi_17, NULL)
static void transfer_memory_info(const TYPE17_DMI_INFO *dmi17, struct dimm_info *dimm)
Populate dimm_info using AGESA TYPE17_DMI_INFO.
Definition: dmi.c:39
@ CONFIG
Definition: dsi_common.h:201
int google_chromeec_cbi_get_dram_part_num(char *buf, size_t bufsize)
Definition: ec.c:905
const void * fsp_find_extension_hob_by_guid(const uint8_t *guid, size_t *size)
smbios_memory_type
Definition: smbios.h:164
@ MEMORY_TYPE_DDR4
Definition: smbios.h:187
@ MEMORY_TYPE_LPDDR4
Definition: smbios.h:191
smbios_memory_form_factor
Definition: smbios.h:145
size_t hexstrtobin(const char *str, uint8_t *buf, size_t len)
Definition: hexstrtobin.c:6
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
uint16_t lpddr4_speed_mhz_to_reported_mts(uint16_t speed_mhz)
Converts LPDDR4 clock speed in MHz to the standard reported speed in MT/s.
Definition: lpddr4.c:87
Utilities for decoding LPDDR4 info.
#define DIMM_INFO_PART_NUMBER_SIZE
Definition: memory_info.h:10
struct dimm_info_st dimm_info
#define NULL
Definition: stddef.h:19
unsigned short uint16_t
Definition: stdint.h:11
unsigned char uint8_t
Definition: stdint.h:8
char * strncpy(char *to, const char *from, int count)
Definition: string.c:72
size_t strlen(const char *src)
Definition: string.c:42
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 mod_type
Definition: memory_info.h:60
uint8_t rank_per_dimm
Definition: memory_info.h:35
uint8_t channel_num
Definition: memory_info.h:36
uint8_t dimm_num
Definition: memory_info.h:37
uint16_t configured_speed_mts
Definition: memory_info.h:94
uint8_t bus_width
Definition: memory_info.h:80
uint8_t module_part_number[DIMM_INFO_PART_NUMBER_SIZE]
Definition: memory_info.h:48
uint16_t max_speed_mts
Definition: memory_info.h:89
uint16_t ddr_type
Definition: memory_info.h:29
uint8_t serial[DIMM_INFO_SERIAL_SIZE]
Definition: memory_info.h:42
uint16_t ddr_frequency
Definition: memory_info.h:34
uint16_t mod_id
Definition: memory_info.h:52
uint8_t bank_locator
Definition: memory_info.h:38
uint32_t dimm_size
Definition: memory_info.h:23
struct dimm_info dimm[DIMM_INFO_TOTAL]
Definition: memory_info.h:110
uint8_t dimm_cnt
Definition: memory_info.h:109