blob: d132590483c5feb3d34ec3c69880c764f740cb4c [file] [log] [blame]
Rob Barnes009a23d2020-04-13 01:27:12 -06001/* 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>
Nikolai Vyssotskia289cdd2021-04-28 18:09:29 -050016#include <dmi_info.h>
Rob Barnese5aa5ae2020-09-14 07:51:51 -060017#include <device/dram/ddr4.h>
Nikolai Vyssotskic839b372021-06-25 11:15:38 -050018#include <device/dram/lpddr4.h>
Matt DeVillier32bb6b62022-08-22 17:30:00 -050019#include <device/dram/ddr5.h>
Nikolai Vyssotskic839b372021-06-25 11:15:38 -050020
21/**
22 * Convert DDR clock speed (based on memory type) in MHz to the standard reported speed in MT/s
23 */
24static uint16_t ddr_speed_mhz_to_reported_mts(uint16_t ddr_type, uint16_t speed)
25{
Martin Rothb6877e42022-10-29 16:00:57 -060026 if (CONFIG(USE_DDR4) && ddr_type == MEMORY_TYPE_DDR4)
Nikolai Vyssotskic839b372021-06-25 11:15:38 -050027 return ddr4_speed_mhz_to_reported_mts(speed);
Martin Rothb6877e42022-10-29 16:00:57 -060028 else if (CONFIG(USE_LPDDR4) && ddr_type == MEMORY_TYPE_LPDDR4)
Nikolai Vyssotskic839b372021-06-25 11:15:38 -050029 return lpddr4_speed_mhz_to_reported_mts(speed);
Martin Rothb6877e42022-10-29 16:00:57 -060030 else if (CONFIG(USE_DDR5) && (ddr_type == MEMORY_TYPE_DDR5 ||
31 ddr_type == MEMORY_TYPE_LPDDR5))
Matt DeVillier32bb6b62022-08-22 17:30:00 -050032 return ddr5_speed_mhz_to_reported_mts(speed);
Martin Rothb6877e42022-10-29 16:00:57 -060033
34 printk(BIOS_ERR, "Unknown memory type %x\n", ddr_type);
35 return 0;
Nikolai Vyssotskic839b372021-06-25 11:15:38 -050036}
Rob Barnes009a23d2020-04-13 01:27:12 -060037
38/**
Matt DeVillier17144bc2022-08-23 11:54:50 -050039 * Return DDR voltage (in mV) based on memory type
40 */
41static uint16_t ddr_get_voltage(uint16_t ddr_type)
42{
43 switch (ddr_type) {
44 case MEMORY_TYPE_DDR4:
45 return 1200;
46 case MEMORY_TYPE_LPDDR4:
47 case MEMORY_TYPE_DDR5:
48 return 1100;
49 case MEMORY_TYPE_LPDDR5:
50 return 1050;
51 default:
52 printk(BIOS_ERR, "Unknown memory type %x\n", ddr_type);
53 return 0;
54 }
55}
56
57/**
Rob Barnes009a23d2020-04-13 01:27:12 -060058 * Populate dimm_info using AGESA TYPE17_DMI_INFO.
59 */
60static void transfer_memory_info(const TYPE17_DMI_INFO *dmi17,
61 struct dimm_info *dimm)
62{
63 hexstrtobin(dmi17->SerialNumber, dimm->serial, sizeof(dimm->serial));
64
65 dimm->dimm_size = smbios_memory_size_to_mib(dmi17->MemorySize, dmi17->ExtSize);
66
67 dimm->ddr_type = dmi17->MemoryType;
68
Nikolai Vyssotskic839b372021-06-25 11:15:38 -050069 dimm->configured_speed_mts = ddr_speed_mhz_to_reported_mts(
70 dmi17->MemoryType, dmi17->ConfigSpeed);
Rob Barnesb132bf52020-09-01 10:28:36 -060071
Nikolai Vyssotskic839b372021-06-25 11:15:38 -050072 dimm->max_speed_mts = ddr_speed_mhz_to_reported_mts(dmi17->MemoryType, dmi17->Speed);
Rob Barnes009a23d2020-04-13 01:27:12 -060073
74 dimm->rank_per_dimm = dmi17->Attributes;
75
Arthur Heymans4401a912022-03-23 22:14:25 +010076 dimm->mod_type = smbios_form_factor_to_spd_mod_type(
77 (smbios_memory_type)dmi17->MemoryType,
78 (smbios_memory_form_factor)dmi17->FormFactor);
Rob Barnes009a23d2020-04-13 01:27:12 -060079
Subrata Banik3306f372021-10-26 13:19:20 +053080 dimm->bus_width = smbios_bus_width_to_spd_width(dmi17->MemoryType, dmi17->TotalWidth,
81 dmi17->DataWidth);
Rob Barnes009a23d2020-04-13 01:27:12 -060082
83 dimm->mod_id = dmi17->ManufacturerIdCode;
84
85 dimm->bank_locator = 0;
86
Matt DeVillier17144bc2022-08-23 11:54:50 -050087 dimm->vdd_voltage = ddr_get_voltage(dmi17->MemoryType);
88
Rob Barnes009a23d2020-04-13 01:27:12 -060089 strncpy((char *)dimm->module_part_number, dmi17->PartNumber,
90 sizeof(dimm->module_part_number) - 1);
91}
92
93static void print_dimm_info(const struct dimm_info *dimm)
94{
95 printk(BIOS_DEBUG,
96 "CBMEM_ID_MEMINFO:\n"
97 " dimm_size: %u\n"
98 " ddr_type: 0x%hx\n"
Matt DeVillierb4a5ef42022-08-23 11:49:54 -050099 " max_speed_mts: %hu\n"
100 " config_speed_mts: %hu\n"
Matt DeVillier17144bc2022-08-23 11:54:50 -0500101 " vdd_voltage: %hu\n"
Rob Barnes009a23d2020-04-13 01:27:12 -0600102 " rank_per_dimm: %hhu\n"
103 " channel_num: %hhu\n"
104 " dimm_num: %hhu\n"
105 " bank_locator: %hhu\n"
106 " mod_id: %hx\n"
107 " mod_type: 0x%hhx\n"
108 " bus_width: %hhu\n"
109 " serial: %02hhx%02hhx%02hhx%02hhx\n"
110 " module_part_number(%zu): %s\n",
111 dimm->dimm_size,
112 dimm->ddr_type,
Matt DeVillierb4a5ef42022-08-23 11:49:54 -0500113 dimm->max_speed_mts,
114 dimm->configured_speed_mts,
Matt DeVillier17144bc2022-08-23 11:54:50 -0500115 dimm->vdd_voltage,
Rob Barnes009a23d2020-04-13 01:27:12 -0600116 dimm->rank_per_dimm,
117 dimm->channel_num,
118 dimm->dimm_num,
119 dimm->bank_locator,
120 dimm->mod_id,
121 dimm->mod_type,
122 dimm->bus_width,
123 dimm->serial[0],
124 dimm->serial[1],
125 dimm->serial[2],
126 dimm->serial[3],
127 strlen((const char *)dimm->module_part_number),
128 (char *)dimm->module_part_number);
129}
130
131static void print_dmi_info(const TYPE17_DMI_INFO *dmi17)
132{
133 printk(BIOS_DEBUG,
134 "AGESA TYPE 17 DMI INFO:\n"
135 " Handle: %hu\n"
136 " TotalWidth: %hu\n"
137 " DataWidth: %hu\n"
138 " MemorySize: %hu\n"
139 " DeviceSet: %hhu\n"
140 " Speed: %hu\n"
141 " ManufacturerIdCode: %llx\n"
142 " Attributes: %hhu\n"
143 " ExtSize: %u\n"
144 " ConfigSpeed: %hu\n"
145 " MemoryType: 0x%x\n"
146 " FormFactor: 0x%x\n"
147 " DeviceLocator: %8s\n"
148 " BankLocator: %10s\n"
149 " SerialNumber(%zu): %9s\n"
150 " PartNumber(%zu): %19s\n",
151 dmi17->Handle,
152 dmi17->TotalWidth,
153 dmi17->DataWidth,
154 dmi17->MemorySize,
155 dmi17->DeviceSet,
156 dmi17->Speed,
157 dmi17->ManufacturerIdCode,
158 dmi17->Attributes,
159 dmi17->ExtSize,
160 dmi17->ConfigSpeed,
161 dmi17->MemoryType,
162 dmi17->FormFactor,
163 dmi17->DeviceLocator,
164 dmi17->BankLocator,
165 strlen((const char *)dmi17->SerialNumber),
166 dmi17->SerialNumber,
167 strlen((const char *)dmi17->PartNumber),
168 dmi17->PartNumber);
169}
170
171/**
172 * Marshalls dimm info from AMD_FSP_DMI_HOB into CBMEM_ID_MEMINFO
173 */
Martin Roth3a5d1952023-02-23 15:54:55 -0700174static void prepare_dmi_16_17(void *unused)
Rob Barnes009a23d2020-04-13 01:27:12 -0600175{
176 const DMI_INFO *dmi_table;
177 const TYPE17_DMI_INFO *type17_dmi_info;
178 struct memory_info *mem_info;
179 struct dimm_info *dimm_info;
180 char cbi_part_number[DIMM_INFO_PART_NUMBER_SIZE];
181 bool use_cbi_part_number = false;
182 size_t dimm_cnt = 0;
183 size_t amd_fsp_dmi_hob_size;
184 const EFI_GUID amd_fsp_dmi_hob_guid = AMD_FSP_DMI_HOB_GUID;
185
186 printk(BIOS_DEBUG, "Saving dimm info for smbios type 17\n");
187
188 /* Allocate meminfo in cbmem. */
189 mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(struct memory_info));
190 if (!mem_info) {
191 printk(BIOS_ERR,
192 "Failed to add memory info to CBMEM, DMI tables will be incomplete\n");
193 return;
194 }
195 memset(mem_info, 0, sizeof(struct memory_info));
196
197 /* Locate the memory info HOB. */
198 dmi_table = fsp_find_extension_hob_by_guid(
199 (const uint8_t *)&amd_fsp_dmi_hob_guid, &amd_fsp_dmi_hob_size);
200
201 if (dmi_table == NULL || amd_fsp_dmi_hob_size == 0) {
202 printk(BIOS_ERR,
203 "AMD_FSP_DMI_HOB not found, DMI table 17 will be incomplete\n");
204 return;
205 }
206 printk(BIOS_DEBUG, "AMD_FSP_DMI_HOB found\n");
207
Nikolai Vyssotski60d67ce2021-04-28 19:26:37 -0500208 if (CONFIG(EC_GOOGLE_CHROMEEC)) {
Rob Barnes009a23d2020-04-13 01:27:12 -0600209 /* Prefer DRAM part number from CBI. */
210 if (google_chromeec_cbi_get_dram_part_num(
211 cbi_part_number, sizeof(cbi_part_number)) == 0) {
212 use_cbi_part_number = true;
213 } else {
214 printk(BIOS_ERR, "Could not obtain DRAM part number from CBI\n");
215 }
216 }
217
Konrad Adamczyk86dfcb82023-06-28 12:23:08 +0000218 for (unsigned int channel = 0; channel < AGESA_STRUCT_CHANNELS_PER_SOCKET; channel++) {
219 for (unsigned int dimm = 0; dimm < AGESA_STRUCT_DIMMS_PER_CHANNEL; dimm++) {
Rob Barnes009a23d2020-04-13 01:27:12 -0600220 type17_dmi_info = &dmi_table->T17[0][channel][dimm];
221 /* DIMMs that are present will have a non-zero
222 handle. */
223 if (type17_dmi_info->Handle == 0)
224 continue;
225 print_dmi_info(type17_dmi_info);
226 dimm_info = &mem_info->dimm[dimm_cnt];
227 dimm_info->channel_num = channel;
Konrad Adamczyk2910a542023-06-27 12:44:43 +0000228 dimm_info->dimm_num = dimm;
Rob Barnes009a23d2020-04-13 01:27:12 -0600229 transfer_memory_info(type17_dmi_info, dimm_info);
230 if (use_cbi_part_number) {
231 /* mem_info is memset to 0 above, so it's
232 safe to assume module_part_number will be
233 null terminated */
234 strncpy((char *)dimm_info->module_part_number, cbi_part_number,
235 sizeof(dimm_info->module_part_number) - 1);
Martin Rothd712c622023-02-23 16:23:34 -0700236
237 /* These ID values match what's used in device/dram/spd.c */
238 switch (dimm_info->module_part_number[0]) {
239 case 'H':
240 dimm_info->mod_id = 0xad00; // Hynix
241 break;
242 case 'K':
243 dimm_info->mod_id = 0x9801; // Kingston
244 break;
245 case 'M':
246 dimm_info->mod_id = 0x2c00; // Micron
247 break;
248 case 'N':
249 dimm_info->mod_id = 0x0b83; // Nanya
250 break;
251 }
Rob Barnes009a23d2020-04-13 01:27:12 -0600252 }
253 print_dimm_info(dimm_info);
254 dimm_cnt++;
255 }
256 }
257 mem_info->dimm_cnt = dimm_cnt;
Martin Roth3a5d1952023-02-23 15:54:55 -0700258
259 mem_info->ecc_type = dmi_table->T16.MemoryErrorCorrection;
Rob Barnes009a23d2020-04-13 01:27:12 -0600260}
261
262/* AMD_FSP_DMI_HOB is initialized very late, so check it just in time for writing tables. */
Martin Roth3a5d1952023-02-23 15:54:55 -0700263BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, prepare_dmi_16_17, NULL);