soc/apollolake: Return correct wake status in _SWS
Wake status is calculated from the four pairs of gpe0 in cbmem CBMEM_ID_POWER_STATE which is filled very early in romstage and depends on the routing information in PMC GPE_CFG register. Coreboot sets the proper value of routing based on devicetree from pmc_init. But when system goes to S3 on waking up PMC is writing default values again in GPE_CFG which results in returning wrong wake status in _SWS. This patch corrects that behaviour by correcting the gpe0 pairs in cbmem after PMC sets the routing table in resume path. BUG=chrome-os-partner:54876 TEST=On resume through powerbtn, lidopen, keyboard press, etc. we are getting proper wake status. Change-Id: I5942d5c20d8c6aef73468dc611190bb7c49c7c7a Signed-off-by: Shaunak Saha <shaunak.saha@intel.com> Reviewed-on: https://review.coreboot.org/16040 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Brandon Breitenstein <brandon.breitenstein@intel.com>
This commit is contained in:
parent
b6739d1b56
commit
60b4618a84
|
@ -44,6 +44,7 @@ config CPU_SPECIFIC_OPTIONS
|
|||
select SMM_TSEG
|
||||
select SOC_INTEL_COMMON
|
||||
select SOC_INTEL_COMMON_ACPI
|
||||
select SOC_INTEL_COMMON_ACPI_WAKE_SOURCE
|
||||
select SOC_INTEL_COMMON_LPSS_I2C
|
||||
select SOC_INTEL_COMMON_SMI
|
||||
select SPI_FLASH
|
||||
|
|
|
@ -168,6 +168,41 @@ static void acpi_create_gnvs(struct global_nvs_t *gnvs)
|
|||
|
||||
/* Enable DPTF based on mainboard configuration */
|
||||
gnvs->dpte = cfg->dptf_enable;
|
||||
|
||||
/* Set unknown wake source */
|
||||
gnvs->pm1i = ~0ULL;
|
||||
}
|
||||
|
||||
/* Save wake source information for calculating ACPI _SWS values */
|
||||
int soc_fill_acpi_wake(uint32_t *pm1, uint32_t **gpe0)
|
||||
{
|
||||
struct chipset_power_state *ps;
|
||||
static uint32_t gpe0_sts[GPE0_REG_MAX];
|
||||
uint32_t pm1_en;
|
||||
int i;
|
||||
|
||||
ps = cbmem_find(CBMEM_ID_POWER_STATE);
|
||||
if (ps == NULL)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* PM1_EN to check the basic wake events which can happen through
|
||||
* powerbtn or any other wake source like lidopen, key board press etc.
|
||||
* WAK_STS bit is set when the system is in one of the sleep states
|
||||
* (via the SLP_EN bit) and an enabled wake event occurs. Upon setting
|
||||
* this bit, the PMC will transition the system to the ON state and
|
||||
* can only be set by hardware and can only be cleared by writing a one
|
||||
* to this bit position.
|
||||
*/
|
||||
pm1_en = ps->pm1_en | WAK_STS | RTC_EN | PWRBTN_EN;
|
||||
*pm1 = ps->pm1_sts & pm1_en;
|
||||
|
||||
/* Mask off GPE0 status bits that are not enabled */
|
||||
*gpe0 = &gpe0_sts[0];
|
||||
for (i = 0; i < GPE0_REG_MAX; i++)
|
||||
gpe0_sts[i] = ps->gpe0_sts[i] & ps->gpe0_en[i];
|
||||
|
||||
return GPE0_REG_MAX;
|
||||
}
|
||||
|
||||
void southbridge_inject_dsdt(device_t device)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#define PM1_STS 0x00
|
||||
#define WAK_STS (1 << 15)
|
||||
#define RTC_STS (1 << 10)
|
||||
#define PWRBTN_STS (1 << 8)
|
||||
|
||||
#define PM1_EN 0x02
|
||||
|
@ -162,6 +163,8 @@ struct chipset_power_state {
|
|||
|
||||
int fill_power_state(struct chipset_power_state *ps);
|
||||
int chipset_prev_sleep_state(struct chipset_power_state *ps);
|
||||
/* Rewrite the gpe0 registers in cbmem to proper values as per routing table */
|
||||
void fixup_power_state(void);
|
||||
|
||||
/* Power Management Utility Functions. */
|
||||
uint32_t clear_smi_status(void);
|
||||
|
|
|
@ -117,6 +117,9 @@ static void pmc_gpe_init(void)
|
|||
|
||||
/* Set the routes in the GPIO communities as well. */
|
||||
gpio_route_gpe(dw1, dw2, dw3);
|
||||
|
||||
/* Reset the power state in cbmem as routing */
|
||||
fixup_power_state();
|
||||
}
|
||||
|
||||
static void pmc_init(struct device *dev)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <arch/io.h>
|
||||
#include <console/console.h>
|
||||
#include <cbmem.h>
|
||||
#include <rules.h>
|
||||
#include <device/pci_def.h>
|
||||
#include <halt.h>
|
||||
|
@ -327,6 +328,30 @@ int chipset_prev_sleep_state(struct chipset_power_state *ps)
|
|||
return prev_sleep_state;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function re-writes the gpe0 register values in power state
|
||||
* cbmem variable. After system wakes from sleep state internal PMC logic
|
||||
* writes default values in GPE_CFG register which gives a wrong offset to
|
||||
* calculate the wake reason. So we need to set it again to the routing
|
||||
* table as per the devicetree.
|
||||
*/
|
||||
void fixup_power_state(void)
|
||||
{
|
||||
int i;
|
||||
struct chipset_power_state *ps;
|
||||
|
||||
ps = cbmem_find(CBMEM_ID_POWER_STATE);
|
||||
if (ps == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < GPE0_REG_MAX; i++) {
|
||||
ps->gpe0_sts[i] = inl(ACPI_PMIO_BASE + GPE0_STS(i));
|
||||
ps->gpe0_en[i] = inl(ACPI_PMIO_BASE + GPE0_EN(i));
|
||||
printk(BIOS_DEBUG, "gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n",
|
||||
i, ps->gpe0_sts[i], i, ps->gpe0_en[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* returns prev_sleep_state */
|
||||
int fill_power_state(struct chipset_power_state *ps)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue