Mohan D'Costa (mohan@ndr.co.jp) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/6937
-gerrit
commit 7ee3e9f83cfd0a2e549b18e6c7c693387b4d356c Author: Mohan D'Costa mohan@ndr.co.jp Date: Thu Sep 18 15:57:06 2014 +0900
intel/fsp_baytrail: Add S3 suspend/resume Support
This adds S3 Suspend / Resume support to Intel's Bay Trail FSP
It is based on the "src/soc/intel/baytrail/romstage/romstage.c" implementation.
Change-Id: If0011068eb7290d1b764c5c4b12c17375fb69008 Signed-off-by: Mohan D'Costa mohan@ndr.co.jp --- src/drivers/intel/fsp/Kconfig | 1 + src/soc/intel/fsp_baytrail/acpi/sleepstates.asl | 3 + src/soc/intel/fsp_baytrail/baytrail/romstage.h | 1 + src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.c | 33 ++++++++++- src/soc/intel/fsp_baytrail/ramstage.c | 32 +++++++++++ src/soc/intel/fsp_baytrail/romstage/romstage.c | 68 ++++++++++++++++++++++- 6 files changed, 133 insertions(+), 5 deletions(-)
diff --git a/src/drivers/intel/fsp/Kconfig b/src/drivers/intel/fsp/Kconfig index 5e44046..2d41365 100644 --- a/src/drivers/intel/fsp/Kconfig +++ b/src/drivers/intel/fsp/Kconfig @@ -63,6 +63,7 @@ config ENABLE_FSP_FAST_BOOT
config ENABLE_MRC_CACHE bool + default y if HAVE_ACPI_RESUME default n help Enabling this feature will cause MRC data to be cached in NV storage. diff --git a/src/soc/intel/fsp_baytrail/acpi/sleepstates.asl b/src/soc/intel/fsp_baytrail/acpi/sleepstates.asl index 65339cc..12e359a 100644 --- a/src/soc/intel/fsp_baytrail/acpi/sleepstates.asl +++ b/src/soc/intel/fsp_baytrail/acpi/sleepstates.asl @@ -21,5 +21,8 @@
Name(_S0, Package(){0x0,0x0,0x0,0x0}) // Name(_S1, Package(){0x1,0x1,0x0,0x0}) +#if CONFIG_HAVE_ACPI_RESUME +Name(_S3, Package(){0x5,0x5,0x0,0x0}) +#endif Name(_S4, Package(){0x6,0x6,0x0,0x0}) Name(_S5, Package(){0x7,0x7,0x0,0x0}) diff --git a/src/soc/intel/fsp_baytrail/baytrail/romstage.h b/src/soc/intel/fsp_baytrail/baytrail/romstage.h index 8feab8a..1ceb4cf 100644 --- a/src/soc/intel/fsp_baytrail/baytrail/romstage.h +++ b/src/soc/intel/fsp_baytrail/baytrail/romstage.h @@ -33,6 +33,7 @@ void report_platform_info(void); #include <fsptypes.h>
void romstage_main_continue(EFI_STATUS status, void *hob_list_ptr); +uint32_t chipset_prev_sleep_state(uint32_t clear);
#define NUM_ROMSTAGE_TS 4
diff --git a/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.c b/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.c index 60a1f7a..83a1100 100644 --- a/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.c +++ b/src/soc/intel/fsp_baytrail/fsp/chipset_fsp_util.c @@ -28,7 +28,11 @@ #include <baytrail/pci_devs.h> #include <drivers/intel/fsp/fsp_util.h> #include "../chip.h" +#include <arch/io.h> #include <baytrail/reset.h> +#include <baytrail/pmc.h> +#include <baytrail/acpi.h> +#include <baytrail/iomap.h>
#ifdef __PRE_RAM__ #include <baytrail/romstage.h> @@ -307,18 +311,43 @@ void chipset_fsp_early_init(FSP_INIT_PARAMS *pFspInitParams, FSP_INFO_HEADER *fsp_ptr) { FSP_INIT_RT_BUFFER *pFspRtBuffer = pFspInitParams->RtBufferPtr; + uint32_t prev_sleep_state; + + /* Get previous sleep state but don't clear */ + prev_sleep_state = chipset_prev_sleep_state(0); + printk(BIOS_INFO, "prev_sleep_state = S%d\n", prev_sleep_state);
/* Initialize the UPD Data */ GetUpdDefaultFromFsp (fsp_ptr, pFspRtBuffer->Common.UpdDataRgnPtr); ConfigureDefaultUpdData(pFspRtBuffer->Common.UpdDataRgnPtr); pFspInitParams->NvsBufferPtr = NULL; - pFspRtBuffer->Common.BootMode = BOOT_WITH_FULL_CONFIGURATION;
-#if IS_ENABLED(CONFIG_ENABLE_FSP_FAST_BOOT) +#if IS_ENABLED(CONFIG_ENABLE_MRC_CACHE) /* Find the fastboot cache that was saved in the ROM */ pFspInitParams->NvsBufferPtr = find_and_set_fastboot_cache(); #endif
+ if (prev_sleep_state == 3) { + /* S3 resume */ + if ( pFspInitParams->NvsBufferPtr == NULL) { + /* If waking from S3 and no cache then. */ + printk(BIOS_WARNING, "No MRC cache found in S3 resume path.\n"); + post_code(POST_RESUME_FAILURE); + /* Clear Sleep Type */ + outl(inl(ACPI_BASE_ADDRESS + PM1_CNT) & + ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT); + /* Reboot */ + printk(BIOS_WARNING,"Rebooting..\n" ); + warm_reset(); + /* Should not reach here.. */ + die("Reboot System\n"); + } + pFspRtBuffer->Common.BootMode = BOOT_ON_S3_RESUME; + } else { + /* Not S3 resume */ + pFspRtBuffer->Common.BootMode = BOOT_WITH_FULL_CONFIGURATION; + } + return; }
diff --git a/src/soc/intel/fsp_baytrail/ramstage.c b/src/soc/intel/fsp_baytrail/ramstage.c index e231701..814b16e 100644 --- a/src/soc/intel/fsp_baytrail/ramstage.c +++ b/src/soc/intel/fsp_baytrail/ramstage.c @@ -18,6 +18,7 @@ */
#include <arch/cpu.h> +#include <arch/acpi.h> #include <console/console.h> #include <cpu/intel/microcode.h> #include <cpu/x86/cr.h> @@ -25,10 +26,12 @@ #include <device/device.h> #include <device/pci_def.h> #include <device/pci_ops.h> +#include <romstage_handoff.h> #include <stdlib.h>
#include <baytrail/gpio.h> #include <baytrail/lpc.h> +#include <baytrail/nvs.h> #include <baytrail/msr.h> #include <baytrail/pattrs.h> #include <baytrail/pci_devs.h> @@ -123,6 +126,32 @@ static void fill_in_pattrs(void) }
+static inline void set_acpi_sleep_type(int val) +{ +#if CONFIG_HAVE_ACPI_RESUME + acpi_slp_type = val; +#endif +} + +static void s3_resume_prepare(void) +{ + global_nvs_t *gnvs; + struct romstage_handoff *romstage_handoff; + + gnvs = cbmem_add(CBMEM_ID_ACPI_GNVS, sizeof(global_nvs_t)); + + romstage_handoff = cbmem_find(CBMEM_ID_ROMSTAGE_INFO); + if (romstage_handoff == NULL || romstage_handoff->s3_resume == 0) { + if (gnvs != NULL) { + memset(gnvs, 0, sizeof(global_nvs_t)); + } + set_acpi_sleep_type(0); + return; + } + + set_acpi_sleep_type(3); +} + void baytrail_init_pre_device(void) { struct soc_gpio_config *config; @@ -132,6 +161,9 @@ void baytrail_init_pre_device(void) /* Allow for SSE instructions to be executed. */ write_cr4(read_cr4() | CR4_OSFXSR | CR4_OSXMMEXCPT);
+ /* Indicate S3 resume to rest of ramstage. */ + s3_resume_prepare(); + /* Get GPIO initial states from mainboard */ config = mainboard_get_gpios(); setup_soc_gpios(config); diff --git a/src/soc/intel/fsp_baytrail/romstage/romstage.c b/src/soc/intel/fsp_baytrail/romstage/romstage.c index a63156f..0c72b98 100644 --- a/src/soc/intel/fsp_baytrail/romstage/romstage.c +++ b/src/soc/intel/fsp_baytrail/romstage/romstage.c @@ -24,6 +24,7 @@ #include <arch/io.h> #include <arch/cbfs.h> #include <arch/stages.h> +#include <arch/early_variables.h> #include <console/console.h> #include <cbmem.h> #include <cpu/x86/mtrr.h> @@ -44,6 +45,51 @@ #include <device/pci_def.h> #include <console/cbmem_console.h>
+/* Return 0, 3, 4 or 5 to indicate the previous sleep state. */ +uint32_t chipset_prev_sleep_state(uint32_t clear) +{ + /* Default to S0. */ + uint32_t prev_sleep_state = 0; + uint32_t pm1_sts; + uint32_t pm1_cnt; + uint32_t gen_pmcon1; + + /* Read Power State */ + pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS); + pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT); + gen_pmcon1 = read32(PMC_BASE_ADDRESS + GEN_PMCON1); + + printk(BIOS_DEBUG, "PM1_STS = 0x%x PM1_CNT = 0x%x GEN_PMCON1 = 0x%x\n", + pm1_sts, pm1_cnt, gen_pmcon1); + + if (pm1_sts & WAK_STS) { + switch ((pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) { + #if CONFIG_HAVE_ACPI_RESUME + case SLP_TYP_S3: + prev_sleep_state = 3; + break; + #endif + case SLP_TYP_S4: + prev_sleep_state = 4; + break; + + case SLP_TYP_S5: + prev_sleep_state = 5; + break; + } + /* If set Clear SLP_TYP. */ + if (clear == 1) { + outl(pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT); + } + } + + if (gen_pmcon1 & (PWR_FLR | SUS_PWR_FLR)) { + prev_sleep_state = 5; + } + + return prev_sleep_state; +} + static void program_base_addresses(void) { uint32_t reg; @@ -174,6 +220,8 @@ void * asmlinkage main(FSP_INFO_HEADER *fsp_info_header) void romstage_main_continue(EFI_STATUS status, void *hob_list_ptr) { int cbmem_was_initted; void *cbmem_hob_ptr; + uint32_t prev_sleep_state; + struct romstage_handoff *handoff;
#if IS_ENABLED(CONFIG_COLLECT_TIMESTAMPS) tsc_t after_initram_time = rdtsc(); @@ -193,6 +241,10 @@ void romstage_main_continue(EFI_STATUS status, void *hob_list_ptr) {
printk(BIOS_DEBUG, "FSP Status: 0x%0x\n", (u32)status);
+ /* Get previous sleep state again and clear */ + prev_sleep_state = chipset_prev_sleep_state(1); + printk(BIOS_DEBUG, "%s: prev_sleep_state = S%d\n", __func__, prev_sleep_state); + report_platform_info();
#if IS_ENABLED(CONFIG_COLLECT_TIMESTAMPS) @@ -203,16 +255,26 @@ void romstage_main_continue(EFI_STATUS status, void *hob_list_ptr) { late_mainboard_romstage_entry(); post_code(0x4c);
- quick_ram_check(); - post_code(0x4d); + /* if S3 resume skip ram check */ + if (prev_sleep_state != 3) { + quick_ram_check(); + post_code(0x4d); + }
- cbmem_was_initted = !cbmem_recovery(0); + cbmem_was_initted = !cbmem_recovery(prev_sleep_state == 3);
/* Save the HOB pointer in CBMEM to be used in ramstage*/ cbmem_hob_ptr = cbmem_add (CBMEM_ID_HOB_POINTER, sizeof(*hob_list_ptr)); *(u32*)cbmem_hob_ptr = (u32)hob_list_ptr; post_code(0x4e);
+ handoff = romstage_handoff_find_or_add(); + if (handoff != NULL) + handoff->s3_resume = (prev_sleep_state == 3); + else + printk(BIOS_DEBUG, "Romstage handoff structure not added!\n"); + + #if IS_ENABLED(CONFIG_COLLECT_TIMESTAMPS) timestamp_init(base_time); timestamp_reinit();