diff --git a/src/soc/intel/skylake/include/soc/pm.h b/src/soc/intel/skylake/include/soc/pm.h index 4d9abcb20d..2e722bf206 100644 --- a/src/soc/intel/skylake/include/soc/pm.h +++ b/src/soc/intel/skylake/include/soc/pm.h @@ -21,6 +21,9 @@ #ifndef _SOC_PM_H_ #define _SOC_PM_H_ +#include +#include + /* ACPI_BASE_ADDRESS / PMBASE */ #define PM1_STS 0x00 @@ -169,4 +172,12 @@ uint8_t *pmc_mmio_regs(void); /* Get base address of TCO I/O registers. */ uint16_t pmc_tco_regs(void); +static inline int deep_s3_enabled(void) +{ + uint32_t deep_s3_pol; + + deep_s3_pol = read32(pmc_mmio_regs() + S3_PWRGATE_POL); + return !!(deep_s3_pol & (S3DC_GATE_SUS | S3AC_GATE_SUS)); +} + #endif diff --git a/src/soc/intel/skylake/romstage/power_state.c b/src/soc/intel/skylake/romstage/power_state.c index 4ffa381b11..5c94e89fd7 100644 --- a/src/soc/intel/skylake/romstage/power_state.c +++ b/src/soc/intel/skylake/romstage/power_state.c @@ -74,8 +74,22 @@ static int prev_sleep_state(struct chipset_power_state *ps) outl(ps->pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT); } - if (ps->gen_pmcon_b & (PWR_FLR | SUS_PWR_FLR)) - prev_sleep_state = SLEEP_STATE_S5; + /* + * If waking from S3 determine if deep S3 is enabled. If not, + * need to check both deep sleep well and normal suspend well. + * Otherwise just check deep sleep well. + */ + if (prev_sleep_state == SLEEP_STATE_S3) { + /* PWR_FLR represents deep sleep power well loss. */ + uint32_t mask = PWR_FLR; + + /* If deep s3 isn't enabled check the suspend well too. */ + if (!deep_s3_enabled()) + mask |= SUS_PWR_FLR; + + if (ps->gen_pmcon_b & mask) + prev_sleep_state = SLEEP_STATE_S5; + } return prev_sleep_state; }