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> Reviewed-on: https://review.coreboot.org/c/coreboot/+/85025 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Karthik Ramasubramanian <kramasub@google.com> Reviewed-by: Kapil Porwal <kapilporwal@google.com>
This commit is contained in:
parent
2dd8f2e13b
commit
28f71b5c3a
1 changed files with 46 additions and 0 deletions
|
|
@ -430,6 +430,9 @@ static int pmc_prev_sleep_state(const struct chipset_power_state *ps)
|
|||
|
||||
/* 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 @@ static int pmc_prev_sleep_state(const struct chipset_power_state *ps)
|
|||
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 @@ void pmc_fill_pm_reg_info(struct chipset_power_state *ps)
|
|||
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 & SLP_TYP)) {
|
||||
printk(BIOS_DEBUG, "Enforcing the S5 exit path\n");
|
||||
uint32_t pm1_cnt_slp_type = SLP_TYP_S5 << SLP_TYP_SHIFT;
|
||||
ps->pm1_cnt |= pm1_cnt_slp_type;
|
||||
pmc_enable_pm1_control(pm1_cnt_slp_type);
|
||||
}
|
||||
|
||||
printk(BIOS_DEBUG, "pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
|
||||
ps->pm1_sts, ps->pm1_en, ps->pm1_cnt);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue