summaryrefslogtreecommitdiff
path: root/src/cpu/amd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/amd')
-rw-r--r--src/cpu/amd/Kconfig1
-rw-r--r--src/cpu/amd/Makefile.inc1
-rw-r--r--src/cpu/amd/agesa/Kconfig2
-rw-r--r--src/cpu/amd/agesa/Makefile.inc1
-rw-r--r--src/cpu/amd/agesa/amd_late_init.c5
-rw-r--r--src/cpu/amd/pi/00730F01/Kconfig (renamed from src/cpu/amd/agesa/00730F01/Kconfig)4
-rw-r--r--src/cpu/amd/pi/00730F01/Makefile.inc (renamed from src/cpu/amd/agesa/00730F01/Makefile.inc)0
-rw-r--r--src/cpu/amd/pi/00730F01/acpi/cpu.asl (renamed from src/cpu/amd/agesa/00730F01/acpi/cpu.asl)0
-rw-r--r--src/cpu/amd/pi/00730F01/chip_name.c (renamed from src/cpu/amd/agesa/00730F01/chip_name.c)2
-rw-r--r--src/cpu/amd/pi/00730F01/model_16_init.c (renamed from src/cpu/amd/agesa/00730F01/model_16_init.c)0
-rw-r--r--src/cpu/amd/pi/Kconfig76
-rw-r--r--src/cpu/amd/pi/Makefile.inc45
-rw-r--r--src/cpu/amd/pi/amd_late_init.c60
-rw-r--r--src/cpu/amd/pi/cache_as_ram.inc110
-rw-r--r--src/cpu/amd/pi/heapmanager.c342
-rw-r--r--src/cpu/amd/pi/s3_resume.c311
-rw-r--r--src/cpu/amd/pi/s3_resume.h38
-rw-r--r--src/cpu/amd/pi/spi.c49
18 files changed, 1037 insertions, 10 deletions
diff --git a/src/cpu/amd/Kconfig b/src/cpu/amd/Kconfig
index 5603f41ef0..ab2d1f2464 100644
--- a/src/cpu/amd/Kconfig
+++ b/src/cpu/amd/Kconfig
@@ -19,3 +19,4 @@ source src/cpu/amd/geode_lx/Kconfig
source src/cpu/amd/sc520/Kconfig
source src/cpu/amd/agesa/Kconfig
+source src/cpu/amd/pi/Kconfig
diff --git a/src/cpu/amd/Makefile.inc b/src/cpu/amd/Makefile.inc
index 85ce7f652a..6257615c65 100644
--- a/src/cpu/amd/Makefile.inc
+++ b/src/cpu/amd/Makefile.inc
@@ -15,3 +15,4 @@ subdirs-$(CONFIG_CPU_AMD_SC520) += sc520
subdirs-$(CONFIG_CPU_AMD_SOCKET_S1G1) += socket_S1G1
subdirs-$(CONFIG_CPU_AMD_AGESA) += agesa
+subdirs-$(CONFIG_CPU_AMD_PI) += pi
diff --git a/src/cpu/amd/agesa/Kconfig b/src/cpu/amd/agesa/Kconfig
index d288fef177..fcba0cfdb2 100644
--- a/src/cpu/amd/agesa/Kconfig
+++ b/src/cpu/amd/agesa/Kconfig
@@ -25,7 +25,6 @@ config CPU_AMD_AGESA
default y if CPU_AMD_AGESA_FAMILY15
default y if CPU_AMD_AGESA_FAMILY15_TN
default y if CPU_AMD_AGESA_FAMILY16_KB
- default y if CPU_AMD_AGESA_00730F01
default n
select ARCH_BOOTBLOCK_X86_32
select ARCH_ROMSTAGE_X86_32
@@ -85,5 +84,4 @@ source src/cpu/amd/agesa/family14/Kconfig
source src/cpu/amd/agesa/family15/Kconfig
source src/cpu/amd/agesa/family15tn/Kconfig
source src/cpu/amd/agesa/family16kb/Kconfig
-source src/cpu/amd/agesa/00730F01/Kconfig
diff --git a/src/cpu/amd/agesa/Makefile.inc b/src/cpu/amd/agesa/Makefile.inc
index 800f8e7452..beba040ef4 100644
--- a/src/cpu/amd/agesa/Makefile.inc
+++ b/src/cpu/amd/agesa/Makefile.inc
@@ -22,7 +22,6 @@ subdirs-$(CONFIG_CPU_AMD_AGESA_FAMILY14) += family14
subdirs-$(CONFIG_CPU_AMD_AGESA_FAMILY15) += family15
subdirs-$(CONFIG_CPU_AMD_AGESA_FAMILY15_TN) += family15tn
subdirs-$(CONFIG_CPU_AMD_AGESA_FAMILY16_KB) += family16kb
-subdirs-$(CONFIG_CPU_AMD_AGESA_00730F01) += 00730F01
romstage-y += s3_resume.c
ramstage-y += s3_resume.c
diff --git a/src/cpu/amd/agesa/amd_late_init.c b/src/cpu/amd/agesa/amd_late_init.c
index cab03a3096..4fa2e4e8bc 100644
--- a/src/cpu/amd/agesa/amd_late_init.c
+++ b/src/cpu/amd/agesa/amd_late_init.c
@@ -31,9 +31,6 @@
#include <sb_cimx.h>
#endif
-#define NORTHBRIDGE_00700F00 IS_ENABLED(CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY_16KB)
-#define NORTHBRIDGE_00730F01 IS_ENABLED(CONFIG_NORTHBRIDGE_AMD_AGESA_00730F01)
-
static void agesawrapper_post_device(void *unused)
{
if (acpi_is_wakeup_s3())
@@ -41,7 +38,7 @@ static void agesawrapper_post_device(void *unused)
AGESAWRAPPER(amdinitlate);
-#if (NORTHBRIDGE_00700F00) || (NORTHBRIDGE_00730F01)
+#if IS_ENABLED(CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY_16KB)
device_t dev;
u32 value;
dev = dev_find_slot(0, PCI_DEVFN(0, 0)); /* clear IoapicSbFeatureEn */
diff --git a/src/cpu/amd/agesa/00730F01/Kconfig b/src/cpu/amd/pi/00730F01/Kconfig
index ccc44d6c5d..e610ea2ff4 100644
--- a/src/cpu/amd/agesa/00730F01/Kconfig
+++ b/src/cpu/amd/pi/00730F01/Kconfig
@@ -17,12 +17,12 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-config CPU_AMD_AGESA_00730F01
+config CPU_AMD_PI_00730F01
bool
select PCI_IO_CFG_EXT
select X86_AMD_FIXED_MTRRS
-if CPU_AMD_AGESA_00730F01
+if CPU_AMD_PI_00730F01
config CPU_ADDR_BITS
int
diff --git a/src/cpu/amd/agesa/00730F01/Makefile.inc b/src/cpu/amd/pi/00730F01/Makefile.inc
index fba21854e7..fba21854e7 100644
--- a/src/cpu/amd/agesa/00730F01/Makefile.inc
+++ b/src/cpu/amd/pi/00730F01/Makefile.inc
diff --git a/src/cpu/amd/agesa/00730F01/acpi/cpu.asl b/src/cpu/amd/pi/00730F01/acpi/cpu.asl
index dc86df54e0..dc86df54e0 100644
--- a/src/cpu/amd/agesa/00730F01/acpi/cpu.asl
+++ b/src/cpu/amd/pi/00730F01/acpi/cpu.asl
diff --git a/src/cpu/amd/agesa/00730F01/chip_name.c b/src/cpu/amd/pi/00730F01/chip_name.c
index 7a1c06ccff..4a2c3eafc7 100644
--- a/src/cpu/amd/agesa/00730F01/chip_name.c
+++ b/src/cpu/amd/pi/00730F01/chip_name.c
@@ -19,6 +19,6 @@
#include <device/device.h>
-struct chip_operations cpu_amd_agesa_00730F01_ops = {
+struct chip_operations cpu_amd_pi_00730F01_ops = {
CHIP_NAME("AMD CPU Family 16h")
};
diff --git a/src/cpu/amd/agesa/00730F01/model_16_init.c b/src/cpu/amd/pi/00730F01/model_16_init.c
index 8053fd1f06..8053fd1f06 100644
--- a/src/cpu/amd/agesa/00730F01/model_16_init.c
+++ b/src/cpu/amd/pi/00730F01/model_16_init.c
diff --git a/src/cpu/amd/pi/Kconfig b/src/cpu/amd/pi/Kconfig
new file mode 100644
index 0000000000..366beb41c1
--- /dev/null
+++ b/src/cpu/amd/pi/Kconfig
@@ -0,0 +1,76 @@
+#
+# This file is part of the coreboot project.
+#
+# Copyright (C) 2011 - 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+config CPU_AMD_PI
+ bool
+ default y if CPU_AMD_PI_00730F01
+ default n
+ select ARCH_BOOTBLOCK_X86_32
+ select ARCH_ROMSTAGE_X86_32
+ select ARCH_RAMSTAGE_X86_32
+ select TSC_SYNC_LFENCE
+ select UDELAY_LAPIC
+ select LAPIC_MONOTONIC_TIMER
+ select BROKEN_CAR_MIGRATE
+ select SPI_FLASH if HAVE_ACPI_RESUME
+
+if CPU_AMD_PI
+
+config UDELAY_IO
+ bool
+ default n
+
+config XIP_ROM_SIZE
+ hex
+ default 0x100000
+ help
+ Overwride the default write through caching size as 1M Bytes.
+ On some AMD platforms, one socket supports 2 or more kinds of
+ processor family, compiling several CPU families agesa code
+ will increase the romstage size.
+ In order to execute romstage in place on the flash ROM,
+ more space is required to be set as write through caching.
+
+config UDELAY_LAPIC_FIXED_FSB
+ int
+ default 200
+
+# TODO: Sync these with definitions in PI vendorcode.
+# DCACHE_RAM_BASE must equal BSP_STACK_BASE_ADDR.
+# DCACHE_RAM_SIZE must equal BSP_STACK_SIZE.
+
+config DCACHE_RAM_BASE
+ hex
+ default 0x30000
+
+config DCACHE_RAM_SIZE
+ hex
+ default 0x10000
+
+config S3_DATA_POS
+ hex
+ default 0xFFFF0000
+
+config S3_DATA_SIZE
+ int
+ default 32768
+
+endif # CPU_AMD_PI
+
+source src/cpu/amd/pi/00730F01/Kconfig
diff --git a/src/cpu/amd/pi/Makefile.inc b/src/cpu/amd/pi/Makefile.inc
new file mode 100644
index 0000000000..8228b12182
--- /dev/null
+++ b/src/cpu/amd/pi/Makefile.inc
@@ -0,0 +1,45 @@
+#
+# This file is part of the coreboot project.
+#
+# Copyright (C) 2011 - 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+
+subdirs-$(CONFIG_CPU_AMD_PI_00730F01) += 00730F01
+
+romstage-y += s3_resume.c
+ramstage-y += s3_resume.c
+ramstage-$(CONFIG_SPI_FLASH) += spi.c
+
+cpu_incs += $(src)/cpu/amd/pi/cache_as_ram.inc
+
+romstage-y += heapmanager.c
+ramstage-y += heapmanager.c
+ramstage-y += amd_late_init.c
+
+ifeq ($(CONFIG_HAVE_ACPI_RESUME), y)
+
+$(obj)/coreboot_s3nv.rom: $(obj)/config.h
+ echo " S3 NVRAM $(CONFIG_S3_DATA_POS) (S3 storage area)"
+ # force C locale, so cygwin awk doesn't try to interpret the 0xff below as UTF-8 (or worse)
+ printf %d $(CONFIG_S3_DATA_SIZE) | LC_ALL=C awk '{for (i=0; i<$$1; i++) {printf "%c", 255}}' > $@.tmp
+ mv $@.tmp $@
+
+cbfs-files-y += s3nv
+s3nv-file := $(obj)/coreboot_s3nv.rom
+s3nv-position := $(CONFIG_S3_DATA_POS)
+s3nv-type := raw
+
+endif # CONFIG_HAVE_ACPI_RESUME == y
diff --git a/src/cpu/amd/pi/amd_late_init.c b/src/cpu/amd/pi/amd_late_init.c
new file mode 100644
index 0000000000..efb1667d8c
--- /dev/null
+++ b/src/cpu/amd/pi/amd_late_init.c
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <arch/acpi.h>
+#include <bootstate.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci_def.h>
+#include <device/pci_ops.h>
+
+#include <agesawrapper.h>
+#include <northbridge/amd/pi/agesawrapper_call.h>
+
+static void agesawrapper_post_device(void *unused)
+{
+ if (acpi_is_wakeup_s3())
+ return;
+
+ AGESAWRAPPER(amdinitlate);
+
+#if (1) /* NORTHBRIDGE_00730F01 */
+ device_t dev;
+ u32 value;
+ dev = dev_find_slot(0, PCI_DEVFN(0, 0)); /* clear IoapicSbFeatureEn */
+ pci_write_config32(dev, 0xF8, 0);
+ pci_write_config32(dev, 0xFC, 5); /* TODO: move it to dsdt.asl */
+
+ /* disable No Snoop */
+ dev = dev_find_slot(0, PCI_DEVFN(1, 1));
+ value = pci_read_config32(dev, 0x60);
+ value &= ~(1 << 11);
+ pci_write_config32(dev, 0x60, value);
+#endif
+
+ if (!acpi_s3_resume_allowed())
+ return;
+
+ AGESAWRAPPER(amdS3Save);
+}
+
+BOOT_STATE_INIT_ENTRIES(agesa_bscb) = {
+ BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT,
+ agesawrapper_post_device, NULL),
+};
diff --git a/src/cpu/amd/pi/cache_as_ram.inc b/src/cpu/amd/pi/cache_as_ram.inc
new file mode 100644
index 0000000000..449cf693f2
--- /dev/null
+++ b/src/cpu/amd/pi/cache_as_ram.inc
@@ -0,0 +1,110 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/******************************************************************************
+ * AMD Generic Encapsulated Software Architecture
+ *
+ * $Workfile:: cache_as_ram.inc
+ *
+ * Description: cache_as_ram.inc - AGESA Module Entry Point for GCC complier
+ *
+ ******************************************************************************
+ */
+
+#include "gcccar.inc"
+#include <cpu/x86/cache.h>
+
+/*
+ * XMM map:
+ * xmm0: BIST
+ * xmm1: backup ebx -- cpu_init_detected
+ */
+
+.code32
+.globl cache_as_ram_setup, disable_cache_as_ram, cache_as_ram_setup_out
+
+cache_as_ram_setup:
+
+ post_code(0xa0)
+
+ /* enable SSE2 128bit instructions */
+ /* Turn on OSFXSR [BIT9] and OSXMMEXCPT [BIT10] onto CR4 register */
+
+ movl %cr4, %eax
+ orl $(3<<9), %eax
+ movl %eax, %cr4
+
+ /* Get the cpu_init_detected */
+ mov $1, %eax
+ cpuid
+ shr $24, %ebx
+
+ /* Save the BIST result */
+ cvtsi2sd %ebp, %xmm0
+
+ /* for normal part %ebx already contain cpu_init_detected from fallback call */
+
+ /* Save the cpu_init_detected */
+ cvtsi2sd %ebx, %xmm1
+
+ post_code(0xa1)
+ AMD_ENABLE_STACK
+
+ post_code(0xa1)
+
+ /* Restore the BIST result */
+ cvtsd2si %xmm0, %edx
+
+ /* Restore the cpu_init_detected */
+ cvtsd2si %xmm1, %ebx
+
+ pushl %ebx /* init detected */
+ pushl %edx /* bist */
+ call cache_as_ram_main
+
+ /* Should never see this postcode */
+ post_code(0xaf)
+stop:
+ jmp stop
+
+disable_cache_as_ram:
+ /* Save return stack */
+ movd 0(%esp), %xmm1
+ movd %esp, %xmm0
+
+ /* Disable cache */
+ movl %cr0, %eax
+ orl $CR0_CacheDisable, %eax
+ movl %eax, %cr0
+
+ AMD_DISABLE_STACK
+
+ /* enable cache */
+ movl %cr0, %eax
+ andl $0x9fffffff, %eax
+ movl %eax, %cr0
+ xorl %eax, %eax
+
+ /* Restore the return stack */
+ wbinvd
+ movd %xmm0, %esp
+ movd %xmm1, (%esp)
+ ret
+
+cache_as_ram_setup_out:
diff --git a/src/cpu/amd/pi/heapmanager.c b/src/cpu/amd/pi/heapmanager.c
new file mode 100644
index 0000000000..d2c39312d5
--- /dev/null
+++ b/src/cpu/amd/pi/heapmanager.c
@@ -0,0 +1,342 @@
+
+#include "AGESA.h"
+#include "amdlib.h"
+#include <northbridge/amd/agesa/BiosCallOuts.h>
+#include "heapManager.h"
+
+#include <cbmem.h>
+#include <arch/acpi.h>
+#include <string.h>
+
+UINT32 GetHeapBase(AMD_CONFIG_PARAMS *StdHeader)
+{
+ UINT32 heap = BIOS_HEAP_START_ADDRESS;
+
+#if CONFIG_HAVE_ACPI_RESUME
+ /* Both romstage and ramstage has this S3 detect. */
+ if (acpi_get_sleep_type() == 3)
+ heap = (UINT32) cbmem_find(CBMEM_ID_RESUME_SCRATCH) +
+ (CONFIG_HIGH_SCRATCH_MEMORY_SIZE - BIOS_HEAP_SIZE);
+ /* himem_heap_base + high_stack_size */
+#endif
+ return heap;
+}
+
+void EmptyHeap(void)
+{
+ void *BiosManagerPtr = (void *) GetHeapBase(NULL);
+ memset(BiosManagerPtr, 0, BIOS_HEAP_SIZE);
+}
+
+#if CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY15_TN
+
+#define AGESA_RUNTIME_SIZE 4096
+
+static AGESA_STATUS alloc_cbmem(AGESA_BUFFER_PARAMS *AllocParams) {
+ static unsigned int used = 0;
+ void *p = cbmem_find(CBMEM_ID_AGESA_RUNTIME);
+
+ if ((AGESA_RUNTIME_SIZE - used) < AllocParams->BufferLength) {
+ return AGESA_BOUNDS_CHK;
+ }
+
+ /* first time allocation */
+ if (!p) {
+ p = cbmem_add(CBMEM_ID_AGESA_RUNTIME, AGESA_RUNTIME_SIZE);
+ if (!p)
+ return AGESA_BOUNDS_CHK;
+ }
+
+ AllocParams->BufferPointer = p + used;
+ used += AllocParams->BufferLength;
+ return AGESA_SUCCESS;
+}
+#endif
+
+AGESA_STATUS agesa_AllocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
+{
+ UINT32 AvailableHeapSize;
+ UINT8 *BiosHeapBaseAddr;
+ UINT32 CurrNodeOffset;
+ UINT32 PrevNodeOffset;
+ UINT32 FreedNodeOffset;
+ UINT32 BestFitNodeOffset;
+ UINT32 BestFitPrevNodeOffset;
+ UINT32 NextFreeOffset;
+ BIOS_BUFFER_NODE *CurrNodePtr;
+ BIOS_BUFFER_NODE *FreedNodePtr;
+ BIOS_BUFFER_NODE *BestFitNodePtr;
+ BIOS_BUFFER_NODE *BestFitPrevNodePtr;
+ BIOS_BUFFER_NODE *NextFreePtr;
+ BIOS_HEAP_MANAGER *BiosHeapBasePtr;
+ AGESA_BUFFER_PARAMS *AllocParams;
+
+ AllocParams = ((AGESA_BUFFER_PARAMS *) ConfigPtr);
+ AllocParams->BufferPointer = NULL;
+
+#if CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY15_TN
+ /* if the allocation is for runtime use simple CBMEM data */
+ if (Data == HEAP_CALLOUT_RUNTIME)
+ return alloc_cbmem(AllocParams);
+#endif
+
+ AvailableHeapSize = BIOS_HEAP_SIZE - sizeof (BIOS_HEAP_MANAGER);
+ BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader));
+ BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr;
+
+ if (BiosHeapBasePtr->StartOfAllocatedNodes == 0) {
+ /* First allocation */
+ CurrNodeOffset = sizeof (BIOS_HEAP_MANAGER);
+ CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
+ CurrNodePtr->BufferHandle = AllocParams->BufferHandle;
+ CurrNodePtr->BufferSize = AllocParams->BufferLength;
+ CurrNodePtr->NextNodeOffset = 0;
+ AllocParams->BufferPointer = (UINT8 *) CurrNodePtr + sizeof (BIOS_BUFFER_NODE);
+
+ /* Update the remaining free space */
+ FreedNodeOffset = CurrNodeOffset + CurrNodePtr->BufferSize + sizeof (BIOS_BUFFER_NODE);
+ FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
+ FreedNodePtr->BufferSize = AvailableHeapSize - sizeof (BIOS_BUFFER_NODE) - CurrNodePtr->BufferSize;
+ FreedNodePtr->NextNodeOffset = 0;
+
+ /* Update the offsets for Allocated and Freed nodes */
+ BiosHeapBasePtr->StartOfAllocatedNodes = CurrNodeOffset;
+ BiosHeapBasePtr->StartOfFreedNodes = FreedNodeOffset;
+ } else {
+ /* Find out whether BufferHandle has been allocated on the heap.
+ * If it has, return AGESA_BOUNDS_CHK.
+ */
+ CurrNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
+ CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
+
+ while (CurrNodeOffset != 0) {
+ CurrNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + CurrNodeOffset);
+ if (CurrNodePtr->BufferHandle == AllocParams->BufferHandle) {
+ return AGESA_BOUNDS_CHK;
+ }
+ CurrNodeOffset = CurrNodePtr->NextNodeOffset;
+ /* If BufferHandle has not been allocated on the heap, CurrNodePtr here points
+ * to the end of the allocated nodes list.
+ */
+ }
+ /* Find the node that best fits the requested buffer size */
+ FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
+ PrevNodeOffset = FreedNodeOffset;
+ BestFitNodeOffset = 0;
+ BestFitPrevNodeOffset = 0;
+ while (FreedNodeOffset != 0) {
+ FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
+ if (FreedNodePtr->BufferSize >= (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
+ if (BestFitNodeOffset == 0) {
+ /* First node that fits the requested buffer size */
+ BestFitNodeOffset = FreedNodeOffset;
+ BestFitPrevNodeOffset = PrevNodeOffset;
+ } else {
+ /* Find out whether current node is a better fit than the previous nodes */
+ BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
+ if (BestFitNodePtr->BufferSize > FreedNodePtr->BufferSize) {
+ BestFitNodeOffset = FreedNodeOffset;
+ BestFitPrevNodeOffset = PrevNodeOffset;
+ }
+ }
+ }
+ PrevNodeOffset = FreedNodeOffset;
+ FreedNodeOffset = FreedNodePtr->NextNodeOffset;
+ } /* end of while loop */
+
+ if (BestFitNodeOffset == 0) {
+ /* If we could not find a node that fits the requested buffer
+ * size, return AGESA_BOUNDS_CHK.
+ */
+ return AGESA_BOUNDS_CHK;
+ } else {
+ BestFitNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitNodeOffset);
+ BestFitPrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + BestFitPrevNodeOffset);
+
+ /* If BestFitNode is larger than the requested buffer, fragment the node further */
+ if (BestFitNodePtr->BufferSize > (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE))) {
+ NextFreeOffset = BestFitNodeOffset + AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE);
+
+ NextFreePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextFreeOffset);
+ NextFreePtr->BufferSize = BestFitNodePtr->BufferSize - (AllocParams->BufferLength + sizeof (BIOS_BUFFER_NODE));
+ NextFreePtr->NextNodeOffset = BestFitNodePtr->NextNodeOffset;
+ } else {
+ /* Otherwise, next free node is NextNodeOffset of BestFitNode */
+ NextFreeOffset = BestFitNodePtr->NextNodeOffset;
+ }
+
+ /* If BestFitNode is the first buffer in the list, then update
+ * StartOfFreedNodes to reflect the new free node.
+ */
+ if (BestFitNodeOffset == BiosHeapBasePtr->StartOfFreedNodes) {
+ BiosHeapBasePtr->StartOfFreedNodes = NextFreeOffset;
+ } else {
+ BestFitPrevNodePtr->NextNodeOffset = NextFreeOffset;
+ }
+
+ /* Add BestFitNode to the list of Allocated nodes */
+ CurrNodePtr->NextNodeOffset = BestFitNodeOffset;
+ BestFitNodePtr->BufferSize = AllocParams->BufferLength;
+ BestFitNodePtr->BufferHandle = AllocParams->BufferHandle;
+ BestFitNodePtr->NextNodeOffset = 0;
+
+ /* Remove BestFitNode from list of Freed nodes */
+ AllocParams->BufferPointer = (UINT8 *) BestFitNodePtr + sizeof (BIOS_BUFFER_NODE);
+ }
+ }
+
+ return AGESA_SUCCESS;
+}
+
+AGESA_STATUS agesa_DeallocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
+{
+
+ UINT8 *BiosHeapBaseAddr;
+ UINT32 AllocNodeOffset;
+ UINT32 PrevNodeOffset;
+ UINT32 NextNodeOffset;
+ UINT32 FreedNodeOffset;
+ UINT32 EndNodeOffset;
+ BIOS_BUFFER_NODE *AllocNodePtr;
+ BIOS_BUFFER_NODE *PrevNodePtr;
+ BIOS_BUFFER_NODE *FreedNodePtr;
+ BIOS_BUFFER_NODE *NextNodePtr;
+ BIOS_HEAP_MANAGER *BiosHeapBasePtr;
+ AGESA_BUFFER_PARAMS *AllocParams;
+
+ AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
+
+ BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader));
+ BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr;
+
+ /* Find target node to deallocate in list of allocated nodes.
+ * Return AGESA_BOUNDS_CHK if the BufferHandle is not found.
+ */
+ AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
+ AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
+ PrevNodeOffset = AllocNodeOffset;
+
+ while (AllocNodePtr->BufferHandle != AllocParams->BufferHandle) {
+ if (AllocNodePtr->NextNodeOffset == 0) {
+ return AGESA_BOUNDS_CHK;
+ }
+ PrevNodeOffset = AllocNodeOffset;
+ AllocNodeOffset = AllocNodePtr->NextNodeOffset;
+ AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
+ }
+
+ /* Remove target node from list of allocated nodes */
+ PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
+ PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
+
+ /* Zero out the buffer, and clear the BufferHandle */
+ LibAmdMemFill ((UINT8 *)AllocNodePtr + sizeof (BIOS_BUFFER_NODE), 0, AllocNodePtr->BufferSize, &(AllocParams->StdHeader));
+ AllocNodePtr->BufferHandle = 0;
+ AllocNodePtr->BufferSize += sizeof (BIOS_BUFFER_NODE);
+
+ /* Add deallocated node in order to the list of freed nodes */
+ FreedNodeOffset = BiosHeapBasePtr->StartOfFreedNodes;
+ FreedNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + FreedNodeOffset);
+
+ EndNodeOffset = AllocNodeOffset + AllocNodePtr->BufferSize;
+
+ if (AllocNodeOffset < FreedNodeOffset) {
+ /* Add to the start of the freed list */
+ if (EndNodeOffset == FreedNodeOffset) {
+ /* If the freed node is adjacent to the first node in the list, concatenate both nodes */
+ AllocNodePtr->BufferSize += FreedNodePtr->BufferSize;
+ AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset;
+
+ /* Clear the BufferSize and NextNodeOffset of the previous first node */
+ FreedNodePtr->BufferSize = 0;
+ FreedNodePtr->NextNodeOffset = 0;
+
+ } else {
+ /* Otherwise, add freed node to the start of the list
+ * Update NextNodeOffset and BufferSize to include the
+ * size of BIOS_BUFFER_NODE.
+ */
+ AllocNodePtr->NextNodeOffset = FreedNodeOffset;
+ }
+ /* Update StartOfFreedNodes to the new first node */
+ BiosHeapBasePtr->StartOfFreedNodes = AllocNodeOffset;
+ } else {
+ /* Traverse list of freed nodes to find where the deallocated node
+ * should be placed.
+ */
+ NextNodeOffset = FreedNodeOffset;
+ NextNodePtr = FreedNodePtr;
+ while (AllocNodeOffset > NextNodeOffset) {
+ PrevNodeOffset = NextNodeOffset;
+ if (NextNodePtr->NextNodeOffset == 0) {
+ break;
+ }
+ NextNodeOffset = NextNodePtr->NextNodeOffset;
+ NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
+ }
+
+ /* If deallocated node is adjacent to the next node,
+ * concatenate both nodes.
+ */
+ if (NextNodeOffset == EndNodeOffset) {
+ NextNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + NextNodeOffset);
+ AllocNodePtr->BufferSize += NextNodePtr->BufferSize;
+ AllocNodePtr->NextNodeOffset = NextNodePtr->NextNodeOffset;
+
+ NextNodePtr->BufferSize = 0;
+ NextNodePtr->NextNodeOffset = 0;
+ } else {
+ /*AllocNodePtr->NextNodeOffset = FreedNodePtr->NextNodeOffset; */
+ AllocNodePtr->NextNodeOffset = NextNodeOffset;
+ }
+ /* If deallocated node is adjacent to the previous node,
+ * concatenate both nodes.
+ */
+ PrevNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + PrevNodeOffset);
+ EndNodeOffset = PrevNodeOffset + PrevNodePtr->BufferSize;
+ if (AllocNodeOffset == EndNodeOffset) {
+ PrevNodePtr->NextNodeOffset = AllocNodePtr->NextNodeOffset;
+ PrevNodePtr->BufferSize += AllocNodePtr->BufferSize;
+
+ AllocNodePtr->BufferSize = 0;
+ AllocNodePtr->NextNodeOffset = 0;
+ } else {
+ PrevNodePtr->NextNodeOffset = AllocNodeOffset;
+ }
+ }
+ return AGESA_SUCCESS;
+}
+
+AGESA_STATUS agesa_LocateBuffer (UINT32 Func, UINT32 Data, VOID *ConfigPtr)
+{
+ UINT32 AllocNodeOffset;
+ UINT8 *BiosHeapBaseAddr;
+ BIOS_BUFFER_NODE *AllocNodePtr;
+ BIOS_HEAP_MANAGER *BiosHeapBasePtr;
+ AGESA_BUFFER_PARAMS *AllocParams;
+
+ AllocParams = (AGESA_BUFFER_PARAMS *) ConfigPtr;
+
+ BiosHeapBaseAddr = (UINT8 *) GetHeapBase(&(AllocParams->StdHeader));
+ BiosHeapBasePtr = (BIOS_HEAP_MANAGER *) BiosHeapBaseAddr;
+
+ AllocNodeOffset = BiosHeapBasePtr->StartOfAllocatedNodes;
+ AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
+
+ while (AllocParams->BufferHandle != AllocNodePtr->BufferHandle) {
+ if (AllocNodePtr->NextNodeOffset == 0) {
+ AllocParams->BufferPointer = NULL;
+ AllocParams->BufferLength = 0;
+ return AGESA_BOUNDS_CHK;
+ } else {
+ AllocNodeOffset = AllocNodePtr->NextNodeOffset;
+ AllocNodePtr = (BIOS_BUFFER_NODE *) (BiosHeapBaseAddr + AllocNodeOffset);
+ }
+ }
+
+ AllocParams->BufferPointer = (UINT8 *) ((UINT8 *) AllocNodePtr + sizeof (BIOS_BUFFER_NODE));
+ AllocParams->BufferLength = AllocNodePtr->BufferSize;
+
+ return AGESA_SUCCESS;
+
+}
diff --git a/src/cpu/amd/pi/s3_resume.c b/src/cpu/amd/pi/s3_resume.c
new file mode 100644
index 0000000000..fc619f7a34
--- /dev/null
+++ b/src/cpu/amd/pi/s3_resume.c
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <AGESA.h>
+#include <Lib/amdlib.h>
+#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 <device/device.h>
+#include <arch/io.h>
+#include <arch/acpi.h>
+#include <string.h>
+#include "Porting.h"
+#include <northbridge/amd/agesa/BiosCallOuts.h>
+#include "s3_resume.h"
+
+/* The size needs to be 4k aligned, which is the sector size of most flashes. */
+#define S3_DATA_VOLATILE_SIZE 0x6000
+#define S3_DATA_MTRR_SIZE 0x1000
+#define S3_DATA_NONVOLATILE_SIZE 0x1000
+
+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) && \
+ (S3_DATA_VOLATILE_SIZE + S3_DATA_MTRR_SIZE + S3_DATA_NONVOLATILE_SIZE) > CONFIG_S3_DATA_SIZE
+#error "Please increase the value of S3_DATA_SIZE"
+#endif
+
+static void get_s3nv_data(S3_DATA_TYPE S3DataType, u32 *pos, u32 *len)
+{
+ /* FIXME: Find file from CBFS. */
+ u32 s3_data = CONFIG_S3_DATA_POS;
+
+ switch (S3DataType) {
+ case S3DataTypeVolatile:
+ *pos = s3_data;
+ *len = S3_DATA_VOLATILE_SIZE;
+ break;
+ case S3DataTypeMTRR:
+ *pos = s3_data + S3_DATA_VOLATILE_SIZE;
+ *len = S3_DATA_MTRR_SIZE;
+ break;
+ case S3DataTypeNonVolatile:
+ *pos = s3_data + S3_DATA_VOLATILE_SIZE + S3_DATA_MTRR_SIZE;
+ *len = S3_DATA_NONVOLATILE_SIZE;
+ break;
+ default:
+ *pos = 0;
+ *len = 0;
+ break;
+ }
+}
+
+void restore_mtrr(void)
+{
+ u32 msr;
+ volatile UINT32 *msrPtr;
+ msr_t msr_data;
+
+ printk(BIOS_SPEW, "%s\n", __func__);
+
+ u32 pos, size;
+ get_s3nv_data(S3DataTypeMTRR, &pos, &size);
+ msrPtr = (UINT32 *)(pos + sizeof(UINT32));
+
+ disable_cache();
+
+ /* Enable access to AMD RdDram and WrDram extension bits */
+ msr_data = rdmsr(SYS_CFG);
+ msr_data.lo |= SYSCFG_MSR_MtrrFixDramModEn;
+ wrmsr(SYS_CFG, msr_data);
+
+ /* Now restore the Fixed MTRRs */
+ msr_data.lo = *msrPtr;
+ msrPtr ++;
+ msr_data.hi = *msrPtr;
+ msrPtr ++;
+ wrmsr(0x250, msr_data);
+
+ msr_data.lo = *msrPtr;
+ msrPtr ++;
+ msr_data.hi = *msrPtr;
+ msrPtr ++;
+ wrmsr(0x258, msr_data);
+
+ msr_data.lo = *msrPtr;
+ msrPtr ++;
+ msr_data.hi = *msrPtr;
+ msrPtr ++;
+ wrmsr(0x259, msr_data);
+
+ for (msr = 0x268; msr <= 0x26F; msr++) {
+ msr_data.lo = *msrPtr;
+ msrPtr ++;
+ msr_data.hi = *msrPtr;
+ msrPtr ++;
+ wrmsr(msr, msr_data);
+ }
+
+ /* Disable access to AMD RdDram and WrDram extension bits */
+ msr_data = rdmsr(SYS_CFG);
+ msr_data.lo &= ~SYSCFG_MSR_MtrrFixDramModEn;
+ wrmsr(SYS_CFG, msr_data);
+
+ /* Restore the Variable MTRRs */
+ for (msr = 0x200; msr <= 0x20F; msr++) {
+ msr_data.lo = *msrPtr;
+ msrPtr ++;
+ msr_data.hi = *msrPtr;
+ msrPtr ++;
+ wrmsr(msr, msr_data);
+ }
+
+ /* Restore SYSCFG MTRR */
+ msr_data.lo = *msrPtr;
+ msrPtr ++;
+ msr_data.hi = *msrPtr;
+ msrPtr ++;
+ wrmsr(SYS_CFG, msr_data);
+}
+
+#ifdef __PRE_RAM__
+static void *backup_resume(void)
+{
+ void *resume_backup_memory;
+
+ if (cbmem_recovery(1))
+ return NULL;
+
+ resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
+ if (((u32) resume_backup_memory == 0)
+ || ((u32) resume_backup_memory == -1)) {
+ printk(BIOS_ERR, "Error: resume_backup_memory: %x\n",
+ (u32) resume_backup_memory);
+ for (;;) ;
+ }
+
+ return resume_backup_memory;
+}
+
+static void move_stack_high_mem(void)
+{
+ void *high_stack;
+
+ high_stack = cbmem_find(CBMEM_ID_RESUME_SCRATCH);
+ memcpy(high_stack, (void *)BSP_STACK_BASE_ADDR,
+ (CONFIG_HIGH_SCRATCH_MEMORY_SIZE - BIOS_HEAP_SIZE));
+
+ __asm__
+ volatile ("add %0, %%esp; add %0, %%ebp; invd"::"g"
+ (high_stack - BSP_STACK_BASE_ADDR)
+ :);
+}
+#endif
+
+#ifndef __PRE_RAM__
+/* FIXME: Why store MTRR in SPI, just use CBMEM ? */
+static u8 mtrr_store[S3_DATA_MTRR_SIZE];
+
+static void write_mtrr(u8 **p_nvram_pos, unsigned idx)
+{
+ msr_t msr_data;
+ msr_data = rdmsr(idx);
+
+ memcpy(*p_nvram_pos, &msr_data, sizeof(msr_data));
+ *p_nvram_pos += sizeof(msr_data);
+}
+
+void OemAgesaSaveMtrr(void)
+{
+ msr_t msr_data;
+ u32 i;
+
+ u8 *nvram_pos = (u8 *) mtrr_store;
+
+ /* Enable access to AMD RdDram and WrDram extension bits */
+ msr_data = rdmsr(SYS_CFG);
+ msr_data.lo |= SYSCFG_MSR_MtrrFixDramModEn;
+ wrmsr(SYS_CFG, msr_data);
+
+ /* Fixed MTRRs */
+ write_mtrr(&nvram_pos, 0x250);
+ write_mtrr(&nvram_pos, 0x258);
+ write_mtrr(&nvram_pos, 0x259);
+
+ for (i = 0x268; i < 0x270; i++)
+ write_mtrr(&nvram_pos, i);
+
+ /* Disable access to AMD RdDram and WrDram extension bits */
+ msr_data = rdmsr(SYS_CFG);
+ msr_data.lo &= ~SYSCFG_MSR_MtrrFixDramModEn;
+ wrmsr(SYS_CFG, msr_data);
+
+ /* Variable MTRRs */
+ for (i = 0x200; i < 0x210; i++)
+ write_mtrr(&nvram_pos, i);
+
+ /* SYS_CFG */
+ write_mtrr(&nvram_pos, 0xC0010010);
+ /* TOM */
+ write_mtrr(&nvram_pos, 0xC001001A);
+ /* TOM2 */
+ write_mtrr(&nvram_pos, 0xC001001D);
+
+#if IS_ENABLED(CONFIG_SPI_FLASH)
+ u32 pos, size;
+ get_s3nv_data(S3DataTypeMTRR, &pos, &size);
+ spi_SaveS3info(pos, size, mtrr_store, nvram_pos - (u8 *) mtrr_store);
+#endif
+}
+
+u32 OemAgesaSaveS3Info(S3_DATA_TYPE S3DataType, u32 DataSize, void *Data)
+{
+#if IS_ENABLED(CONFIG_SPI_FLASH)
+ u32 pos, size;
+ get_s3nv_data(S3DataType, &pos, &size);
+ spi_SaveS3info(pos, size, Data, DataSize);
+#endif
+ return AGESA_SUCCESS;
+}
+#endif
+
+void OemAgesaGetS3Info(S3_DATA_TYPE S3DataType, u32 *DataSize, void **Data)
+{
+ AMD_CONFIG_PARAMS StdHeader;
+
+ u32 pos, size;
+ get_s3nv_data(S3DataType, &pos, &size);
+
+ if (S3DataType == S3DataTypeNonVolatile) {
+ *DataSize = *(UINT32 *) pos;
+ *Data = (void *) (pos + sizeof(UINT32));
+ } else if (S3DataType == S3DataTypeVolatile) {
+ u32 len = *(UINT32 *) pos;
+ void *src = (void *) (pos + sizeof(UINT32));
+ void *dst = (void *) GetHeapBase(&StdHeader);
+ memcpy(dst, src, len);
+ *DataSize = len;
+ *Data = dst;
+ }
+}
+
+#ifdef __PRE_RAM__
+static void set_resume_cache(void)
+{
+ msr_t msr;
+
+ /* disable fixed mtrr for now, it will be enabled by mtrr restore */
+ msr = rdmsr(SYSCFG_MSR);
+ msr.lo &= ~(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrFixDramModEn);
+ wrmsr(SYSCFG_MSR, msr);
+
+ /* Enable caching for 0 - coreboot ram using variable mtrr */
+ msr.lo = 0 | MTRR_TYPE_WRBACK;
+ msr.hi = 0;
+ wrmsr(MTRRphysBase_MSR(0), msr);
+ msr.lo = ~(CONFIG_RAMTOP - 1) | MTRRphysMaskValid;
+ msr.hi = (1 << (CONFIG_CPU_ADDR_BITS - 32)) - 1;
+ wrmsr(MTRRphysMask_MSR(0), msr);
+
+ /* Set the default memory type and disable fixed and enable variable MTRRs */
+ msr.hi = 0;
+ msr.lo = (1 << 11);
+ wrmsr(MTRRdefType_MSR, msr);
+
+ enable_cache();
+}
+
+void prepare_for_resume(void)
+{
+ printk(BIOS_DEBUG, "Find resume memory location\n");
+ void *resume_backup_memory = backup_resume();
+
+ post_code(0x62);
+ printk(BIOS_DEBUG, "Move CAR stack.\n");
+ move_stack_high_mem();
+ printk(BIOS_DEBUG, "stack moved to: 0x%x\n", (u32) (resume_backup_memory + HIGH_MEMORY_SAVE));
+
+ post_code(0x63);
+ disable_cache_as_ram();
+ printk(BIOS_DEBUG, "CAR disabled.\n");
+ set_resume_cache();
+
+ /*
+ * Copy the system memory that is in the ramstage area to the
+ * reserved area.
+ */
+ if (resume_backup_memory)
+ memcpy(resume_backup_memory, (void *)(CONFIG_RAMBASE), HIGH_MEMORY_SAVE);
+
+ printk(BIOS_DEBUG, "System memory saved. OK to load ramstage.\n");
+}
+#endif
diff --git a/src/cpu/amd/pi/s3_resume.h b/src/cpu/amd/pi/s3_resume.h
new file mode 100644
index 0000000000..14984dfc9c
--- /dev/null
+++ b/src/cpu/amd/pi/s3_resume.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef S3_RESUME_H
+#define S3_RESUME_H
+
+typedef enum {
+ S3DataTypeNonVolatile=0, ///< NonVolatile Data Type
+ S3DataTypeVolatile, ///< Volatile Data Type
+ S3DataTypeMTRR ///< MTRR storage
+} S3_DATA_TYPE;
+
+void restore_mtrr(void);
+void prepare_for_resume(void);
+
+u32 OemAgesaSaveS3Info (S3_DATA_TYPE S3DataType, u32 DataSize, void *Data);
+void OemAgesaGetS3Info (S3_DATA_TYPE S3DataType, u32 *DataSize, void **Data);
+void OemAgesaSaveMtrr (void);
+
+void spi_SaveS3info(u32 pos, u32 size, u8 *buf, u32 len);
+
+#endif
diff --git a/src/cpu/amd/pi/spi.c b/src/cpu/amd/pi/spi.c
new file mode 100644
index 0000000000..1c652fd295
--- /dev/null
+++ b/src/cpu/amd/pi/spi.c
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <console/console.h>
+#include <spi-generic.h>
+#include <spi_flash.h>
+
+#include "s3_resume.h"
+
+void spi_SaveS3info(u32 pos, u32 size, u8 *buf, u32 len)
+{
+ struct spi_flash *flash;
+
+ spi_init();
+ flash = spi_flash_probe(0, 0);
+ if (!flash) {
+ printk(BIOS_DEBUG, "Could not find SPI device\n");
+ /* Dont make flow stop. */
+ return;
+ }
+
+ flash->spi->rw = SPI_WRITE_FLAG;
+ spi_claim_bus(flash->spi);
+
+ flash->erase(flash, pos, size);
+ flash->write(flash, pos, sizeof(len), &len);
+ flash->write(flash, pos + sizeof(len), len, buf);
+
+ flash->spi->rw = SPI_WRITE_FLAG;
+ spi_release_bus(flash->spi);
+
+ return;
+}