Marshall Dawson has uploaded this change for review.

View Change

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

To view, visit change 22654. To unsubscribe, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic6c7cf7fca7167051d69f22d53c528ea5a9ea5ad
Gerrit-Change-Number: 22654
Gerrit-PatchSet: 1
Gerrit-Owner: Marshall Dawson <marshalldawson3rd@gmail.com>