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