Subrata Banik has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/85025?usp=email )
Change subject: soc/intel/cmn/pmc: Perform PM register init for CSE ......................................................................
soc/intel/cmn/pmc: Perform PM register init for CSE
Before entering FSP-M, AP firmware must ensure the PM1_CNT register reflects the correct sleep state if a global reset occurred.
This is crucial when Intel CSE has reset the system, as indicated by the global reset bit and wake status register.
If PM1_CNT doesn't contain a valid sleep state after a CSE reset, AP firmware must enforce an S5 exit path before handing control to FSP-M for CSE initialization. This ensures proper system initialization and avoids potential issues caused by an inconsistent sleep state.
Additionally, clears the PM1 status register (PM1_STS) after retrieving the power state. This prevents stale status information from persisting across power cycles, which could lead to confusion during subsequent boots.
BUG=b:265939425 TEST=Verified that `prev_sleep_state` holds the correct value (5 for S5) after CSE performs a global reset.
Fixes: Inconsistent sleep state after CSE reset.
Change-Id: Iae9c026da86fef4a3571e06b1bb20504c3d8c9be Signed-off-by: Subrata Banik subratabanik@google.com --- M src/soc/intel/common/block/pmc/pmclib.c 1 file changed, 46 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/25/85025/1
diff --git a/src/soc/intel/common/block/pmc/pmclib.c b/src/soc/intel/common/block/pmc/pmclib.c index 0b3863a..17adf1f 100644 --- a/src/soc/intel/common/block/pmc/pmclib.c +++ b/src/soc/intel/common/block/pmc/pmclib.c @@ -430,6 +430,9 @@
/* Clear SLP_TYP. */ pmc_write_pm1_control(ps->pm1_cnt & ~(SLP_TYP)); + + /* Clear PM1_STATUS */ + pmc_clear_pm1_status(); }
prev_sleep_state = soc_prev_sleep_state(ps, prev_sleep_state); @@ -440,6 +443,34 @@ return prev_sleep_state; }
+static bool pmc_get_global_reset_sts_mmio(void) +{ + uint8_t *addr = pmc_mmio_regs(); + + return !!(read32p((uintptr_t)(addr + GEN_PMCON_A)) & GBL_RST_STS); +} + +static bool pmc_get_global_reset_sts_pci(void) +{ +#if defined(__SIMPLE_DEVICE__) + pci_devfn_t dev = PCI_DEV(0, PCI_SLOT(PCH_DEVFN_PMC), PCI_FUNC(PCH_DEVFN_PMC)); +#else + struct device *dev = pcidev_path_on_root(PCH_DEVFN_PMC); + if (!dev) + return false; +#endif + + return !!(pci_read_config32(dev, GEN_PMCON_A) & GBL_RST_STS); +} + +static bool pmc_get_global_reset_sts(void) +{ + if (CONFIG(SOC_INTEL_MEM_MAPPED_PM_CONFIGURATION)) + return pmc_get_global_reset_sts_mmio(); + else + return pmc_get_global_reset_sts_pci(); +} + void pmc_fill_pm_reg_info(struct chipset_power_state *ps) { int i; @@ -450,6 +481,21 @@ ps->pm1_en = inw(ACPI_BASE_ADDRESS + PM1_EN); ps->pm1_cnt = pmc_read_pm1_control();
+ /* + * Before system memory initialization, AP firmware should check the wake status + * to determine if Intel CSE has reset the system and system sleep state (PM1_CNT) + * holds a valid sleep entry? + * + * If not, then AP FW should force to take a S5 exit path (by programming the PM1_CNT) + * register as per PM register initialization requirement for CSE. + */ + if (pmc_get_global_reset_sts() && (ps->pm1_sts & WAK_STS) && !ps->pm1_cnt) { + printk(BIOS_DEBUG, "Enforcing the S5 exit path\n"); + uint32_t pm1_cnt_value = SLP_TYP_S5 << SLP_TYP_SHIFT; + ps->pm1_cnt = pm1_cnt_value; + pmc_enable_pm1_control(pm1_cnt_value); + } + printk(BIOS_DEBUG, "pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n", ps->pm1_sts, ps->pm1_en, ps->pm1_cnt);