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 <intelblocks/smbus.h>
11 #include <memory_info.h>
12 #include <soc/intel/common/smbios.h>
13 #include <soc/iomap.h>
15 #include <soc/romstage.h>
16 #include <soc/soc_chip.h>
19 #define FSP_SMBIOS_MEMORY_INFO_GUID \
21 0xd4, 0x71, 0x20, 0x9b, 0x54, 0xb0, 0x0c, 0x4e, \
22 0x8d, 0x09, 0x11, 0xcf, 0x8b, 0x9f, 0x03, 0x23 \
25 /* Save the DIMM information for SMBIOS table 17 */
26 static void save_dimm_info(void)
28 int node
, channel
, dimm
, dimm_max
, index
;
30 const CONTROLLER_INFO
*ctrlr_info
;
31 const CHANNEL_INFO
*channel_info
;
32 const DIMM_INFO
*src_dimm
;
33 struct dimm_info
*dest_dimm
;
34 struct memory_info
*mem_info
;
35 const MEMORY_INFO_DATA_HOB
*meminfo_hob
;
36 const uint8_t smbios_memory_info_guid
[16] =
37 FSP_SMBIOS_MEMORY_INFO_GUID
;
38 const uint8_t *serial_num
;
39 const char *dram_part_num
= NULL
;
40 size_t dram_part_num_len
= 0;
41 bool is_dram_part_overridden
= false;
43 /* Locate the memory info HOB, presence validated by raminit */
44 meminfo_hob
= fsp_find_extension_hob_by_guid(
45 smbios_memory_info_guid
,
47 if (meminfo_hob
== NULL
|| hob_size
== 0) {
48 printk(BIOS_ERR
, "SMBIOS MEMORY_INFO_DATA_HOB not found\n");
53 * Allocate CBMEM area for DIMM information used to populate SMBIOS
56 mem_info
= cbmem_add(CBMEM_ID_MEMINFO
, sizeof(*mem_info
));
57 if (mem_info
== NULL
) {
58 printk(BIOS_ERR
, "CBMEM entry for DIMM info missing\n");
61 memset(mem_info
, 0, sizeof(*mem_info
));
63 /* Allow mainboard to override DRAM part number. */
64 dram_part_num
= mainboard_get_dram_part_num();
66 dram_part_num_len
= strlen(dram_part_num
);
67 is_dram_part_overridden
= true;
70 /* Save available DIMM information */
72 dimm_max
= ARRAY_SIZE(mem_info
->dimm
);
73 for (node
= 0; node
< MAX_NODE
; node
++) {
74 ctrlr_info
= &meminfo_hob
->Controller
[node
];
75 for (channel
= 0; channel
< MAX_CH
&& index
< dimm_max
;
77 channel_info
= &ctrlr_info
->ChannelInfo
[channel
];
78 if (channel_info
->Status
!= CHANNEL_PRESENT
)
81 for (dimm
= 0; dimm
< MAX_DIMM
&& index
< dimm_max
;
83 src_dimm
= &channel_info
->DimmInfo
[dimm
];
84 dest_dimm
= &mem_info
->dimm
[index
];
85 if (src_dimm
->Status
!= DIMM_PRESENT
)
88 /* If there is no DRAM part number overridden by
89 * mainboard then use original one. */
90 if (!is_dram_part_overridden
) {
91 dram_part_num_len
= sizeof(src_dimm
->ModulePartNum
);
92 dram_part_num
= (const char *)
93 &src_dimm
->ModulePartNum
[0];
96 u8 memProfNum
= meminfo_hob
->MemoryProfile
;
97 serial_num
= src_dimm
->SpdSave
+
98 SPD_SAVE_OFFSET_SERIAL
;
100 /* Populate the DIMM information */
101 dimm_info_fill(dest_dimm
,
102 src_dimm
->DimmCapacity
,
103 meminfo_hob
->MemoryType
,
104 meminfo_hob
->ConfiguredMemoryClockSpeed
,
105 src_dimm
->RankInDimm
,
106 channel_info
->ChannelId
,
111 meminfo_hob
->DataWidth
,
112 meminfo_hob
->VddVoltage
[memProfNum
],
113 meminfo_hob
->EccSupport
,
115 src_dimm
->SpdModuleType
,
117 meminfo_hob
->MaximumMemoryClockSpeed
);
122 mem_info
->dimm_cnt
= index
;
123 printk(BIOS_DEBUG
, "%d DIMMs found\n", mem_info
->dimm_cnt
);
126 void mainboard_romstage_entry(void)
129 struct chipset_power_state
*ps
= pmc_get_power_state();
131 /* Program MCHBAR, DMIBAR, GDXBAR and EDRAMBAR */
132 systemagent_early_init();
133 /* Program SMBus base address and enable it */
135 /* initialize Heci interface */
136 cse_init(HECI1_BASE_ADDRESS
);
138 s3wake
= pmc_fill_power_state(ps
) == ACPI_S3
;
139 fsp_memory_init(s3wake
);
143 * cse_fw_sync() must be called after DRAM initialization as
144 * HMRFPO_ENABLE HECI command (which is used by cse_fw_sync())
145 * is expected to be executed after DRAM initialization.
148 if (CONFIG(SOC_INTEL_CSE_LITE_SKU
))