<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>