[coreboot-gerrit] Change in coreboot[master]: WIP, TO_BE_SPLIT: amd/stoneyridge: Add S3 support

Marshall Dawson (Code Review) gerrit at coreboot.org
Thu Nov 30 17:49:57 CET 2017


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 at 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 https://review.coreboot.org/22654
To unsubscribe, visit https://review.coreboot.org/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 at gmail.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20171130/61d4e650/attachment-0001.html>


More information about the coreboot-gerrit mailing list