Marshall Dawson has uploaded this change for review. ( https://review.coreboot.org/22654
Change subject: WIP, TO_BE_SPLIT: amd/stoneyridge: Add S3 support ......................................................................
WIP, TO_BE_SPLIT: amd/stoneyridge: Add S3 support
I see TOM and TOM2 restored by AGESA but no MTRRs.
My mtrr restore doesn't work because finding in cbmem doesn't work. cbmem_top relies on top_of_low_cacheable.
todo: * move some of the BiosCallouts.h changes earlier
Change-Id: Ic6c7cf7fca7167051d69f22d53c528ea5a9ea5ad Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M src/soc/amd/common/BiosCallOuts.h M src/soc/amd/common/Makefile.inc M src/soc/amd/common/agesawrapper.c M src/soc/amd/common/agesawrapper.h M src/soc/amd/common/amd_late_init.c A src/soc/amd/common/s3_resume.c M src/soc/amd/common/s3_resume.h M src/soc/amd/common/spi.c M src/soc/amd/stoneyridge/chip.c M src/soc/amd/stoneyridge/model_15_init.c M src/soc/amd/stoneyridge/northbridge.c M src/soc/amd/stoneyridge/romstage.c 12 files changed, 567 insertions(+), 49 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/54/22654/1
diff --git a/src/soc/amd/common/BiosCallOuts.h b/src/soc/amd/common/BiosCallOuts.h index 0d287f9..d53296f 100644 --- a/src/soc/amd/common/BiosCallOuts.h +++ b/src/soc/amd/common/BiosCallOuts.h @@ -19,18 +19,20 @@
#include "s3_resume.h" #include "agesawrapper.h" +#include "s3_resume.h"
//#define S3_NONVOLATILE_SIZE 0x1000 //#define S3_MTRR_SIZE 0x1000 //#define S3_TOTAL_SIZE (S3_NONVOLATILE_SIZE + S3_MTRR_SIZE) #define S3_VOLATILE_SIZE 0x6000 + #define BIOS_HEAP_SIZE 0x30000 #define BSP_STACK_BASE_ADDR 0x30000
struct cbmem_usage { uint8_t heap_base[BIOS_HEAP_SIZE]; #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) - uint8_t s3_save_area[S3_VOLATILE_SIZE]; + uint8_t s3_vol_data[S3_VOLATILE_SIZE]; struct all_mtrrs s3_mtrrs; #endif }; diff --git a/src/soc/amd/common/Makefile.inc b/src/soc/amd/common/Makefile.inc index aa27512..3256f03 100644 --- a/src/soc/amd/common/Makefile.inc +++ b/src/soc/amd/common/Makefile.inc @@ -9,12 +9,14 @@ romstage-y += agesawrapper.c romstage-y += def_callouts.c romstage-y += heapmanager.c +romstage-y += s3_resume.c
ramstage-y += agesawrapper.c ramstage-y += amd_late_init.c ramstage-y += amd_pci_util.c ramstage-y += def_callouts.c ramstage-y += heapmanager.c +ramstage-y += s3_resume.c ramstage-$(CONFIG_SPI_FLASH) += spi.c
subdirs-$(CONFIG_SOC_AMD_COMMON_BLOCK) += block diff --git a/src/soc/amd/common/agesawrapper.c b/src/soc/amd/common/agesawrapper.c index b939183..ebe470c 100644 --- a/src/soc/amd/common/agesawrapper.c +++ b/src/soc/amd/common/agesawrapper.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */
+#include <arch/io.h> #include "agesawrapper.h" #include <cbfs.h> #include <cbmem.h> @@ -20,6 +21,7 @@ #include <cpu/x86/mtrr.h> #include <BiosCallOuts.h> #include <string.h> +#include "s3_resume.h"
void __attribute__((weak)) SetMemParams(AMD_POST_PARAMS *PostParams) {} void __attribute__((weak)) OemPostParams(AMD_POST_PARAMS *PostParams) {} @@ -361,6 +363,181 @@ return Status; }
+AGESA_STATUS agesawrapper_amdinitresume(void) +{ + AGESA_STATUS status; + AMD_INTERFACE_PARAMS AmdParamStruct; + AMD_RESUME_PARAMS *AmdResumeParamsPtr; + struct region nv_data; + + memset(&AmdParamStruct, 0, sizeof(AmdParamStruct)); + + AmdParamStruct.AgesaFunctionName = AMD_INIT_RESUME; + AmdParamStruct.AllocationMethod = PreMemHeap; + AmdParamStruct.StdHeader.AltImageBasePtr = 0; + AmdParamStruct.StdHeader.CalloutPtr = &GetBiosCallout; + AmdParamStruct.StdHeader.Func = 0; + AmdParamStruct.StdHeader.ImageBasePtr = 0; + AmdCreateStruct (&AmdParamStruct); + + AmdResumeParamsPtr = (AMD_RESUME_PARAMS *)AmdParamStruct.NewStructPtr; + + get_s3_info(S3DataTypeNonVolatile, &nv_data); + AmdResumeParamsPtr->S3DataBlock.NvStorage = (void *)nv_data.offset; + AmdResumeParamsPtr->S3DataBlock.NvStorageSize = nv_data.size; + + status = AmdInitResume ((AMD_RESUME_PARAMS *)AmdParamStruct.NewStructPtr); + + if (status != AGESA_SUCCESS) agesawrapper_amdreadeventlog(AmdParamStruct.StdHeader.HeapStatus); + AmdReleaseStruct (&AmdParamStruct); + + return status; +} + +// todo: still to be tested +AGESA_STATUS agesawrapper_amds3laterestore(void) +{ + AGESA_STATUS Status; + AMD_INTERFACE_PARAMS AmdInterfaceParams; + AMD_S3LATE_PARAMS AmdS3LateParams; + AMD_S3LATE_PARAMS *AmdS3LateParamsPtr; + struct region vol_data; + + amd_initcpuio(); + + memset(&AmdS3LateParams, 0, sizeof(AmdS3LateParams)); + + AmdInterfaceParams.StdHeader.ImageBasePtr = 0; + AmdInterfaceParams.AllocationMethod = ByHost; + AmdInterfaceParams.AgesaFunctionName = AMD_S3LATE_RESTORE; + AmdInterfaceParams.NewStructPtr = &AmdS3LateParams; + AmdInterfaceParams.StdHeader.CalloutPtr = &GetBiosCallout; + AmdS3LateParamsPtr = &AmdS3LateParams; + AmdInterfaceParams.NewStructSize = sizeof(AMD_S3LATE_PARAMS); + + AmdCreateStruct(&AmdInterfaceParams); + + get_s3_info(S3DataTypeVolatile, &vol_data); + AmdS3LateParamsPtr->S3DataBlock.VolatileStorage = (void *)vol_data.offset; + AmdS3LateParamsPtr->S3DataBlock.VolatileStorageSize = vol_data.size; + + Status = AmdS3LateRestore(AmdS3LateParamsPtr); + if (Status != AGESA_SUCCESS) { + agesawrapper_amdreadeventlog(AmdInterfaceParams.StdHeader.HeapStatus); + ASSERT(Status == AGESA_SUCCESS); + } + + return Status; +} + +// todo: WIP: fch save/restore functions are not yet tested + +AGESA_STATUS agesawrapper_fchs3earlyrestore(void) +{ + AGESA_STATUS status = AGESA_SUCCESS; + FCH_DATA_BLOCK FchParams; + AMD_CONFIG_PARAMS StdHeader; + struct cbmem_usage *amd_cbmem; + + amd_cbmem = (struct cbmem_usage *)GetHeapBase(); + if (!amd_cbmem) { + printk(BIOS_ERR, "Error locating CBMEM_ID_RESUME_SCRATCH\n"); + return AGESA_ERROR; + } + + StdHeader.HeapStatus = HEAP_SYSTEM_MEM; + StdHeader.HeapBasePtr = (uintptr_t)&amd_cbmem->heap_base; + StdHeader.AltImageBasePtr = 0; + StdHeader.CalloutPtr = &GetBiosCallout; + StdHeader.Func = 0; + StdHeader.ImageBasePtr = 0; + + memset(&FchParams, 0, sizeof(FchParams)); + + FchParams.StdHeader = &StdHeader; +// todo +// see example in southbridge/amd/agesa/hudson/resume.c +// s3_resume_init_data(&FchParams); + + FchInitS3EarlyRestore(&FchParams); + + return status; +} + +AGESA_STATUS agesawrapper_fchs3laterestore(void) +{ + AGESA_STATUS status = AGESA_SUCCESS; + AMD_CONFIG_PARAMS StdHeader; + FCH_DATA_BLOCK FchParams; + struct cbmem_usage *amd_cbmem; + + amd_cbmem = (struct cbmem_usage *)GetHeapBase(); + if (!amd_cbmem) { + printk(BIOS_ERR, "Error locating CBMEM_ID_RESUME_SCRATCH\n"); + return AGESA_ERROR; + } + + StdHeader.HeapStatus = HEAP_SYSTEM_MEM; + StdHeader.HeapBasePtr = (uintptr_t)&amd_cbmem->heap_base; + StdHeader.AltImageBasePtr = 0; + StdHeader.CalloutPtr = &GetBiosCallout; + StdHeader.Func = 0; + StdHeader.ImageBasePtr = 0; + + memset(&FchParams, 0, sizeof(FchParams)); + + FchParams.StdHeader = &StdHeader; +// todo +// see example in southbridge/amd/agesa/hudson/resume.c +// s3_resume_init_data(&FchParams); + FchInitS3LateRestore(&FchParams); + + // todo: still need to reload interrupt values? native agesa doesn't + // but old PI code used to. + + return status; +} + +AGESA_STATUS agesawrapper_amdinitrtb(void) +{ + AGESA_STATUS Status; + AMD_RTB_PARAMS *AmdS3SaveParamsPtr; + AMD_INTERFACE_PARAMS AmdInterfaceParams; + struct region nv_data, vol_data; + + memset(&AmdInterfaceParams, 0, sizeof(AMD_INTERFACE_PARAMS)); + + AmdInterfaceParams.StdHeader.ImageBasePtr = 0; + AmdInterfaceParams.StdHeader.HeapStatus = HEAP_SYSTEM_MEM; + AmdInterfaceParams.StdHeader.CalloutPtr = &GetBiosCallout; + AmdInterfaceParams.AllocationMethod = PostMemDram; + AmdInterfaceParams.AgesaFunctionName = AMD_INIT_RTB; + AmdInterfaceParams.StdHeader.AltImageBasePtr = 0; + AmdInterfaceParams.StdHeader.Func = 0; + AmdCreateStruct(&AmdInterfaceParams); + + AmdS3SaveParamsPtr = (AMD_RTB_PARAMS *)AmdInterfaceParams.NewStructPtr; + AmdS3SaveParamsPtr->StdHeader = AmdInterfaceParams.StdHeader; + + Status = AmdInitRtb(AmdS3SaveParamsPtr); + if (Status != AGESA_SUCCESS) { + agesawrapper_amdreadeventlog(AmdInterfaceParams.StdHeader.HeapStatus); + ASSERT(Status == AGESA_SUCCESS); + } + + nv_data.offset = (size_t)AmdS3SaveParamsPtr->S3DataBlock.NvStorage; + nv_data.size = (size_t)AmdS3SaveParamsPtr->S3DataBlock.NvStorageSize; + vol_data.offset = (size_t)AmdS3SaveParamsPtr->S3DataBlock.VolatileStorage; + vol_data.size = (size_t)AmdS3SaveParamsPtr->S3DataBlock.VolatileStorageSize; + + if (save_s3_info(nv_data, vol_data)) + printk(BIOS_ERR, "Error saving S3 data, resume is possible\n"); + + AmdReleaseStruct(&AmdInterfaceParams); + + return Status; +} + const void *agesawrapper_locate_module (const CHAR8 name[8]) { const void* agesa; diff --git a/src/soc/amd/common/agesawrapper.h b/src/soc/amd/common/agesawrapper.h index f7a2fc0..a6983ad 100644 --- a/src/soc/amd/common/agesawrapper.h +++ b/src/soc/amd/common/agesawrapper.h @@ -41,7 +41,7 @@ void *agesawrapper_getlateinitptr(int pick); AGESA_STATUS agesawrapper_amdlaterunaptask(UINT32 Func, UINTN Data, void *ConfigPtr); -AGESA_STATUS agesawrapper_amdS3Save(void); +AGESA_STATUS agesawrapper_amdinitrtb(void); AGESA_STATUS agesawrapper_amdinitresume(void); AGESA_STATUS agesawrapper_amds3laterestore(void);
diff --git a/src/soc/amd/common/amd_late_init.c b/src/soc/amd/common/amd_late_init.c index 3aee23c..d57de26 100644 --- a/src/soc/amd/common/amd_late_init.c +++ b/src/soc/amd/common/amd_late_init.c @@ -27,13 +27,12 @@ { if (acpi_is_wakeup_s3()) return; - AGESAWRAPPER(amdinitlate);
if (!acpi_s3_resume_allowed()) return;
- AGESAWRAPPER(amdS3Save); + AGESAWRAPPER(amdinitrtb); }
BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, diff --git a/src/soc/amd/common/s3_resume.c b/src/soc/amd/common/s3_resume.c new file mode 100644 index 0000000..782aac8 --- /dev/null +++ b/src/soc/amd/common/s3_resume.c @@ -0,0 +1,264 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2012 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <console/console.h> +#include <cpu/x86/msr.h> +#include <cpu/x86/mtrr.h> +#include <cpu/amd/car.h> +#include <cpu/amd/mtrr.h> +#include <cpu/x86/cache.h> +#include <cbmem.h> +#include <fmap.h> +#include <device/device.h> +#include <arch/io.h> +#include <arch/acpi.h> +#include <program_loading.h> +#include <string.h> +#include <soc/iomap.h> +#include <Porting.h> +#include <BiosCallOuts.h> +#include <halt.h> +#include <AGESA.h> +#include "agesawrapper.h" +#include <s3_resume.h> + +#if !IS_ENABLED(CONFIG_SPI_FLASH) +#error "CONFIG_SPI_FLASH must be enabled" +#endif + +// todo: improve this? +#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) && !IS_ENABLED(CONFIG_VBOOT) \ + && S3_TOTAL_NV_SIZE > CONFIG_S3_DATA_SIZE +#error "Please increase the value of S3_DATA_SIZE" +#endif + +static int lookup_region_by_name(const char *name, struct region *r) +{ + if (fmap_locate_area(name, r) == 0) + return 0; + + if (IS_ENABLED(CONFIG_VBOOT)) { + printk(BIOS_ERR, "Error: vboot requires flash map for S3\n"); + return -1; + } + + /* Fall back to Kconfig values */ + r->offset = CONFIG_S3_DATA_POS; + r->size = CONFIG_S3_DATA_SIZE; + return 0; +} + +static void get_s3nv_region(struct region *nv) +{ + struct region mrc_cache; + int status = lookup_region_by_name("RW_MRC_CACHE", &mrc_cache); + if (status) { + nv->offset = 0; + nv->size = 0; + return; + } + + nv->offset = (size_t)mrc_cache.offset; + nv->size = S3_NONVOLATILE_SIZE; +} + +static void get_s3vol_region(struct region *vol) +{ + struct cbmem_usage *heap = (struct cbmem_usage *)GetHeapBase(); + if (!heap) { + printk(BIOS_ERR, "Error locating CBMEM_ID_RESUME_SCRATCH\n"); + return; + } + vol->offset = (size_t)heap->s3_vol_data; + vol->size = S3_VOLATILE_SIZE; +} + +static void get_s3mtrr_region(struct region *mtrr) +{ + struct cbmem_usage *heap = (struct cbmem_usage *)GetHeapBase(); + if (!heap) { + printk(BIOS_ERR, "Error locating CBMEM_ID_RESUME_SCRATCH\n"); + return; + } + mtrr->offset = (size_t)&heap->s3_mtrrs; + mtrr->size = sizeof(struct all_mtrrs); +} + +void restore_mtrr(void) +{ + u32 i; + msr_t msr; + struct all_mtrrs *mtrrs; + int num_vmtrrs; + + struct cbmem_usage *heap = (struct cbmem_usage *)GetHeapBase(); + if (!heap) { + printk(BIOS_ERR, "Error locating CBMEM_ID_RESUME_SCRATCH\n"); + return; + } + mtrrs = (struct all_mtrrs *)&heap->s3_mtrrs; + + msr = rdmsr(MTRR_CAP_MSR); + num_vmtrrs = msr.lo & MTRR_CAP_VCNT; + + disable_cache(); + + /* Enable access to AMD RdDram and WrDram extension bits */ + msr = rdmsr(SYSCFG_MSR); + msr.lo |= SYSCFG_MSR_MtrrFixDramModEn; + wrmsr(SYSCFG_MSR, msr); + + /* Now restore the Fixed MTRRs */ + wrmsr(MTRR_FIX_64K_00000, mtrrs->_64k_00); + wrmsr(MTRR_FIX_16K_80000, mtrrs->_16k_80); + wrmsr(MTRR_FIX_16K_A0000, mtrrs->_16k_a0); + wrmsr(MTRR_FIX_4K_C0000, mtrrs->_4k_c0); + wrmsr(MTRR_FIX_4K_C8000, mtrrs->_4k_c8); + wrmsr(MTRR_FIX_4K_D0000, mtrrs->_4k_d0); + wrmsr(MTRR_FIX_4K_D8000, mtrrs->_4k_d8); + wrmsr(MTRR_FIX_4K_E0000, mtrrs->_4k_e0); + wrmsr(MTRR_FIX_4K_E8000, mtrrs->_4k_e8); + wrmsr(MTRR_FIX_4K_F0000, mtrrs->_4k_f0); + wrmsr(MTRR_FIX_4K_F8000, mtrrs->_4k_f8); + + for (i = 0 ; i < num_vmtrrs ; i++) { + wrmsr(MTRR_PHYS_BASE(i), mtrrs->vmtrr[i].base); + wrmsr(MTRR_PHYS_MASK(i), mtrrs->vmtrr[i].mask); + } + + wrmsr(SYSCFG_MSR, mtrrs->sys_cfg); +} + +static int save_mtrr(struct all_mtrrs *mtrrs) +{ + u32 i; + msr_t msr; + int num_vmtrrs; + + msr = rdmsr(MTRR_CAP_MSR); + num_vmtrrs = msr.lo & MTRR_CAP_VCNT; /* no. of supported var. MTRRs */ + + if (num_vmtrrs > MAX_VAR_MTRRS) { + printk(BIOS_ERR, "Error: Increase MAX_VAR_MTRRS for S3\n"); + return -1; + } + + /* Start saving */ + mtrrs->sys_cfg = rdmsr(SYSCFG_MSR); + + /* Enable access to AMD RdDram and WrDram extension bits */ + msr = rdmsr(SYSCFG_MSR); + msr.lo |= SYSCFG_MSR_MtrrFixDramModEn; + wrmsr(SYSCFG_MSR, msr); + + /* Save the Fixed MTRRs */ + mtrrs->_64k_00 = rdmsr(MTRR_FIX_64K_00000); + mtrrs->_16k_80 = rdmsr(MTRR_FIX_16K_80000); + mtrrs->_16k_a0 = rdmsr(MTRR_FIX_16K_A0000); + mtrrs->_4k_c0 = rdmsr(MTRR_FIX_4K_C0000); + mtrrs->_4k_c8 = rdmsr(MTRR_FIX_4K_C8000); + mtrrs->_4k_d0 = rdmsr(MTRR_FIX_4K_D0000); + mtrrs->_4k_d8 = rdmsr(MTRR_FIX_4K_D8000); + mtrrs->_4k_e0 = rdmsr(MTRR_FIX_4K_E0000); + mtrrs->_4k_e8 = rdmsr(MTRR_FIX_4K_E8000); + mtrrs->_4k_f0 = rdmsr(MTRR_FIX_4K_F0000); + mtrrs->_4k_f8 = rdmsr(MTRR_FIX_4K_F8000); + + /* Disable access to AMD RdDram and WrDram extension bits */ + msr = rdmsr(SYSCFG_MSR); + msr.lo &= ~SYSCFG_MSR_MtrrFixDramModEn; + wrmsr(SYSCFG_MSR, msr); + + for (i = 0 ; i < num_vmtrrs ; i++) { + mtrrs->vmtrr[i].base = rdmsr(MTRR_PHYS_BASE(i)); + mtrrs->vmtrr[i].mask = rdmsr(MTRR_PHYS_MASK(i)); + } + + /* AGESA restores TOM and TOM2 */ + + return 0; +} + +void get_s3_info(S3_DATA_TYPE type, struct region *info) +{ + struct region rgn = { .offset = 0, .size = 0 }; + + switch (type) { + case S3DataTypeNonVolatile: + get_s3nv_region(&rgn); + rgn.offset += FLASH_BASE_ADDR; + printk(BIOS_SPEW, "S3 NV data @0x%zx\n", rgn.offset); + break; + case S3DataTypeVolatile: + get_s3vol_region(&rgn); + printk(BIOS_SPEW, "S3 volatile data @0x%zx\n", rgn.offset); + break; + default: + printk(BIOS_ERR, "Error: %s called with bad type %d\n", + __func__, type); + return; + } + + info->size = *(size_t *)rgn.offset; + info->offset = rgn.offset + sizeof(info->size); + + return; +} + +int save_s3_info(struct region nv, struct region vol) +{ + struct region dst; + void *data; + + printk(BIOS_SPEW, "%s(): S3 NV data @0x%zx (0x%zx bytes)" + " volatile data @0x%zx (0x%zx bytes)\n", + __func__, nv.offset, nv.size, + vol.offset, vol.size); + + get_s3vol_region(&dst); + if (vol.size && (dst.offset == 0 || dst.size == 0)) { + printk(BIOS_ERR, "Error: can't access S3 volatile save area\n"); + return -1; + } + + /* write size followed by AGESA's volatile data */ + data = (void *)(dst.offset + sizeof(size_t)); + memset((void *)dst.offset, 0, S3_VOLATILE_SIZE); + + *(size_t *)dst.offset = vol.size; + memcpy(data, (void *)vol.offset, vol.size); + + get_s3mtrr_region(&dst); + if (!dst.offset || !dst.size) { + printk(BIOS_ERR, "Error: can't access S3 MTRR save area\n"); + return -1; + } + + if (save_mtrr((void *)dst.offset)) + return -1; + + get_s3nv_region(&dst); + if (!dst.offset || !dst.size) { + printk(BIOS_ERR, "Error: can't find S3 NV save area\n"); + return -1; + } + + if (spi_save_s3_info(dst, nv)) { + printk(BIOS_ERR, "Error: can't save S3 NV data\n"); + return -1; + } + + return 0; +} diff --git a/src/soc/amd/common/s3_resume.h b/src/soc/amd/common/s3_resume.h index 3e80d72..b58340f 100644 --- a/src/soc/amd/common/s3_resume.h +++ b/src/soc/amd/common/s3_resume.h @@ -17,6 +17,20 @@ #define __S3_RESUME_H__
#include <cpu/x86/msr.h> +#include <commonlib/region.h> + +/* todo: Make the Intel MRC flash region management common and then use that + * instead of redefining it here. + */ +#define DEFAULT_MRC_CACHE "RW_MRC_CACHE" +#define VARIABLE_MRC_CACHE "RW_VAR_MRC_CACHE" +#define RECOVERY_MRC_CACHE "RECOVERY_MRC_CACHE" +#define UNIFIED_MRC_CACHE "UNIFIED_MRC_CACHE" + +typedef enum { + S3DataTypeNonVolatile=0, /* NonVolatile Data */ + S3DataTypeVolatile, /* Volatile Data */ +} S3_DATA_TYPE;
struct vmtrr_pair { msr_t base; @@ -40,6 +54,11 @@ struct vmtrr_pair vmtrr[MAX_VAR_MTRRS]; };
-void spi_SaveS3info(u32 pos, u32 size, u8 *buf, u32 len); +void restore_mtrr(void); + +int save_s3_info(struct region nv, struct region vol); +void get_s3_info(S3_DATA_TYPE type, struct region *info); + +int spi_save_s3_info(struct region dst, struct region src);
#endif /* __S3_RESUME_H__ */ diff --git a/src/soc/amd/common/spi.c b/src/soc/amd/common/spi.c index 44c86e6..7587536 100644 --- a/src/soc/amd/common/spi.c +++ b/src/soc/amd/common/spi.c @@ -1,7 +1,8 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2012 Advanced Micro Devices, Inc. + * Copyright (C) 2012-2017 Advanced Micro Devices, Inc. + * Copyright (C) 2014 Google Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,24 +17,49 @@ #include <console/console.h> #include <spi-generic.h> #include <spi_flash.h> +#include <region_file.h> +#include <security/vboot/vboot_common.h> #include "s3_resume.h"
-void spi_SaveS3info(u32 pos, u32 size, u8 *buf, u32 len) +int spi_save_s3_info(struct region dst, struct region src) { struct spi_flash flash; + int status; + + if (src.size == 0) + return 0;
spi_init(); if (spi_flash_probe(0, 0, &flash)) { - printk(BIOS_DEBUG, "Could not find SPI device\n"); - /* Dont make flow stop. */ - return; + printk(BIOS_DEBUG, "S3 SPI: couldn't find SPI device\n"); + return -1; }
- spi_flash_volatile_group_begin(&flash); + /* need to write the data plus the size below */ + if (src.size + sizeof(src.size) > dst.size) { + printk(BIOS_DEBUG, "S3 SPI: src is larger than dest.\n"); + return -1; + }
- spi_flash_erase(&flash, pos, size); - spi_flash_write(&flash, pos, sizeof(len), &len); - spi_flash_write(&flash, pos + sizeof(len), len, buf); + status = spi_flash_volatile_group_begin(&flash); + if (status) + goto error;
+ status = spi_flash_erase(&flash, dst.offset, dst.size); + if (status) + goto error; + + /* write size first */ + status = spi_flash_write(&flash, dst.offset, sizeof(src.size), + (void *)&src.size); + if (status) + goto error; + + /* write buffer */ + status = spi_flash_write(&flash, dst.offset + sizeof(dst.size), + src.size, (void *)src.offset); + +error: spi_flash_volatile_group_end(&flash); + return status; } diff --git a/src/soc/amd/stoneyridge/chip.c b/src/soc/amd/stoneyridge/chip.c index 8e4ab2e..2545a44 100644 --- a/src/soc/amd/stoneyridge/chip.c +++ b/src/soc/amd/stoneyridge/chip.c @@ -20,6 +20,7 @@ #include <cpu/cpu.h> #include <device/device.h> #include <device/pci.h> +#include <romstage_handoff.h> #include <soc/cpu.h> #include <soc/northbridge.h> #include <soc/southbridge.h> @@ -81,12 +82,18 @@
static void earliest_ramstage(void *unused) { - post_code(0x46); - if (IS_ENABLED(CONFIG_SOC_AMD_PSP_SELECTABLE_SMU_FW)) - psp_load_named_blob(MBOX_BIOS_CMD_SMU_FW2, "smu_fw2"); + if (!acpi_is_wakeup_s3()) { + post_code(0x46); + if (IS_ENABLED(CONFIG_SOC_AMD_PSP_SELECTABLE_SMU_FW) + && !romstage_handoff_is_resume()) + psp_load_named_blob(MBOX_BIOS_CMD_SMU_FW2, "smu_fw2");
- post_code(0x47); - AGESAWRAPPER(amdinitenv); + post_code(0x47); + AGESAWRAPPER(amdinitenv); + } else { + AGESAWRAPPER(amds3laterestore); + AGESAWRAPPER(fchs3earlyrestore); + } }
BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, earliest_ramstage, NULL); diff --git a/src/soc/amd/stoneyridge/model_15_init.c b/src/soc/amd/stoneyridge/model_15_init.c index 930e395..3a3f72d 100644 --- a/src/soc/amd/stoneyridge/model_15_init.c +++ b/src/soc/amd/stoneyridge/model_15_init.c @@ -29,6 +29,8 @@ #include <cpu/amd/amdfam15.h> #include <arch/acpi.h>
+#include <s3_resume.h> + static void msr_rw_dram(unsigned int reg) { #define RW_DRAM (MTRR_READ_MEM | MTRR_WRITE_MEM) @@ -69,6 +71,9 @@ msr.lo |= SYSCFG_MSR_MtrrFixDramEn; wrmsr(SYSCFG_MSR, msr);
+ if (acpi_is_wakeup()) + restore_mtrr(); + x86_enable_cache();
/* zero the machine check error status registers */ diff --git a/src/soc/amd/stoneyridge/northbridge.c b/src/soc/amd/stoneyridge/northbridge.c index 3eb8e8d..a640bbf 100644 --- a/src/soc/amd/stoneyridge/northbridge.c +++ b/src/soc/amd/stoneyridge/northbridge.c @@ -28,6 +28,7 @@ #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> +#include <romstage_handoff.h> #include <agesawrapper.h> #include <agesawrapper_call.h> #include <soc/northbridge.h> @@ -423,12 +424,12 @@
void domain_enable_resources(device_t dev) { - if (acpi_is_wakeup_s3()) - AGESAWRAPPER(fchs3laterestore); - +printk(0, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$ acpi_is_wakeup_s3 returns %d acpi_is_wakeup returns %d\n", acpi_is_wakeup_s3(), acpi_is_wakeup()); /* Must be called after PCI enumeration and resource allocation */ - if (!acpi_is_wakeup_s3()) + if (!romstage_handoff_is_resume()) AGESAWRAPPER(amdinitmid); + else + AGESAWRAPPER(fchs3laterestore);
printk(BIOS_DEBUG, " ader - leaving domain_enable_resources.\n"); } diff --git a/src/soc/amd/stoneyridge/romstage.c b/src/soc/amd/stoneyridge/romstage.c index 32dee5a..3e63a26 100644 --- a/src/soc/amd/stoneyridge/romstage.c +++ b/src/soc/amd/stoneyridge/romstage.c @@ -15,6 +15,7 @@ */
#include <arch/cpu.h> +#include <arch/acpi.h> #include <cpu/x86/msr.h> #include <cpu/x86/mtrr.h> #include <cpu/amd/mtrr.h> @@ -24,10 +25,12 @@ #include <device/device.h> #include <chip.h> #include <program_loading.h> +#include <romstage_handoff.h> #include <agesawrapper.h> #include <agesawrapper_call.h> #include <soc/northbridge.h> #include <soc/southbridge.h> +#include <s3_resume.h> #include <amdblocks/psp.h>
asmlinkage void car_stage_entry(void) @@ -40,45 +43,58 @@ msr_t base, mask; msr_t mtrr_cap = rdmsr(MTRR_CAP_MSR); int vmtrrs = mtrr_cap.lo & MTRR_CAP_VCNT; + int s3_resume = acpi_is_wakeup_s3(); int i;
console_init();
- post_code(0x40); - AGESAWRAPPER(amdinitpost); + if (!s3_resume) { + post_code(0x40); + AGESAWRAPPER(amdinitpost);
- post_code(0x41); - /* - * TODO: This is a hack to work around current AGESA behavior. AGESA - * needs to change to reflect that coreboot owns the MTRRs. - * - * After setting up DRAM, AGESA also completes the configuration of the - * MTRRs, setting regions to WB. Anything written to memory between - * now and and when CAR is dismantled will be in cache and lost. For - * now, set the regions UC to ensure the writes get to DRAM. - */ - for (i = 0 ; i < vmtrrs ; i++) { - base = rdmsr(MTRR_PHYS_BASE(i)); - mask = rdmsr(MTRR_PHYS_MASK(i)); - if (!(mask.lo & MTRR_PHYS_MASK_VALID)) - continue; + post_code(0x41); + /* + * TODO: This is a hack to work around current AGESA behavior. + * AGESA needs to change to reflect that coreboot owns + * the MTRRs. + * + * After setting up DRAM, AGESA also completes the configuration + * of the MTRRs, setting regions to WB. Anything written to + * memory between now and and when CAR is dismantled will be + * in cache and lost. For now, set the regions UC to ensure + * the writes get to DRAM. + */ + for (i = 0 ; i < vmtrrs ; i++) { + base = rdmsr(MTRR_PHYS_BASE(i)); + mask = rdmsr(MTRR_PHYS_MASK(i)); + if (!(mask.lo & MTRR_PHYS_MASK_VALID)) + continue;
- if ((base.lo & 0x7) == MTRR_TYPE_WRBACK) { - base.lo &= ~0x7; - base.lo |= MTRR_TYPE_UNCACHEABLE; - wrmsr(MTRR_PHYS_BASE(i), base); + if ((base.lo & 0x7) == MTRR_TYPE_WRBACK) { + base.lo &= ~0x7; + base.lo |= MTRR_TYPE_UNCACHEABLE; + wrmsr(MTRR_PHYS_BASE(i), base); + } } + /* Disable WB from to region 4GB-TOM2. */ + msr_t sys_cfg = rdmsr(SYSCFG_MSR); + sys_cfg.lo &= ~SYSCFG_MSR_TOM2WB; + wrmsr(SYSCFG_MSR, sys_cfg); + } else { + printk(BIOS_INFO, "S3 detected\n"); + post_code(0x60); + agesawrapper_amdinitresume(); + restore_top_of_low_cacheable(); + + post_code(0x61); } - /* Disable WB from to region 4GB-TOM2. */ - msr_t sys_cfg = rdmsr(SYSCFG_MSR); - sys_cfg.lo &= ~SYSCFG_MSR_TOM2WB; - wrmsr(SYSCFG_MSR, sys_cfg);
post_code(0x42); psp_notify_dram();
post_code(0x43); - cbmem_initialize_empty(); + cbmem_recovery(s3_resume); + romstage_handoff_init(s3_resume);
post_code(0x44); if (postcar_frame_init(&pcf, 1 * KiB))