mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
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>
398 lines
9.5 KiB
C
398 lines
9.5 KiB
C
/*
|
|
* This file is part of the coreboot project.
|
|
*
|
|
* Copyright (C) 2011-2012 Advanced Micro Devices, Inc.
|
|
* Copyright (C) 2016 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 <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include <arch/acpi.h>
|
|
#include <bootstate.h>
|
|
#include <cbfs.h>
|
|
#include <cbmem.h>
|
|
|
|
#include <northbridge/amd/agesa/state_machine.h>
|
|
#include <northbridge/amd/agesa/agesa_helper.h>
|
|
#include <northbridge/amd/agesa/BiosCallOuts.h>
|
|
#include "amdlib.h"
|
|
|
|
#include "AMD.h"
|
|
|
|
#if IS_ENABLED(CONFIG_CPU_AMD_AGESA_OPENSOURCE)
|
|
#include "Dispatcher.h"
|
|
#endif
|
|
|
|
#if ENV_ROMSTAGE
|
|
#include <PlatformMemoryConfiguration.h>
|
|
CONST PSO_ENTRY ROMDATA DefaultPlatformMemoryConfiguration[] = {PSO_END};
|
|
#endif
|
|
|
|
static void agesa_locate_image(AMD_CONFIG_PARAMS *StdHeader)
|
|
{
|
|
#if IS_ENABLED(CONFIG_CPU_AMD_AGESA_BINARY_PI)
|
|
const char ModuleIdentifier[] = AGESA_ID;
|
|
const void *agesa, *image;
|
|
size_t file_size;
|
|
|
|
agesa = cbfs_boot_map_with_leak((const char *)CONFIG_AGESA_CBFS_NAME,
|
|
CBFS_TYPE_RAW, &file_size);
|
|
if (agesa == NULL)
|
|
return;
|
|
|
|
image = LibAmdLocateImage(agesa, agesa + file_size, 4096,
|
|
ModuleIdentifier);
|
|
StdHeader->ImageBasePtr = (void*) image;
|
|
#endif
|
|
}
|
|
|
|
void agesa_set_interface(struct sysinfo *cb)
|
|
{
|
|
memset(&cb->StdHeader, 0, sizeof(AMD_CONFIG_PARAMS));
|
|
|
|
cb->StdHeader.CalloutPtr = GetBiosCallout;
|
|
|
|
if (IS_ENABLED(CONFIG_CPU_AMD_AGESA_BINARY_PI)) {
|
|
agesa_locate_image(&cb->StdHeader);
|
|
AMD_IMAGE_HEADER *image =
|
|
(void*)(uintptr_t)cb->StdHeader.ImageBasePtr;
|
|
ASSERT(image);
|
|
AMD_MODULE_HEADER *module =
|
|
(void*)(uintptr_t)image->ModuleInfoOffset;
|
|
ASSERT(module && module->ModuleDispatcher);
|
|
}
|
|
}
|
|
|
|
AGESA_STATUS module_dispatch(AGESA_STRUCT_NAME func,
|
|
AMD_CONFIG_PARAMS *StdHeader)
|
|
{
|
|
MODULE_ENTRY dispatcher;
|
|
|
|
#if IS_ENABLED(CONFIG_CPU_AMD_AGESA_OPENSOURCE)
|
|
dispatcher = AmdAgesaDispatcher;
|
|
#endif
|
|
#if IS_ENABLED(CONFIG_CPU_AMD_AGESA_BINARY_PI)
|
|
AMD_IMAGE_HEADER *image = (void*)(uintptr_t)StdHeader->ImageBasePtr;
|
|
AMD_MODULE_HEADER *module = (void*)(uintptr_t)image->ModuleInfoOffset;
|
|
dispatcher = module->ModuleDispatcher;
|
|
#endif
|
|
|
|
StdHeader->Func = func;
|
|
return dispatcher(StdHeader);
|
|
}
|
|
|
|
static AGESA_STATUS amd_create_struct(AMD_INTERFACE_PARAMS *aip,
|
|
AGESA_STRUCT_NAME func, void *buf, size_t len)
|
|
{
|
|
aip->AgesaFunctionName = func;
|
|
aip->AllocationMethod = 0;
|
|
aip->NewStructPtr = buf;
|
|
aip->NewStructSize = len;
|
|
if (buf != NULL && len != 0)
|
|
aip->AllocationMethod = ByHost;
|
|
|
|
return module_dispatch(AMD_CREATE_STRUCT, &aip->StdHeader);
|
|
}
|
|
|
|
static AGESA_STATUS amd_release_struct(AMD_INTERFACE_PARAMS *aip)
|
|
{
|
|
/* Cannot release AMD_LATE_PARAMS until ACPI tables are done. */
|
|
if (aip->AgesaFunctionName == AMD_INIT_LATE)
|
|
return AGESA_SUCCESS;
|
|
|
|
return module_dispatch(AMD_RELEASE_STRUCT, &aip->StdHeader);
|
|
}
|
|
|
|
/* By design, for each valid AGESA_STRUCT_NAME, AMD_CONFIG_PARAMS
|
|
* can be evaluated to apply correct typecast based on Func field.
|
|
*/
|
|
|
|
static AGESA_STATUS romstage_dispatch(struct sysinfo *cb,
|
|
AGESA_STRUCT_NAME func, AMD_CONFIG_PARAMS *StdHeader)
|
|
{
|
|
AGESA_STATUS status = AGESA_UNSUPPORTED;
|
|
|
|
switch (func)
|
|
{
|
|
case AMD_INIT_RESET:
|
|
{
|
|
AMD_RESET_PARAMS *param = (void *)StdHeader;
|
|
platform_BeforeInitReset(cb, param);
|
|
board_BeforeInitReset(cb, param);
|
|
status = module_dispatch(func, StdHeader);
|
|
break;
|
|
}
|
|
|
|
case AMD_INIT_EARLY:
|
|
{
|
|
AMD_EARLY_PARAMS *param = (void *)StdHeader;
|
|
platform_BeforeInitEarly(cb, param);
|
|
board_BeforeInitEarly(cb, param);
|
|
status = module_dispatch(func, StdHeader);
|
|
break;
|
|
}
|
|
|
|
case AMD_INIT_POST:
|
|
{
|
|
AMD_POST_PARAMS *param = (void *)StdHeader;
|
|
platform_BeforeInitPost(cb, param);
|
|
board_BeforeInitPost(cb, param);
|
|
status = module_dispatch(func, StdHeader);
|
|
platform_AfterInitPost(cb, param);
|
|
break;
|
|
}
|
|
|
|
case AMD_INIT_RESUME:
|
|
{
|
|
AMD_RESUME_PARAMS *param = (void *)StdHeader;
|
|
platform_BeforeInitResume(cb, param);
|
|
status = module_dispatch(func, StdHeader);
|
|
platform_AfterInitResume(cb, param);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
return status;
|
|
}
|
|
|
|
static AGESA_STATUS ramstage_dispatch(struct sysinfo *cb,
|
|
AGESA_STRUCT_NAME func, AMD_CONFIG_PARAMS *StdHeader)
|
|
{
|
|
AGESA_STATUS status = AGESA_UNSUPPORTED;
|
|
|
|
switch (func)
|
|
{
|
|
case AMD_INIT_ENV:
|
|
{
|
|
AMD_ENV_PARAMS *param = (void *)StdHeader;
|
|
platform_BeforeInitEnv(cb, param);
|
|
board_BeforeInitEnv(cb, param);
|
|
status = module_dispatch(func, StdHeader);
|
|
platform_AfterInitEnv(cb, param);
|
|
break;
|
|
}
|
|
|
|
case AMD_S3LATE_RESTORE:
|
|
{
|
|
AMD_S3LATE_PARAMS *param = (void *)StdHeader;
|
|
platform_BeforeS3LateRestore(cb, param);
|
|
status = module_dispatch(func, StdHeader);
|
|
platform_AfterS3LateRestore(cb, param);
|
|
break;
|
|
}
|
|
|
|
case AMD_INIT_MID:
|
|
{
|
|
AMD_MID_PARAMS *param = (void *)StdHeader;
|
|
platform_BeforeInitMid(cb, param);
|
|
board_BeforeInitMid(cb, param);
|
|
status = module_dispatch(func, StdHeader);
|
|
break;
|
|
}
|
|
|
|
case AMD_S3_SAVE:
|
|
{
|
|
AMD_S3SAVE_PARAMS *param = (void *)StdHeader;
|
|
status = module_dispatch(func, StdHeader);
|
|
platform_AfterS3Save(cb, param);
|
|
break;
|
|
}
|
|
|
|
case AMD_INIT_LATE:
|
|
{
|
|
AMD_LATE_PARAMS *param = (void *)StdHeader;
|
|
status = module_dispatch(func, StdHeader);
|
|
platform_AfterInitLate(cb, param);
|
|
completion_InitLate(cb, param);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/* DEBUG trace helper */
|
|
|
|
struct agesa_state
|
|
{
|
|
u8 apic_id;
|
|
|
|
AGESA_STRUCT_NAME func;
|
|
const char *function_name;
|
|
};
|
|
|
|
static void state_on_entry(struct agesa_state *task, AGESA_STRUCT_NAME func,
|
|
const char *struct_name)
|
|
{
|
|
task->apic_id = (u8) (cpuid_ebx(1) >> 24);
|
|
task->func = func;
|
|
task->function_name = struct_name;
|
|
|
|
printk(BIOS_DEBUG, "\nAPIC %02d: ** Enter %s [%08x]\n",
|
|
task->apic_id, task->function_name, task->func);
|
|
}
|
|
|
|
static void state_on_exit(struct agesa_state *task,
|
|
AMD_CONFIG_PARAMS *StdHeader)
|
|
{
|
|
printk(BIOS_DEBUG, "APIC %02d: Heap in %s (%d) at 0x%08x\n",
|
|
task->apic_id, heap_status_name(StdHeader->HeapStatus),
|
|
StdHeader->HeapStatus, (u32)StdHeader->HeapBasePtr);
|
|
|
|
printk(BIOS_DEBUG, "APIC %02d: ** Exit %s [%08x]\n",
|
|
task->apic_id, task->function_name, task->func);
|
|
}
|
|
|
|
int agesa_execute_state(struct sysinfo *cb, AGESA_STRUCT_NAME func)
|
|
{
|
|
AMD_INTERFACE_PARAMS aip;
|
|
union {
|
|
AMD_RESET_PARAMS reset;
|
|
AMD_S3LATE_PARAMS s3late;
|
|
} agesa_params;
|
|
void *buf = NULL;
|
|
size_t len = 0;
|
|
const char *state_name = agesa_struct_name(func);
|
|
|
|
AGESA_STATUS status, final;
|
|
|
|
struct agesa_state task;
|
|
memset(&task, 0, sizeof(task));
|
|
state_on_entry(&task, func, state_name);
|
|
|
|
aip.StdHeader = cb->StdHeader;
|
|
|
|
/* For these calls, heap is not available. */
|
|
if (func == AMD_INIT_RESET || func == AMD_S3LATE_RESTORE) {
|
|
buf = (void *) &agesa_params;
|
|
len = sizeof(agesa_params);
|
|
memcpy(buf, &cb->StdHeader, sizeof(cb->StdHeader));
|
|
}
|
|
|
|
status = amd_create_struct(&aip, func, buf, len);
|
|
ASSERT(status == AGESA_SUCCESS);
|
|
|
|
/* Must call the function buffer was allocated for.*/
|
|
AMD_CONFIG_PARAMS *StdHeader = aip.NewStructPtr;
|
|
ASSERT(StdHeader->Func == func);
|
|
|
|
if (ENV_ROMSTAGE)
|
|
final = romstage_dispatch(cb, func, StdHeader);
|
|
|
|
if (ENV_RAMSTAGE)
|
|
final = ramstage_dispatch(cb, func, StdHeader);
|
|
|
|
agesawrapper_trace(final, StdHeader, state_name);
|
|
ASSERT(final < AGESA_FATAL);
|
|
|
|
status = amd_release_struct(&aip);
|
|
ASSERT(status == AGESA_SUCCESS);
|
|
|
|
state_on_exit(&task, &aip.StdHeader);
|
|
|
|
return (final < AGESA_FATAL) ? 0 : -1;
|
|
}
|
|
|
|
#if ENV_RAMSTAGE
|
|
|
|
static void amd_bs_ramstage_init(void *arg)
|
|
{
|
|
struct sysinfo *cb = arg;
|
|
|
|
agesa_set_interface(cb);
|
|
|
|
if (!acpi_is_wakeup_s3())
|
|
agesa_execute_state(cb, AMD_INIT_ENV);
|
|
else {
|
|
agesa_execute_state(cb, AMD_S3LATE_RESTORE);
|
|
fchs3earlyrestore(&cb->StdHeader);
|
|
}
|
|
}
|
|
|
|
void sb_After_Pci_Restore_Init(void);
|
|
|
|
static void amd_bs_dev_enable(void *arg)
|
|
{
|
|
struct sysinfo *cb = arg;
|
|
|
|
if (!acpi_is_wakeup_s3())
|
|
agesa_execute_state(cb, AMD_INIT_MID);
|
|
|
|
/* FIXME */
|
|
if (IS_ENABLED(CONFIG_AMD_SB_CIMX) && acpi_is_wakeup_s3())
|
|
sb_After_Pci_Restore_Init();
|
|
}
|
|
|
|
static void amd_bs_post_device(void *arg)
|
|
{
|
|
struct sysinfo *cb = arg;
|
|
|
|
if (acpi_is_wakeup_s3()) {
|
|
fchs3laterestore(&cb->StdHeader);
|
|
return;
|
|
}
|
|
|
|
agesa_execute_state(cb, AMD_INIT_LATE);
|
|
|
|
if (!acpi_s3_resume_allowed())
|
|
return;
|
|
|
|
agesa_execute_state(cb, AMD_S3_SAVE);
|
|
}
|
|
|
|
static struct sysinfo state_machine;
|
|
|
|
BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, amd_bs_ramstage_init,
|
|
&state_machine);
|
|
|
|
BOOT_STATE_INIT_ENTRY(BS_DEV_ENABLE, BS_ON_ENTRY, amd_bs_dev_enable,
|
|
&state_machine);
|
|
|
|
BOOT_STATE_INIT_ENTRY(BS_POST_DEVICE, BS_ON_EXIT, amd_bs_post_device,
|
|
&state_machine);
|
|
|
|
#endif /* ENV_RAMSTAGE */
|
|
|
|
/* Empty stubs for cases board does not need to override anything. */
|
|
void __attribute__((weak))
|
|
board_BeforeInitReset(struct sysinfo *cb, AMD_RESET_PARAMS *Reset) { }
|
|
void __attribute__((weak))
|
|
board_BeforeInitEarly(struct sysinfo *cb, AMD_EARLY_PARAMS *Early) { }
|
|
void __attribute__((weak))
|
|
board_BeforeInitPost(struct sysinfo *cb, AMD_POST_PARAMS *Post) { }
|
|
void __attribute__((weak))
|
|
board_BeforeInitEnv(struct sysinfo *cb, AMD_ENV_PARAMS *Env) { }
|
|
void __attribute__((weak))
|
|
board_BeforeInitMid(struct sysinfo *cb, AMD_MID_PARAMS *Mid) { }
|
|
|
|
AGESA_STATUS __attribute__((weak))
|
|
fchs3earlyrestore(AMD_CONFIG_PARAMS *StdHeader)
|
|
{
|
|
return AGESA_SUCCESS;
|
|
}
|
|
|
|
AGESA_STATUS __attribute__((weak))
|
|
fchs3laterestore(AMD_CONFIG_PARAMS *StdHeader)
|
|
{
|
|
return AGESA_SUCCESS;
|
|
}
|