blob: b96b04762722d3f1ebaf8614097ccc4f177a3d53 [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>
19
20/**
21 * Convert DDR clock speed (based on memory type) in MHz to the standard reported speed in MT/s
22 */
23static uint16_t ddr_speed_mhz_to_reported_mts(uint16_t ddr_type, uint16_t speed)
24{
25 switch (ddr_type) {
26 case MEMORY_TYPE_DDR4:
27 return ddr4_speed_mhz_to_reported_mts(speed);
28 case MEMORY_TYPE_LPDDR4:
29 return lpddr4_speed_mhz_to_reported_mts(speed);
30 default:
31 printk(BIOS_ERR, "ERROR: Unknown memory type %x", ddr_type);
32 return 0;
33 }
34}
Rob Barnes009a23d2020-04-13 01:27:12 -060035
36/**
37 * Populate dimm_info using AGESA TYPE17_DMI_INFO.
38 */
39static 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
Nikolai Vyssotskic839b372021-06-25 11:15:38 -050048 dimm->configured_speed_mts = ddr_speed_mhz_to_reported_mts(
49 dmi17->MemoryType, dmi17->ConfigSpeed);
Rob Barnesb132bf52020-09-01 10:28:36 -060050
Nikolai Vyssotskic839b372021-06-25 11:15:38 -050051 dimm->max_speed_mts = ddr_speed_mhz_to_reported_mts(dmi17->MemoryType, dmi17->Speed);
Rob Barnes009a23d2020-04-13 01:27:12 -060052
53 dimm->rank_per_dimm = dmi17->Attributes;
54
Subrata Banik6de8b422021-10-26 20:46:21 +053055 dimm->mod_type = smbios_form_factor_to_spd_mod_type(dmi17->MemoryType,
56 dmi17->FormFactor);
Rob Barnes009a23d2020-04-13 01:27:12 -060057
Subrata Banik3306f372021-10-26 13:19:20 +053058 dimm->bus_width = smbios_bus_width_to_spd_width(dmi17->MemoryType, dmi17->TotalWidth,
59 dmi17->DataWidth);
Rob Barnes009a23d2020-04-13 01:27:12 -060060
61 dimm->mod_id = dmi17->ManufacturerIdCode;
62
63 dimm->bank_locator = 0;
64
65 strncpy((char *)dimm->module_part_number, dmi17->PartNumber,
66 sizeof(dimm->module_part_number) - 1);
67}
68
69static void print_dimm_info(const struct dimm_info *dimm)
70{
71 printk(BIOS_DEBUG,
72 "CBMEM_ID_MEMINFO:\n"
73 " dimm_size: %u\n"
74 " ddr_type: 0x%hx\n"
75 " ddr_frequency: %hu\n"
76 " rank_per_dimm: %hhu\n"
77 " channel_num: %hhu\n"
78 " dimm_num: %hhu\n"
79 " bank_locator: %hhu\n"
80 " mod_id: %hx\n"
81 " mod_type: 0x%hhx\n"
82 " bus_width: %hhu\n"
83 " serial: %02hhx%02hhx%02hhx%02hhx\n"
84 " module_part_number(%zu): %s\n",
85 dimm->dimm_size,
86 dimm->ddr_type,
87 dimm->ddr_frequency,
88 dimm->rank_per_dimm,
89 dimm->channel_num,
90 dimm->dimm_num,
91 dimm->bank_locator,
92 dimm->mod_id,
93 dimm->mod_type,
94 dimm->bus_width,
95 dimm->serial[0],
96 dimm->serial[1],
97 dimm->serial[2],
98 dimm->serial[3],
99 strlen((const char *)dimm->module_part_number),
100 (char *)dimm->module_part_number);
101}
102
103static void print_dmi_info(const TYPE17_DMI_INFO *dmi17)
104{
105 printk(BIOS_DEBUG,
106 "AGESA TYPE 17 DMI INFO:\n"
107 " Handle: %hu\n"
108 " TotalWidth: %hu\n"
109 " DataWidth: %hu\n"
110 " MemorySize: %hu\n"
111 " DeviceSet: %hhu\n"
112 " Speed: %hu\n"
113 " ManufacturerIdCode: %llx\n"
114 " Attributes: %hhu\n"
115 " ExtSize: %u\n"
116 " ConfigSpeed: %hu\n"
117 " MemoryType: 0x%x\n"
118 " FormFactor: 0x%x\n"
119 " DeviceLocator: %8s\n"
120 " BankLocator: %10s\n"
121 " SerialNumber(%zu): %9s\n"
122 " PartNumber(%zu): %19s\n",
123 dmi17->Handle,
124 dmi17->TotalWidth,
125 dmi17->DataWidth,
126 dmi17->MemorySize,
127 dmi17->DeviceSet,
128 dmi17->Speed,
129 dmi17->ManufacturerIdCode,
130 dmi17->Attributes,
131 dmi17->ExtSize,
132 dmi17->ConfigSpeed,
133 dmi17->MemoryType,
134 dmi17->FormFactor,
135 dmi17->DeviceLocator,
136 dmi17->BankLocator,
137 strlen((const char *)dmi17->SerialNumber),
138 dmi17->SerialNumber,
139 strlen((const char *)dmi17->PartNumber),
140 dmi17->PartNumber);
141}
142
143/**
144 * Marshalls dimm info from AMD_FSP_DMI_HOB into CBMEM_ID_MEMINFO
145 */
146static void prepare_dmi_17(void *unused)
147{
148 const DMI_INFO *dmi_table;
149 const TYPE17_DMI_INFO *type17_dmi_info;
150 struct memory_info *mem_info;
151 struct dimm_info *dimm_info;
152 char cbi_part_number[DIMM_INFO_PART_NUMBER_SIZE];
153 bool use_cbi_part_number = false;
154 size_t dimm_cnt = 0;
155 size_t amd_fsp_dmi_hob_size;
156 const EFI_GUID amd_fsp_dmi_hob_guid = AMD_FSP_DMI_HOB_GUID;
157
158 printk(BIOS_DEBUG, "Saving dimm info for smbios type 17\n");
159
160 /* Allocate meminfo in cbmem. */
161 mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(struct memory_info));
162 if (!mem_info) {
163 printk(BIOS_ERR,
164 "Failed to add memory info to CBMEM, DMI tables will be incomplete\n");
165 return;
166 }
167 memset(mem_info, 0, sizeof(struct memory_info));
168
169 /* Locate the memory info HOB. */
170 dmi_table = fsp_find_extension_hob_by_guid(
171 (const uint8_t *)&amd_fsp_dmi_hob_guid, &amd_fsp_dmi_hob_size);
172
173 if (dmi_table == NULL || amd_fsp_dmi_hob_size == 0) {
174 printk(BIOS_ERR,
175 "AMD_FSP_DMI_HOB not found, DMI table 17 will be incomplete\n");
176 return;
177 }
178 printk(BIOS_DEBUG, "AMD_FSP_DMI_HOB found\n");
179
Nikolai Vyssotski60d67ce2021-04-28 19:26:37 -0500180 if (CONFIG(EC_GOOGLE_CHROMEEC)) {
Rob Barnes009a23d2020-04-13 01:27:12 -0600181 /* Prefer DRAM part number from CBI. */
182 if (google_chromeec_cbi_get_dram_part_num(
183 cbi_part_number, sizeof(cbi_part_number)) == 0) {
184 use_cbi_part_number = true;
185 } else {
186 printk(BIOS_ERR, "Could not obtain DRAM part number from CBI\n");
187 }
188 }
189
190 for (unsigned int channel = 0; channel < MAX_CHANNELS_PER_SOCKET; channel++) {
191 for (unsigned int dimm = 0; dimm < MAX_DIMMS_PER_CHANNEL; dimm++) {
192 type17_dmi_info = &dmi_table->T17[0][channel][dimm];
193 /* DIMMs that are present will have a non-zero
194 handle. */
195 if (type17_dmi_info->Handle == 0)
196 continue;
197 print_dmi_info(type17_dmi_info);
198 dimm_info = &mem_info->dimm[dimm_cnt];
199 dimm_info->channel_num = channel;
200 dimm_info->dimm_num = channel;
201 transfer_memory_info(type17_dmi_info, dimm_info);
202 if (use_cbi_part_number) {
203 /* mem_info is memset to 0 above, so it's
204 safe to assume module_part_number will be
205 null terminated */
206 strncpy((char *)dimm_info->module_part_number, cbi_part_number,
207 sizeof(dimm_info->module_part_number) - 1);
208 }
209 print_dimm_info(dimm_info);
210 dimm_cnt++;
211 }
212 }
213 mem_info->dimm_cnt = dimm_cnt;
214}
215
216/* AMD_FSP_DMI_HOB is initialized very late, so check it just in time for writing tables. */
217BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY, prepare_dmi_17, NULL);