1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/romstage.h>
5 #include <console/console.h>
7 #include <intelblocks/cfg.h>
8 #include <intelblocks/cse.h>
9 #include <intelblocks/pmclib.h>
10 #include <memory_info.h>
11 #include <soc/intel/common/smbios.h>
12 #include <soc/iomap.h>
14 #include <soc/romstage.h>
15 #include <soc/soc_chip.h>
18 #define FSP_SMBIOS_MEMORY_INFO_GUID \
20 0xd4, 0x71, 0x20, 0x9b, 0x54, 0xb0, 0x0c, 0x4e, \
21 0x8d, 0x09, 0x11, 0xcf, 0x8b, 0x9f, 0x03, 0x23 \
24 /* Save the DIMM information for SMBIOS table 17 */
25 static void save_dimm_info(void)
27 int node
, channel
, dimm
, dimm_max
, index
;
29 const CONTROLLER_INFO
*ctrlr_info
;
30 const CHANNEL_INFO
*channel_info
;
31 const DIMM_INFO
*src_dimm
;
32 struct dimm_info
*dest_dimm
;
33 struct memory_info
*mem_info
;
34 const MEMORY_INFO_DATA_HOB
*meminfo_hob
;
35 const uint8_t smbios_memory_info_guid
[16] =
36 FSP_SMBIOS_MEMORY_INFO_GUID
;
37 const uint8_t *serial_num
;
38 const char *dram_part_num
= NULL
;
39 size_t dram_part_num_len
= 0;
40 bool is_dram_part_overridden
= false;
42 /* Locate the memory info HOB, presence validated by raminit */
43 meminfo_hob
= fsp_find_extension_hob_by_guid(
44 smbios_memory_info_guid
,
46 if (meminfo_hob
== NULL
|| hob_size
== 0) {
47 printk(BIOS_ERR
, "SMBIOS MEMORY_INFO_DATA_HOB not found\n");
52 * Allocate CBMEM area for DIMM information used to populate SMBIOS
55 mem_info
= cbmem_add(CBMEM_ID_MEMINFO
, sizeof(*mem_info
));
56 if (mem_info
== NULL
) {
57 printk(BIOS_ERR
, "CBMEM entry for DIMM info missing\n");
60 memset(mem_info
, 0, sizeof(*mem_info
));
62 /* Allow mainboard to override DRAM part number. */
63 dram_part_num
= mainboard_get_dram_part_num();
65 dram_part_num_len
= strlen(dram_part_num
);
66 is_dram_part_overridden
= true;
69 /* Save available DIMM information */
71 dimm_max
= ARRAY_SIZE(mem_info
->dimm
);
72 for (node
= 0; node
< MAX_NODE
; node
++) {
73 ctrlr_info
= &meminfo_hob
->Controller
[node
];
74 for (channel
= 0; channel
< MAX_CH
&& index
< dimm_max
;
76 channel_info
= &ctrlr_info
->ChannelInfo
[channel
];
77 if (channel_info
->Status
!= CHANNEL_PRESENT
)
80 for (dimm
= 0; dimm
< MAX_DIMM
&& index
< dimm_max
;
82 src_dimm
= &channel_info
->DimmInfo
[dimm
];
83 dest_dimm
= &mem_info
->dimm
[index
];
84 if (src_dimm
->Status
!= DIMM_PRESENT
)
87 /* If there is no DRAM part number overridden by
88 * mainboard then use original one. */
89 if (!is_dram_part_overridden
) {
90 dram_part_num_len
= sizeof(src_dimm
->ModulePartNum
);
91 dram_part_num
= (const char *)
92 &src_dimm
->ModulePartNum
[0];
95 u8 memProfNum
= meminfo_hob
->MemoryProfile
;
96 serial_num
= src_dimm
->SpdSave
+
97 SPD_SAVE_OFFSET_SERIAL
;
99 /* Populate the DIMM information */
100 dimm_info_fill(dest_dimm
,
101 src_dimm
->DimmCapacity
,
102 meminfo_hob
->MemoryType
,
103 meminfo_hob
->ConfiguredMemoryClockSpeed
,
104 src_dimm
->RankInDimm
,
105 channel_info
->ChannelId
,
110 meminfo_hob
->DataWidth
,
111 meminfo_hob
->VddVoltage
[memProfNum
],
112 meminfo_hob
->EccSupport
,
114 src_dimm
->SpdModuleType
);
119 mem_info
->dimm_cnt
= index
;
120 printk(BIOS_DEBUG
, "%d DIMMs found\n", mem_info
->dimm_cnt
);
123 void mainboard_romstage_entry(void)
126 struct chipset_power_state
*ps
= pmc_get_power_state();
128 /* Program MCHBAR, DMIBAR, GDXBAR and EDRAMBAR */
129 systemagent_early_init();
130 /* Program PCH init */
132 /* initialize Heci interface */
133 heci_init(HECI1_BASE_ADDRESS
);
135 s3wake
= pmc_fill_power_state(ps
) == ACPI_S3
;
136 fsp_memory_init(s3wake
);
140 * cse_fw_sync() must be called after DRAM initialization as
141 * HMRFPO_ENABLE HECI command (which is used by cse_fw_sync())
142 * is expected to be executed after DRAM initialization.
145 if (CONFIG(SOC_INTEL_CSE_LITE_SKU
))