AGESA: Move API interface under drivers/

New AGESA support files will be used for binaryPI
platforms as well. Furthermore, some of those should
move from split nb/ sb/ directories to soc/, so move
support files for the API under drivers/.

Change-Id: I549788091de91f61de8b9adc223d52ffb5732235
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/21455
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
Kyösti Mälkki
2017-09-08 07:14:17 +03:00
parent 0f6c0b1a6f
commit d4955f0ade
26 changed files with 71 additions and 75 deletions

View File

@ -25,6 +25,7 @@ config CPU_AMD_AGESA
select ARCH_VERSTAGE_X86_32
select ARCH_ROMSTAGE_X86_32
select ARCH_RAMSTAGE_X86_32
select DRIVERS_AMD_PI
select TSC_SYNC_LFENCE
select UDELAY_LAPIC
select LAPIC_MONOTONIC_TIMER

View File

@ -18,20 +18,10 @@ subdirs-$(CONFIG_CPU_AMD_AGESA_FAMILY15) += family15
subdirs-$(CONFIG_CPU_AMD_AGESA_FAMILY15_TN) += family15tn
subdirs-$(CONFIG_CPU_AMD_AGESA_FAMILY16_KB) += family16kb
ramstage-y += s3_mtrr.c
ifeq ($(CONFIG_AGESA_LEGACY), y)
cpu_incs-y += $(src)/cpu/amd/agesa/cache_as_ram_legacy.inc
else
cpu_incs-y += $(src)/cpu/amd/agesa/cache_as_ram.S
romstage-y += romstage.c mtrr_fixme.c
endif
romstage-$(CONFIG_AGESA_LEGACY_WRAPPER) += heapmanager.c
postcar-y += cache_as_ram.S
ramstage-y += heapmanager.c
ramstage-$(CONFIG_AGESA_LEGACY_WRAPPER) += amd_late_init.c
ifeq ($(CONFIG_HAVE_ACPI_RESUME), y)

View File

@ -1,172 +0,0 @@
/*
* 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.S
*
* Description: cache_as_ram.S - AGESA Module Entry Point for GCC complier
*
******************************************************************************
*/
#include "gcccar.inc"
#include <cpu/x86/cache.h>
#include <cpu/x86/post_code.h>
.code32
.globl _cache_as_ram_setup, _cache_as_ram_setup_end
.globl chipset_teardown_car
_cache_as_ram_setup:
/* Preserve BIST. */
movd %eax, %mm0
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
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:
#endif
call early_all_cores
/* Must maintain 16-byte stack alignment here. */
pushl $0x0
pushl $0x0
pushl $0x0
movd %mm0, %eax /* bist */
pushl %eax
call romstage_main
#if IS_ENABLED(CONFIG_POSTCAR_STAGE)
/* We do not return. Execution continues with run_postcar_phase()
* calling to chipset_teardown_car below.
*/
jmp postcar_entry_failure
chipset_teardown_car:
/*
* Retrieve return address from stack as it will get trashed below if
* execution is utilizing the cache-as-ram stack.
*/
pop %esp
#else
movl %eax, %esp
/* Register %esp is new stacktop for remaining of romstage. */
#endif
/* Disable cache */
movl %cr0, %eax
orl $CR0_CacheDisable, %eax
movl %eax, %cr0
/* Register %esp is preserved in AMD_DISABLE_STACK. */
AMD_DISABLE_STACK
#if IS_ENABLED(CONFIG_POSTCAR_STAGE)
jmp *%esp
#else
/* enable cache */
movl %cr0, %eax
andl $0x9fffffff, %eax
movl %eax, %cr0
call romstage_after_car
#endif
/* Should never see this postcode */
post_code(0xaf)
stop:
hlt
jmp stop
/* These are here for linking purposes. */
.weak early_all_cores, romstage_main
early_all_cores:
romstage_main:
postcar_entry_failure:
/* Should never see this postcode */
post_code(0xae)
jmp stop
_cache_as_ram_setup_end:

View File

@ -28,7 +28,7 @@
#include <cpu/x86/mtrr.h>
#include <cpu/amd/amdfam14.h>
#include <arch/acpi.h>
#include <cpu/amd/agesa/s3_resume.h>
#include <northbridge/amd/agesa/agesa_helper.h>
#define MCI_STATUS 0x401

View File

@ -29,7 +29,7 @@
#include <cpu/x86/mtrr.h>
#include <cpu/amd/amdfam15.h>
#include <arch/acpi.h>
#include <cpu/amd/agesa/s3_resume.h>
#include <northbridge/amd/agesa/agesa_helper.h>
static void model_15_init(device_t dev)
{

View File

@ -28,7 +28,7 @@
#include <cpu/x86/mtrr.h>
#include <cpu/amd/amdfam16.h>
#include <arch/acpi.h>
#include <cpu/amd/agesa/s3_resume.h>
#include <northbridge/amd/agesa/agesa_helper.h>
static void model_16_init(device_t dev)
{

View File

@ -1,374 +0,0 @@
/*
* 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 <cbmem.h>
#include <northbridge/amd/agesa/agesa_helper.h>
#include <northbridge/amd/agesa/BiosCallOuts.h>
#include <arch/acpi.h>
#include <string.h>
/* BIOS_HEAP_START_ADDRESS is only for cold boots. */
#define BIOS_HEAP_SIZE 0x30000
#define BIOS_HEAP_START_ADDRESS 0x010000000
#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) && (HIGH_MEMORY_SCRATCH < BIOS_HEAP_SIZE)
#error Increase HIGH_MEMORY_SCRATCH allocation
#endif
void *GetHeapBase(void)
{
void *heap = (void *)BIOS_HEAP_START_ADDRESS;
if (acpi_is_wakeup_s3()) {
/* FIXME: For S3 resume path, buffer is in CBMEM
* with some arbitrary header. */
heap = cbmem_find(CBMEM_ID_RESUME_SCRATCH);
heap += 0x10;
}
return heap;
}
void EmptyHeap(void)
{
void *base = GetHeapBase();
memset(base, 0, BIOS_HEAP_SIZE);
printk(BIOS_DEBUG, "Wiped HEAP at [%08x - %08x]\n",
(unsigned int)(uintptr_t) base, (unsigned int)(uintptr_t) base + BIOS_HEAP_SIZE - 1);
}
#if defined(HEAP_CALLOUT_RUNTIME) && ENV_RAMSTAGE
#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
typedef struct _BIOS_HEAP_MANAGER {
UINT32 StartOfAllocatedNodes;
UINT32 StartOfFreedNodes;
} BIOS_HEAP_MANAGER;
typedef struct _BIOS_BUFFER_NODE {
UINT32 BufferHandle;
UINT32 BufferSize;
UINT32 NextNodeOffset;
} BIOS_BUFFER_NODE;
static AGESA_STATUS agesa_AllocateBuffer(BIOS_HEAP_MANAGER *BiosHeapBasePtr,
AGESA_BUFFER_PARAMS *AllocParams)
{
UINT32 AvailableHeapSize;
UINT8 *BiosHeapBaseAddr = (void *)BiosHeapBasePtr;
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;
AllocParams->BufferPointer = NULL;
AvailableHeapSize = BIOS_HEAP_SIZE - sizeof(BIOS_HEAP_MANAGER);
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;
}
static AGESA_STATUS agesa_DeallocateBuffer(BIOS_HEAP_MANAGER *BiosHeapBasePtr,
AGESA_BUFFER_PARAMS *AllocParams)
{
UINT8 *BiosHeapBaseAddr = (void *)BiosHeapBasePtr;
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;
/* 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;
}
static AGESA_STATUS agesa_LocateBuffer(BIOS_HEAP_MANAGER *BiosHeapBasePtr,
AGESA_BUFFER_PARAMS *AllocParams)
{
UINT32 AllocNodeOffset;
UINT8 *BiosHeapBaseAddr = (void *)BiosHeapBasePtr;
BIOS_BUFFER_NODE *AllocNodePtr;
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;
}
AGESA_STATUS HeapManagerCallout(UINT32 Func, UINTN Data, VOID *ConfigPtr)
{
AGESA_BUFFER_PARAMS *AllocParams = ConfigPtr;
#if defined(HEAP_CALLOUT_RUNTIME) && ENV_RAMSTAGE
if (Func == AGESA_ALLOCATE_BUFFER && Data == HEAP_CALLOUT_RUNTIME)
return alloc_cbmem(AllocParams);
#endif
/* Must not call GetHeapBase() in AGESA_UNSUPPORTED path. */
if (Func == AGESA_LOCATE_BUFFER)
return agesa_LocateBuffer(GetHeapBase(), AllocParams);
else if (Func == AGESA_ALLOCATE_BUFFER)
return agesa_AllocateBuffer(GetHeapBase(), AllocParams);
else if (Func == AGESA_DEALLOCATE_BUFFER)
return agesa_DeallocateBuffer(GetHeapBase(), AllocParams);
return AGESA_UNSUPPORTED;
}

View File

@ -1,100 +0,0 @@
/*
* 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 <arch/cpu.h>
#include <cbmem.h>
#include <console/console.h>
#include <cpu/amd/mtrr.h>
#include <cpu/cpu.h>
#include <cpu/x86/cache.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/mtrr.h>
#include <northbridge/amd/agesa/agesa_helper.h>
static void set_range_uc(u32 base, u32 size)
{
int i, max_var_mtrrs;
msr_t msr;
msr = rdmsr(MTRR_CAP_MSR);
max_var_mtrrs = msr.lo & MTRR_CAP_VCNT;
for (i = 0; i < max_var_mtrrs; i++) {
msr = rdmsr(MTRR_PHYS_MASK(i));
if (!(msr.lo & MTRR_PHYS_MASK_VALID))
break;
}
if (i == max_var_mtrrs)
die("Run out of unused MTRRs\n");
msr.hi = 0;
msr.lo = base | MTRR_TYPE_UNCACHEABLE;
wrmsr(MTRR_PHYS_BASE(i), msr);
msr.hi = (1 << (cpu_phys_address_size() - 32)) - 1;
msr.lo = ~(size - 1) | MTRR_PHYS_MASK_VALID;
wrmsr(MTRR_PHYS_MASK(i), msr);
}
void fixup_cbmem_to_UC(int s3resume)
{
if (s3resume)
return;
/* For normal path, INIT_POST has returned with all
* memory set WB cacheable. But we need CBMEM as UC
* to make CAR teardown with invalidation without
* writeback possible.
*/
uintptr_t top_of_ram = (uintptr_t) cbmem_top();
top_of_ram = ALIGN_UP(top_of_ram, 4 * MiB);
set_range_uc(top_of_ram - 4 * MiB, 4 * MiB);
set_range_uc(top_of_ram - 8 * MiB, 4 * MiB);
}
void recover_postcar_frame(struct postcar_frame *pcf, int s3resume)
{
msr_t base, mask;
int i;
/* Replicate non-UC MTRRs as left behind by AGESA.
*/
for (i = 0; i < pcf->max_var_mtrrs; i++) {
mask = rdmsr(MTRR_PHYS_MASK(i));
base = rdmsr(MTRR_PHYS_BASE(i));
u32 size = ~(mask.lo & ~0xfff) + 1;
u8 type = base.lo & 0x7;
base.lo &= ~0xfff;
if (!(mask.lo & MTRR_PHYS_MASK_VALID) ||
(type == MTRR_TYPE_UNCACHEABLE))
continue;
postcar_frame_add_mtrr(pcf, base.lo, size, type);
}
/* For S3 resume path, INIT_RESUME does not return with
* memory covering CBMEM set as WB cacheable. For better
* speed make them WB after CAR teardown.
*/
if (s3resume) {
uintptr_t top_of_ram = (uintptr_t) cbmem_top();
top_of_ram = ALIGN_DOWN(top_of_ram, 4*MiB);
postcar_frame_add_mtrr(pcf, top_of_ram - 4*MiB, 4*MiB,
MTRR_TYPE_WRBACK);
postcar_frame_add_mtrr(pcf, top_of_ram - 8*MiB, 4*MiB,
MTRR_TYPE_WRBACK);
}
}

View File

@ -1,120 +0,0 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2017 Kyösti Mälkki
*
* 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 <arch/cpu.h>
#include <cbmem.h>
#include <cpu/amd/car.h>
#include <cpu/x86/bist.h>
#include <console/console.h>
#include <halt.h>
#include <program_loading.h>
#include <romstage_handoff.h>
#include <smp/node.h>
#include <string.h>
#include <timestamp.h>
#include <northbridge/amd/agesa/agesa_helper.h>
#include <northbridge/amd/agesa/state_machine.h>
#if IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
#error "Only EARLY_CBMEM_INIT is supported."
#endif
#if !IS_ENABLED(CONFIG_POSTCAR_STAGE)
#error "Only POSTCAR_STAGE is supported."
#endif
#if HAS_LEGACY_WRAPPER
#error "LEGACY_WRAPPER code not supported"
#endif
void asmlinkage early_all_cores(void)
{
amd_initmmio();
}
void __attribute__((weak)) platform_once(struct sysinfo *cb)
{
board_BeforeAgesa(cb);
}
static void fill_sysinfo(struct sysinfo *cb)
{
memset(cb, 0, sizeof(*cb));
cb->s3resume = acpi_is_wakeup_s3();
agesa_set_interface(cb);
}
void * asmlinkage romstage_main(unsigned long bist)
{
struct postcar_frame pcf;
struct sysinfo romstage_state;
struct sysinfo *cb = &romstage_state;
u8 initial_apic_id = (u8) (cpuid_ebx(1) >> 24);
int cbmem_initted = 0;
fill_sysinfo(cb);
if ((initial_apic_id == 0) && boot_cpu()) {
timestamp_init(timestamp_get());
timestamp_add_now(TS_START_ROMSTAGE);
platform_once(cb);
console_init();
}
printk(BIOS_DEBUG, "APIC %02d: CPU Family_Model = %08x\n",
initial_apic_id, cpuid_eax(1));
/* Halt if there was a built in self test failure */
report_bist_failure(bist);
agesa_execute_state(cb, AMD_INIT_RESET);
agesa_execute_state(cb, AMD_INIT_EARLY);
timestamp_add_now(TS_BEFORE_INITRAM);
if (!cb->s3resume)
agesa_execute_state(cb, AMD_INIT_POST);
else
agesa_execute_state(cb, AMD_INIT_RESUME);
/* FIXME: Detect if TSC frequency changed during raminit? */
timestamp_rescale_table(1, 4);
timestamp_add_now(TS_AFTER_INITRAM);
/* Work around AGESA setting all memory as WB on normal
* boot path.
*/
fixup_cbmem_to_UC(cb->s3resume);
cbmem_initted = !cbmem_recovery(cb->s3resume);
if (cb->s3resume && !cbmem_initted) {
printk(BIOS_EMERG, "Unable to recover CBMEM\n");
halt();
}
romstage_handoff_init(cb->s3resume);
postcar_frame_init(&pcf, HIGH_ROMSTAGE_STACK_SIZE);
recover_postcar_frame(&pcf, cb->s3resume);
run_postcar_phase(&pcf);
/* We do not return. */
return NULL;
}

View File

@ -1,134 +0,0 @@
/*
* 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 <stdint.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/mtrr.h>
#include <cpu/amd/mtrr.h>
#include <cpu/x86/cache.h>
#include <string.h>
#include "s3_resume.h"
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 backup_mtrr(void *mtrr_store, u32 *mtrr_store_size)
{
u8 *nvram_pos = mtrr_store;
msr_t msr_data;
u32 i;
/* Enable access to AMD RdDram and WrDram extension bits */
msr_data = rdmsr(SYSCFG_MSR);
msr_data.lo |= SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYSCFG_MSR, 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(SYSCFG_MSR);
msr_data.lo &= ~SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYSCFG_MSR, msr_data);
/* Variable MTRRs */
for (i = 0x200; i < 0x210; i++)
write_mtrr(&nvram_pos, i);
/* SYSCFG_MSR */
write_mtrr(&nvram_pos, SYSCFG_MSR);
/* TOM */
write_mtrr(&nvram_pos, 0xC001001A);
/* TOM2 */
write_mtrr(&nvram_pos, 0xC001001D);
*mtrr_store_size = nvram_pos - (u8*) mtrr_store;
}
void restore_mtrr(void)
{
volatile u32 *msrPtr = (u32 *) OemS3Saved_MTRR_Storage();
u32 msr;
msr_t msr_data;
if (!msrPtr)
return;
disable_cache();
/* Enable access to AMD RdDram and WrDram extension bits */
msr_data = rdmsr(SYSCFG_MSR);
msr_data.lo |= SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYSCFG_MSR, 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(SYSCFG_MSR);
msr_data.lo &= ~SYSCFG_MSR_MtrrFixDramModEn;
wrmsr(SYSCFG_MSR, 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(SYSCFG_MSR, msr_data);
}

View File

@ -1,24 +0,0 @@
/*
* 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.
*/
#ifndef S3_RESUME_H
#define S3_RESUME_H
void restore_mtrr(void);
void backup_mtrr(void *mtrr_store, u32 *mtrr_store_size);
const void *OemS3Saved_MTRR_Storage(void);
#endif

View File

@ -23,6 +23,7 @@ config CPU_AMD_PI
select ARCH_VERSTAGE_X86_32
select ARCH_ROMSTAGE_X86_32
select ARCH_RAMSTAGE_X86_32
select DRIVERS_AMD_PI
select TSC_SYNC_LFENCE
select UDELAY_LAPIC
select LAPIC_MONOTONIC_TIMER

View File

@ -17,16 +17,7 @@ subdirs-$(CONFIG_CPU_AMD_PI_00630F01) += 00630F01
subdirs-$(CONFIG_CPU_AMD_PI_00730F01) += 00730F01
subdirs-$(CONFIG_CPU_AMD_PI_00660F01) += 00660F01
cpu_incs-y += $(src)/cpu/amd/agesa/cache_as_ram.S
postcar-y += ../agesa/cache_as_ram.S
ifeq ($(CONFIG_BINARYPI_LEGACY_WRAPPER), y)
romstage-y += romstage.c
ramstage-y += amd_late_init.c
romstage-y += ../agesa/heapmanager.c
else
romstage-y += ../agesa/romstage.c
romstage-y += ../agesa/mtrr_fixme.c
endif
ramstage-y += ../agesa/heapmanager.c