sb/intel/bd82x6x: Fix CPU replaced check

Check if CPU has been replaced before doing ram init. When it
has been replaced disable MRC cache and do a full memory training.

Also use get_us_since_boot() to skip waiting additional 50msec
when not necessary. Setting up NEM in bootblock is so slow that
50msec might already have passed.

Before:
 940:waiting for ME acknowledgment of raminit          116,514 (62,804)
After:
 940:waiting for ME acknowledgment of raminit          68,708 (7,211)

Boots 48msec faster than before.

Change-Id: I2d9729792c3546dc9bf23192c42619cd7d639d1c
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/88794
Reviewed-by: Paul Menzel <paulepanter@mailbox.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
This commit is contained in:
Patrick Rudolph 2025-08-14 15:14:48 +02:00 committed by Matt DeVillier
commit b0a63052b7
3 changed files with 54 additions and 23 deletions

View file

@ -411,6 +411,9 @@ static void init_dram_ddr3(int s3resume, const u32 cpuid)
fast_boot = s3resume;
}
if (fast_boot && intel_early_me_cpu_replaced())
fast_boot = false;
if (fast_boot) {
printk(BIOS_DEBUG, "Trying stored timings.\n");
memcpy(&ctrl, ctrl_cached, sizeof(ctrl));

View file

@ -85,6 +85,56 @@ int intel_early_me_uma_size(void)
return 0;
}
/**
* Check if ME reports that CPU has been replaced.
*
* @return TRUE when CPU was replaced and full
* memory training is required.
*/
bool intel_early_me_cpu_replaced(void)
{
u32 millisec;
union me_gmes gmes;
gmes.raw = pci_read_config32(PCH_ME_DEV, PCI_ME_GMES);
/*
* Poll CPU replaced status until 50 ms have elapsed since boot.
* The ME FW should've had enough time to wake up at this point.
*/
millisec = get_us_since_boot() / 1000;
while (!gmes.cpu_replaced_valid && millisec < 50) {
udelay(1000);
gmes.raw = pci_read_config32(PCH_ME_DEV, PCI_ME_GMES);
millisec++;
}
if (gmes.cpu_replaced_valid) {
if (gmes.warm_rst_req_for_df) {
/*
* DF (Dynamic Fusing) is when the ME updates the CAPID0
* register in the host bridge depending on the PCH SKU.
*/
printk(BIOS_NOTICE, "CPU was replaced & warm reset required...\n");
/* Indicate DRAM init not done for MRC */
pci_and_config8(PCH_LPC_DEV, GEN_PMCON_2, 0x7f);
set_global_reset(0);
system_reset();
return true;
}
if (gmes.cpu_replaced_sts) {
printk(BIOS_NOTICE, "Full memory training required\n");
return true;
}
} else {
/* CPU replaced is still not valid (bad ME FW?) */
printk(BIOS_NOTICE, "CPU replaced is not valid, assuming CPU was not replaced...\n");
}
return false;
}
int intel_early_me_init_done(u8 status)
{
u8 reset, errorcode, opmode;
@ -128,28 +178,6 @@ int intel_early_me_init_done(u8 status)
printk(BIOS_NOTICE, "ME: Current PM event: 0x%x\n", (me_fws2 & 0xf000000) >> 24);
printk(BIOS_NOTICE, "ME: Progress code : 0x%x\n", (me_fws2 & 0xf0000000) >> 28);
/* Poll CPU replaced for 50ms */
millisec = 0;
while ((((me_fws2 & 0x100) >> 8) == 0) && millisec < 50) {
udelay(1000);
me_fws2 = pci_read_config32(PCH_ME_DEV, PCI_ME_GMES);
millisec++;
}
if (millisec >= 50 || ((me_fws2 & 0x100) >> 8) == 0x0) {
printk(BIOS_NOTICE, "Waited long enough, or CPU was not replaced, continue...\n");
} else if ((me_fws2 & 0x100) == 0x100) {
if ((me_fws2 & 0x80) == 0x80) {
printk(BIOS_NOTICE, "CPU was replaced & warm reset required...\n");
pci_and_config16(PCH_LPC_DEV, GEN_PMCON_2, ~0x80);
set_global_reset(0);
system_reset();
}
if (((me_fws2 & 0x10) == 0x10) && (me_fws2 & 0x80) == 0x00) {
printk(BIOS_NOTICE, "Full training required\n");
}
}
printk(BIOS_NOTICE, "PASSED! Tell ME that DRAM is ready\n");
/* MEBASE from MESEG_BASE[35:20] */

View file

@ -293,7 +293,7 @@ void intel_early_me_status(void);
int intel_early_me_init(void);
int intel_early_me_uma_size(void);
int intel_early_me_init_done(u8 status);
bool intel_early_me_cpu_replaced(void);
void intel_me_finalize_smm(void);
typedef struct {