blob: f4eae9c4a91f085dd33a959eefbd28d647abf72f [file] [log] [blame]
Jonathan Zhang15fc4592023-01-25 11:33:16 -08001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <assert.h>
4#include <cpu/cpu.h>
5#include <cpu/intel/cpu_ids.h>
6#include <arch/romstage.h>
7#include <console/console.h>
8#include <cbmem.h>
9#include <drivers/vpd/vpd.h>
10#include <drivers/ocp/include/vpd.h>
11#include <security/intel/txt/txt.h>
12#include <fsp/api.h>
13#include <fsp/util.h>
14#include <hob_iiouds.h>
15#include <hob_memmap.h>
16#include <soc/romstage.h>
17#include <soc/pci_devs.h>
18#include <soc/intel/common/smbios.h>
19#include <string.h>
20#include <soc/soc_util.h>
21#include <soc/ddr.h>
22
23#include "chip.h"
24
25/* Initialize to all zero first */
26static UPD_IIO_PCIE_PORT_CONFIG spr_iio_bifur_table[CONFIG_MAX_SOCKET_UPD];
27static UINT8 deemphasis_list[CONFIG_MAX_SOCKET_UPD * MAX_IIO_PORTS_PER_SOCKET];
28
29void __weak mainboard_memory_init_params(FSPM_UPD *mupd)
30{
31 /* Default weak implementation */
32}
33
34bool __weak mainboard_dimm_slot_exists(uint8_t socket, uint8_t channel, uint8_t dimm)
35{
36 return false;
37}
38
39/*
40 * Search from VPD_RW first then VPD_RO for UPD config variables,
41 * overwrites them from VPD if it's found.
42 */
43static void config_upd_from_vpd(FSPM_UPD *mupd)
44{
45 uint8_t val;
46 int val_int, cxl_mode;
47
48 /* Send FSP log message to SOL */
49 if (vpd_get_bool(FSP_LOG, VPD_RW_THEN_RO, &val))
50 mupd->FspmConfig.SerialIoUartDebugEnable = val;
51 else {
52 printk(BIOS_INFO,
53 "Not able to get VPD %s, default set "
54 "SerialIoUartDebugEnable to %d\n",
55 FSP_LOG, FSP_LOG_DEFAULT);
56 mupd->FspmConfig.SerialIoUartDebugEnable = FSP_LOG_DEFAULT;
57 }
58
59 if (mupd->FspmConfig.SerialIoUartDebugEnable) {
60 /* FSP memory debug log level */
61 if (vpd_get_int(FSP_MEM_LOG_LEVEL, VPD_RW_THEN_RO, &val_int)) {
62 if (val_int < 0 || val_int > 4) {
63 printk(BIOS_DEBUG,
64 "Invalid serialDebugMsgLvl value from VPD: "
65 "%d\n",
66 val_int);
67 val_int = FSP_MEM_LOG_LEVEL_DEFAULT;
68 }
69 printk(BIOS_DEBUG, "Setting serialDebugMsgLvl to %d\n", val_int);
70 mupd->FspmConfig.serialDebugMsgLvl = (uint8_t)val_int;
71 } else {
72 printk(BIOS_INFO,
73 "Not able to get VPD %s, default set "
74 "DebugPrintLevel to %d\n",
75 FSP_MEM_LOG_LEVEL, FSP_MEM_LOG_LEVEL_DEFAULT);
76 mupd->FspmConfig.serialDebugMsgLvl = FSP_MEM_LOG_LEVEL_DEFAULT;
77 }
78 /* If serialDebugMsgLvl less than 1, disable FSP memory train results */
79 if (mupd->FspmConfig.serialDebugMsgLvl <= 1) {
80 printk(BIOS_DEBUG, "Setting serialDebugMsgLvlTrainResults to 0\n");
81 mupd->FspmConfig.serialDebugMsgLvlTrainResults = 0x0;
82 }
83 }
84
85 /* FSP Dfx PMIC Secure mode */
86 if (vpd_get_int(FSP_PMIC_SECURE_MODE, VPD_RW_THEN_RO, &val_int)) {
87 if (val_int < 0 || val_int > 2) {
88 printk(BIOS_DEBUG,
89 "Invalid PMIC secure mode value from VPD: "
90 "%d\n",
91 val_int);
92 val_int = FSP_PMIC_SECURE_MODE_DEFAULT;
93 }
94 printk(BIOS_DEBUG, "Setting PMIC secure mode to %d\n", val_int);
95 mupd->FspmConfig.DfxPmicSecureMode = (uint8_t)val_int;
96 } else {
97 printk(BIOS_INFO,
98 "Not able to get VPD %s, default set "
99 "PMIC secure mode to %d\n",
100 FSP_PMIC_SECURE_MODE, FSP_PMIC_SECURE_MODE_DEFAULT);
101 mupd->FspmConfig.DfxPmicSecureMode = FSP_PMIC_SECURE_MODE_DEFAULT;
102 }
103
104 cxl_mode = get_cxl_mode_from_vpd();
105 if (cxl_mode == CXL_SYSTEM_MEMORY || cxl_mode == CXL_SPM)
106 mupd->FspmConfig.DfxCxlType3LegacyEn = 1;
107 else /* Disable CXL */
108 mupd->FspmConfig.DfxCxlType3LegacyEn = 0;
109
110 if (CONFIG(INTEL_TXT)) {
111 /* Configure for error injection test */
112 mupd->FspmConfig.DFXEnable = skip_intel_txt_lockdown() ? 1 : 0;
113 }
114}
115
116/* Initialize non-zero default UPD values for IIO */
117static void initialize_iio_upd(FSPM_UPD *mupd)
118{
119 unsigned int port, socket;
120
121 mupd->FspmConfig.IioPcieConfigTablePtr = (UINT32)spr_iio_bifur_table;
122 mupd->FspmConfig.IioPcieConfigTableNumber = CONFIG_MAX_SOCKET_UPD;
123 UPD_IIO_PCIE_PORT_CONFIG *PciePortConfig =
124 (UPD_IIO_PCIE_PORT_CONFIG *)spr_iio_bifur_table;
125
126 /* Initialize non-zero default UPD values */
127 for (socket = 0; socket < CONFIG_MAX_SOCKET_UPD; socket++) {
128 for (port = 0; port < MAX_IIO_PORTS_PER_SOCKET; port++) {
129 PciePortConfig[socket].PcieMaxPayload[port] = 0x7; /* Auto */
130 PciePortConfig[socket].DfxDnTxPresetGen3[port] = 0xff; /* Auto */
131 }
132 PciePortConfig[socket].PcieGlobalAspm = 0x1; /* Enable ASPM */
133 PciePortConfig[socket].PcieMaxReadRequestSize = 0x5;
134 }
135
136 mupd->FspmConfig.DeEmphasisPtr = (UINT32)deemphasis_list;
137 mupd->FspmConfig.DeEmphasisNumber = CONFIG_MAX_SOCKET_UPD * MAX_IIO_PORTS_PER_SOCKET;
138 UINT8 *DeEmphasisConfig = (UINT8 *)deemphasis_list;
139
140 for (port = 0; port < CONFIG_MAX_SOCKET_UPD * MAX_IIO_PORTS_PER_SOCKET; port++)
141 DeEmphasisConfig[port] = 0x1;
142}
143
144void platform_fsp_memory_init_params_cb(FSPM_UPD *mupd, uint32_t version)
145{
146 FSP_M_CONFIG *m_cfg = &mupd->FspmConfig;
147 const config_t *config = config_of_soc();
148
149 m_cfg->DebugPrintLevel = 0xF;
150
151 m_cfg->DirectoryModeEn = 0x2;
152 const u8 KtiFpgaEnable[] = {0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1};
153 memcpy(m_cfg->KtiFpgaEnable, KtiFpgaEnable, sizeof(m_cfg->KtiFpgaEnable));
154
155 m_cfg->TscSyncEn = 0x1;
156
157 m_cfg->mmiohBase = 0x2000;
158 m_cfg->mmiohSize = 0x3;
159
160 m_cfg->BoardTypeBitmask = 0x11111133;
161
162 m_cfg->X2apic = config->x2apic;
163
164 printk(BIOS_INFO, "m_cfg->X2apic = 0x%x config->x2apic = 0x%x\n", m_cfg->X2apic,
165 config->x2apic);
166
167
168 m_cfg->serialDebugMsgLvl = 0x3;
169
170 m_cfg->VtdSupport = config->vtd_support;
171
Jonathan Zhangd80e6f22023-01-25 11:35:03 -0800172 m_cfg->SerialIoUartDebugIoBase = CONFIG_TTYS0_BASE;
Jonathan Zhang15fc4592023-01-25 11:33:16 -0800173
174 mupd->FspmConfig.AttemptFastBoot = 1;
175 mupd->FspmConfig.AttemptFastBootCold = 1;
176
177 /* Set Patrol Scrub UPD */
178 mupd->FspmConfig.PatrolScrubNotify = 0x1; /* 1:Enable at ReadyToBootFsp() */
179 mupd->FspmConfig.PatrolScrub = 0x2; /* 2:Enable during
180 NotifyPhase(EnumInitPhaseReadyToBoot) */
181 mupd->FspmConfig.ErrorCheckScrub = 1; /* Enable/Disable DDR5 Error Check
182 and Scrub (ECS) in FSP */
183 mupd->FspmConfig.PatrolScrubAddrMode = 1; /* 1:System Physical Address */
184 mupd->FspmConfig.PatrolScrubDuration = 24; /* unit is hour */
185
186 /* Disable below UPDs because those features should be implemented by coreboot */
187 mupd->FspmConfig.LockChipset = 0;
188 mupd->FspmConfig.ProcessorMsrLockControl = 0;
189 /* Don't set and signal MSR_BIOS_DONE in FSP since it should be done by coreboot */
190 mupd->FspmConfig.DfxDisableBiosDone = 1;
191
192 u32 cpu_id = cpu_get_cpuid();
193 if (cpu_id == (u32)CPUID_SAPPHIRERAPIDS_SP_D) {
194 printk(BIOS_DEBUG, "CPU is D stepping, setting package C state to C0/C1\n");
195 mupd->FspmConfig.CpuPmPackageCState = 0;
196 }
197 /* Set some common UPDs from VPD, mainboard can still override them if needed */
198 if (CONFIG(VPD))
199 config_upd_from_vpd(mupd);
200 initialize_iio_upd(mupd);
201 mainboard_memory_init_params(mupd);
202}
203
204static uint8_t get_error_correction_type(const uint8_t RasModesEnabled)
205{
206 switch (RasModesEnabled) {
207 case CH_INDEPENDENT:
208 return MEMORY_ARRAY_ECC_SINGLE_BIT;
209 case FULL_MIRROR_1LM:
210 case PARTIAL_MIRROR_1LM:
211 case FULL_MIRROR_2LM:
212 case PARTIAL_MIRROR_2LM:
213 return MEMORY_ARRAY_ECC_MULTI_BIT;
214 case RK_SPARE:
215 return MEMORY_ARRAY_ECC_SINGLE_BIT;
216 case CH_LOCKSTEP:
217 return MEMORY_ARRAY_ECC_SINGLE_BIT;
218 default:
219 return MEMORY_ARRAY_ECC_MULTI_BIT;
220 }
221}
222
223/* Save the DIMM information for SMBIOS table 17 */
224void save_dimm_info(void)
225{
226 struct dimm_info *dest_dimm;
227 struct memory_info *mem_info;
228 const struct SystemMemoryMapHob *hob;
229 MEMMAP_DIMM_DEVICE_INFO_STRUCT src_dimm;
230 int dimm_max, dimm_num = 0;
231 int index = 0;
232 uint8_t mem_dev_type;
233 uint16_t data_width;
234 uint32_t vdd_voltage;
235
236 hob = get_system_memory_map();
237 assert(hob != NULL);
238
239 /*
240 * Allocate CBMEM area for DIMM information used to populate SMBIOS
241 * table 17
242 */
243 mem_info = cbmem_add(CBMEM_ID_MEMINFO, sizeof(*mem_info));
244 if (mem_info == NULL) {
245 printk(BIOS_ERR, "CBMEM entry for DIMM info missing\n");
246 return;
247 }
248 memset(mem_info, 0, sizeof(*mem_info));
249 /* According to EDS doc#611488, it's 4 TB per processor. */
250 mem_info->max_capacity_mib = 4 * MiB * CONFIG_MAX_SOCKET;
251 mem_info->number_of_devices = CONFIG_DIMM_MAX;
252 mem_info->ecc_type = get_error_correction_type(hob->RasModesEnabled);
253 dimm_max = ARRAY_SIZE(mem_info->dimm);
254 vdd_voltage = get_ddr_millivolt(hob->DdrVoltage);
255 for (int soc = 0; soc < CONFIG_MAX_SOCKET; soc++) {
256 for (int ch = 0; ch < MAX_CH; ch++) {
257 for (int dimm = 0; dimm < MAX_DIMM; dimm++) {
258 if (index >= dimm_max) {
259 printk(BIOS_WARNING, "Too many DIMMs info for %s.\n",
260 __func__);
261 return;
262 }
263
264 src_dimm = hob->Socket[soc].ChannelInfo[ch].DimmInfo[dimm];
265 if (src_dimm.Present) {
266 dest_dimm = &mem_info->dimm[index];
267 index++;
268 } else if (mainboard_dimm_slot_exists(soc, ch, dimm)) {
269 dest_dimm = &mem_info->dimm[index];
270 index++;
271 /* Save DIMM Locator information for SMBIOS Type 17 */
272 dest_dimm->dimm_size = 0;
273 dest_dimm->soc_num = soc;
274 dest_dimm->channel_num = ch;
275 dest_dimm->dimm_num = dimm;
276 continue;
277 } else {
278 /* Ignore DIMM that isn't present and doesn't exist on
279 the board. */
280 continue;
281 }
282 dest_dimm->max_speed_mts =
283 get_max_memory_speed(src_dimm.commonTck);
284 dest_dimm->configured_speed_mts = hob->memFreq;
285 dest_dimm->soc_num = soc;
286
287 if (hob->DramType == SPD_TYPE_DDR5) {
288 /* hard-coded memory device type as DDR5 */
289 mem_dev_type = 0x22;
290 data_width = 64;
291 } else {
292 /* hard-coded memory device type as DDR4 */
293 mem_dev_type = 0x1A;
294 data_width = 64;
295 }
296 dimm_info_fill(
297 dest_dimm, src_dimm.DimmSize << 6, mem_dev_type,
298 hob->memFreq, /* replaced by configured_speed_mts */
299 src_dimm.NumRanks,
300 ch, /* for mainboard locator string override */
301 dimm, /* for mainboard locator string override */
302 (const char *)&src_dimm.PartNumber[0],
303 sizeof(src_dimm.PartNumber),
304 (const uint8_t *)&src_dimm.serialNumber[0], data_width,
305 vdd_voltage, true, /* hard-coded as ECC supported */
306 src_dimm.VendorID, src_dimm.actKeyByte2, 0);
307 dimm_num++;
308 }
309 }
310 }
311
312 mem_info->dimm_cnt = index; /* Number of DIMM slots found */
313 printk(BIOS_DEBUG, "%d Installed DIMMs found\n", dimm_num);
314}