diff options
Diffstat (limited to 'src/cpu/amd')
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; +} |