aboutsummaryrefslogtreecommitdiff
path: root/src/soc/amd/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/soc/amd/common')
-rw-r--r--src/soc/amd/common/Kconfig8
-rw-r--r--src/soc/amd/common/Makefile.inc7
-rw-r--r--src/soc/amd/common/amd_late_init.c40
-rw-r--r--src/soc/amd/common/cache_as_ram.inc170
-rw-r--r--src/soc/amd/common/heapmanager.c319
-rw-r--r--src/soc/amd/common/spi.c41
6 files changed, 585 insertions, 0 deletions
diff --git a/src/soc/amd/common/Kconfig b/src/soc/amd/common/Kconfig
index fac3f43565..d4fe1f7523 100644
--- a/src/soc/amd/common/Kconfig
+++ b/src/soc/amd/common/Kconfig
@@ -2,3 +2,11 @@ config SOC_AMD_COMMON
bool
help
common code for AMD SOCs
+
+if SOC_AMD_COMMON
+
+config SOC_AMD_PI
+ bool
+ default n
+
+endif # SOC_AMD_COMMON
diff --git a/src/soc/amd/common/Makefile.inc b/src/soc/amd/common/Makefile.inc
index 689065bd5a..1a4927efaa 100644
--- a/src/soc/amd/common/Makefile.inc
+++ b/src/soc/amd/common/Makefile.inc
@@ -1,5 +1,12 @@
ifeq ($(CONFIG_SOC_AMD_COMMON),y)
+cpu_incs-y += $(src)/soc/amd/common/cache_as_ram.inc
+
+romstage-y += heapmanager.c
+
+ramstage-y += amd_late_init.c
ramstage-y += amd_pci_util.c
+ramstage-y += heapmanager.c
+ramstage-$(CONFIG_SPI_FLASH) += spi.c
endif
diff --git a/src/soc/amd/common/amd_late_init.c b/src/soc/amd/common/amd_late_init.c
new file mode 100644
index 0000000000..d9a5b43743
--- /dev/null
+++ b/src/soc/amd/common/amd_late_init.c
@@ -0,0 +1,40 @@
+/*
+ * 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 <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 <northbridge/amd/pi/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 (!acpi_s3_resume_allowed())
+ return;
+
+ AGESAWRAPPER(amdS3Save);
+}
+
+BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT,
+ agesawrapper_post_device, NULL);
diff --git a/src/soc/amd/common/cache_as_ram.inc b/src/soc/amd/common/cache_as_ram.inc
new file mode 100644
index 0000000000..c0a69ec74a
--- /dev/null
+++ b/src/soc/amd/common/cache_as_ram.inc
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+/******************************************************************************
+ * 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
+
+ /* Align the stack. */
+ and $0xFFFFFFF0, %esp
+
+#ifdef __x86_64__
+ /* switch to 64 bit long mode */
+ mov %esi, %ecx
+ add $0, %ecx # core number
+ xor %eax, %eax
+ lea (0x1000+0x23)(%ecx), %edi
+ mov %edi, (%ecx)
+ mov %eax, 4(%ecx)
+
+ lea 0x1000(%ecx), %edi
+ movl $0x000000e3, 0x00(%edi)
+ movl %eax, 0x04(%edi)
+ movl $0x400000e3, 0x08(%edi)
+ movl %eax, 0x0c(%edi)
+ movl $0x800000e3, 0x10(%edi)
+ movl %eax, 0x14(%edi)
+ movl $0xc00000e3, 0x18(%edi)
+ movl %eax, 0x1c(%edi)
+
+ # load ROM based identity mapped page tables
+ mov %ecx, %eax
+ mov %eax, %cr3
+
+ # enable PAE
+ mov %cr4, %eax
+ bts $5, %eax
+ mov %eax, %cr4
+
+ # enable long mode
+ mov $0xC0000080, %ecx
+ rdmsr
+ bts $8, %eax
+ wrmsr
+
+ # enable paging
+ mov %cr0, %eax
+ bts $31, %eax
+ mov %eax, %cr0
+
+ # use call far to switch to 64-bit code segment
+ ljmp $0x18, $1f
+1:
+ /* Pass the cpu_init_detected */
+ cvtsd2si %xmm1, %esi
+
+ /* Pass the BIST result */
+ cvtsd2si %xmm0, %edi
+
+
+ .code64
+ call cache_as_ram_main
+ .code32
+
+#else
+
+ /* Restore the BIST result */
+ cvtsd2si %xmm0, %edx
+
+ /* Restore the cpu_init_detected */
+ cvtsd2si %xmm1, %ebx
+
+ /* Must maintain 16-byte stack alignment here. */
+ pushl $0x0
+ pushl $0x0
+ pushl %ebx /* init detected */
+ pushl %edx /* bist */
+ call cache_as_ram_main
+#endif
+
+ /* 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:
+#ifdef __x86_64__
+.code64
+#endif
diff --git a/src/soc/amd/common/heapmanager.c b/src/soc/amd/common/heapmanager.c
new file mode 100644
index 0000000000..b733fe881e
--- /dev/null
+++ b/src/soc/amd/common/heapmanager.c
@@ -0,0 +1,319 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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 <AGESA.h>
+#include <amdlib.h>
+#include <arch/acpi.h>
+#include <BiosCallOuts.h>
+#include <cbmem.h>
+#include <heapManager.h>
+#include <string.h>
+
+UINT32 GetHeapBase(AMD_CONFIG_PARAMS *StdHeader)
+{
+ UINT32 heap = BIOS_HEAP_START_ADDRESS;
+
+ if (acpi_is_wakeup_s3())
+ heap = (UINT32) cbmem_find(CBMEM_ID_RESUME_SCRATCH);
+
+ return heap;
+}
+
+void EmptyHeap(void)
+{
+ void *BiosManagerPtr = (void *) GetHeapBase(NULL);
+ memset(BiosManagerPtr, 0, BIOS_HEAP_SIZE);
+}
+
+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;
+
+ 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/soc/amd/common/spi.c b/src/soc/amd/common/spi.c
new file mode 100644
index 0000000000..ce6deef505
--- /dev/null
+++ b/src/soc/amd/common/spi.c
@@ -0,0 +1,41 @@
+/*
+ * 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 <spi-generic.h>
+#include <spi_flash.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;
+ }
+
+ spi_flash_volatile_group_begin(flash);
+
+ spi_flash_erase(flash, pos, size);
+ spi_flash_write(flash, pos, sizeof(len), &len);
+ spi_flash_write(flash, pos + sizeof(len), len, buf);
+
+ spi_flash_volatile_group_end(flash);
+
+ return;
+}