blob: ff52fbd8c896355b1e7820d0f4a7f23045781c3a [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
#include <acpi/acpi.h>
#include <console/console.h>
#include <timestamp.h>
#include <amdblocks/biosram.h>
#include <amdblocks/s3_resume.h>
#include <amdblocks/agesawrapper.h>
#include <amdblocks/BiosCallOuts.h>
#include <soc/pci_devs.h>
#include <soc/northbridge.h>
#include <soc/cpu.h>
void __weak SetMemParams(AMD_POST_PARAMS *PostParams) {}
void __weak OemPostParams(AMD_POST_PARAMS *PostParams) {}
/* ACPI table pointers returned by AmdInitLate */
static void *DmiTable;
static void *AcpiPstate;
static void *AcpiSrat;
static void *AcpiSlit;
static void *AcpiWheaMce;
static void *AcpiWheaCmc;
static void *AcpiAlib;
static void *AcpiIvrs;
static void *AcpiCrat;
static AGESA_STATUS module_dispatch(AGESA_STRUCT_NAME func,
AMD_CONFIG_PARAMS *StdHeader)
{
MODULE_ENTRY dispatcher = agesa_get_dispatcher();
if (!dispatcher)
return AGESA_UNSUPPORTED;
StdHeader->Func = func;
return dispatcher(StdHeader);
}
static AGESA_STATUS amd_dispatch(void *Params)
{
AMD_CONFIG_PARAMS *StdHeader = Params;
return module_dispatch(StdHeader->Func, StdHeader);
}
AGESA_STATUS amd_late_run_ap_task(AP_EXE_PARAMS *ApExeParams)
{
AMD_CONFIG_PARAMS *StdHeader = (void *)ApExeParams;
return module_dispatch(AMD_LATE_RUN_AP_TASK, StdHeader);
}
static AGESA_STATUS amd_create_struct(AMD_INTERFACE_PARAMS *aip,
AGESA_STRUCT_NAME func, void *buf, size_t len)
{
AGESA_STATUS status;
/* Should clone entire StdHeader here. */
memset(aip, 0, sizeof(*aip));
aip->StdHeader.CalloutPtr = &GetBiosCallout;
/* If we provide the buffer, API expects it to have
StdHeader already filled. */
if (buf != NULL && len >= sizeof(aip->StdHeader)) {
memcpy(buf, &aip->StdHeader, sizeof(aip->StdHeader));
aip->AllocationMethod = ByHost;
aip->NewStructPtr = buf;
aip->NewStructSize = len;
} else {
if (ENV_ROMSTAGE)
aip->AllocationMethod = PreMemHeap;
if (ENV_RAMSTAGE)
aip->AllocationMethod = PostMemDram;
}
aip->AgesaFunctionName = func;
status = module_dispatch(AMD_CREATE_STRUCT, &aip->StdHeader);
if (status != AGESA_SUCCESS) {
printk(BIOS_ERR, "Error: AmdCreateStruct() for 0x%x returned 0x%x. "
"Proper system initialization may not be possible.\n",
aip->AgesaFunctionName, status);
}
if (!aip->NewStructPtr)
die("No AGESA structure created");
return status;
}
static AGESA_STATUS amd_release_struct(AMD_INTERFACE_PARAMS *aip)
{
return module_dispatch(AMD_RELEASE_STRUCT, &aip->StdHeader);
}
static AGESA_STATUS amd_init_reset(AMD_RESET_PARAMS *ResetParams)
{
AGESA_STATUS status;
SetFchResetParams(&ResetParams->FchInterface);
timestamp_add_now(TS_AGESA_INIT_RESET_START);
status = amd_dispatch(ResetParams);
timestamp_add_now(TS_AGESA_INIT_RESET_DONE);
return status;
}
static AGESA_STATUS amd_init_early(AMD_EARLY_PARAMS *EarlyParams)
{
AGESA_STATUS status;
soc_customize_init_early(EarlyParams);
OemCustomizeInitEarly(EarlyParams);
timestamp_add_now(TS_AGESA_INIT_EARLY_START);
status = amd_dispatch(EarlyParams);
timestamp_add_now(TS_AGESA_INIT_EARLY_DONE);
return status;
}
static void print_init_post_settings(AMD_POST_PARAMS *parms)
{
u64 syslimit, bottomio, uma_size, uma_start;
const char *mode;
switch (parms->MemConfig.UmaMode) {
case UMA_AUTO:
mode = "UMA_AUTO";
break;
case UMA_SPECIFIED:
mode = "UMA_SPECIFIED";
break;
case UMA_NONE:
mode = "UMA_NONE";
break;
default:
mode = "unknown!";
break;
}
syslimit = (u64)(parms->MemConfig.SysLimit + 1) * 64 * KiB - 1;
bottomio = (u64)parms->MemConfig.BottomIo * 64 * KiB;
uma_size = (u64)parms->MemConfig.UmaSize * 64 * KiB;
uma_start = (u64)parms->MemConfig.UmaBase * 64 * KiB;
printk(BIOS_SPEW, "AGESA set: umamode %s\n", mode);
printk(BIOS_SPEW, " : syslimit 0x%llx, bottomio 0x%08llx\n",
syslimit, bottomio);
printk(BIOS_SPEW, " : uma size %lluMB, uma start 0x%08llx\n",
uma_size / MiB, uma_start);
}
static AGESA_STATUS amd_init_post(AMD_POST_PARAMS *PostParams)
{
AGESA_STATUS status;
PostParams->MemConfig.UmaMode = CONFIG(GFXUMA) ? UMA_AUTO : UMA_NONE;
PostParams->MemConfig.UmaSize = 0;
PostParams->MemConfig.BottomIo = (uint16_t)
(CONFIG_BOTTOMIO_POSITION >> 24);
SetMemParams(PostParams);
OemPostParams(PostParams);
printk(BIOS_SPEW, "DRAM clear on reset: %s\n",
(PostParams->MemConfig.EnableMemClr == FALSE) ? "Keep" :
(PostParams->MemConfig.EnableMemClr == TRUE) ? "Clear" :
"unknown"
);
timestamp_add_now(TS_AGESA_INIT_POST_START);
status = amd_dispatch(PostParams);
timestamp_add_now(TS_AGESA_INIT_POST_DONE);
/*
* AGESA passes back the base and size of UMA. This is the only
* opportunity to get and save these settings to be used in resource
* allocation. We also need to allocate the top of low memory.
* If UMA is below 4GiB, UMA base is the top of low memory, otherwise
* Sub4GCachetop is the top of low memory.
* With UMA_NONE we see UmaBase==0.
*/
uintptr_t top;
if (PostParams->MemConfig.UmaBase &&
(PostParams->MemConfig.UmaBase < ((4ull * GiB) >> 16)))
top = PostParams->MemConfig.UmaBase << 16;
else
top = PostParams->MemConfig.Sub4GCacheTop;
backup_top_of_low_cacheable(top);
save_uma_size(PostParams->MemConfig.UmaSize * 64 * KiB);
save_uma_base((u64)PostParams->MemConfig.UmaBase * 64 * KiB);
print_init_post_settings(PostParams);
return status;
}
static AGESA_STATUS amd_init_env(AMD_ENV_PARAMS *EnvParams)
{
AGESA_STATUS status;
SetFchEnvParams(&EnvParams->FchInterface);
SetNbEnvParams(&EnvParams->GnbEnvConfiguration);
timestamp_add_now(TS_AGESA_INIT_ENV_START);
status = amd_dispatch(EnvParams);
timestamp_add_now(TS_AGESA_INIT_ENV_DONE);
return status;
}
void *agesawrapper_getlateinitptr(int pick)
{
switch (pick) {
case PICK_DMI:
return DmiTable;
case PICK_PSTATE:
return AcpiPstate;
case PICK_SRAT:
return AcpiSrat;
case PICK_SLIT:
return AcpiSlit;
case PICK_WHEA_MCE:
return AcpiWheaMce;
case PICK_WHEA_CMC:
return AcpiWheaCmc;
case PICK_ALIB:
return AcpiAlib;
case PICK_IVRS:
return AcpiIvrs;
case PICK_CRAT:
return AcpiCrat;
default:
return NULL;
}
}
static AGESA_STATUS amd_init_mid(AMD_MID_PARAMS *MidParams)
{
AGESA_STATUS status;
/* Enable MMIO on AMD CPU Address Map Controller */
amd_initcpuio();
SetFchMidParams(&MidParams->FchInterface);
SetNbMidParams(&MidParams->GnbMidConfiguration);
timestamp_add_now(TS_AGESA_INIT_MID_START);
status = amd_dispatch(MidParams);
timestamp_add_now(TS_AGESA_INIT_MID_DONE);
return status;
}
static AGESA_STATUS amd_init_late(AMD_LATE_PARAMS *LateParams)
{
AGESA_STATUS Status;
const struct device *dev = pcidev_path_on_root(IOMMU_DEVFN);
if (dev && dev->enabled) {
LateParams->GnbLateConfiguration.GnbIoapicId = CONFIG_MAX_CPUS
+ 1;
LateParams->GnbLateConfiguration.FchIoapicId = CONFIG_MAX_CPUS;
}
timestamp_add_now(TS_AGESA_INIT_LATE_START);
Status = amd_dispatch(LateParams);
timestamp_add_now(TS_AGESA_INIT_LATE_DONE);
DmiTable = LateParams->DmiTable;
AcpiPstate = LateParams->AcpiPState;
AcpiWheaMce = LateParams->AcpiWheaMce;
AcpiWheaCmc = LateParams->AcpiWheaCmc;
AcpiAlib = LateParams->AcpiAlib;
AcpiIvrs = LateParams->AcpiIvrs;
AcpiCrat = LateParams->AcpiCrat;
printk(BIOS_DEBUG, "DmiTable:%p, AcpiPstatein: %p, AcpiSrat:%p,"
"AcpiSlit:%p, Mce:%p, Cmc:%p,"
"Alib:%p, AcpiIvrs:%p in %s\n",
DmiTable, AcpiPstate, AcpiSrat,
AcpiSlit, AcpiWheaMce, AcpiWheaCmc,
AcpiAlib, AcpiIvrs, __func__);
return Status;
}
static AGESA_STATUS amd_init_rtb(AMD_RTB_PARAMS *RtbParams)
{
AGESA_STATUS Status;
timestamp_add_now(TS_AGESA_INIT_RTB_START);
Status = amd_dispatch(RtbParams);
timestamp_add_now(TS_AGESA_INIT_RTB_DONE);
if (Status != AGESA_SUCCESS)
return Status;
if (OemS3Save(&RtbParams->S3DataBlock) != AGESA_SUCCESS)
printk(BIOS_ERR, "S3 data not saved, resuming impossible\n");
return Status;
}
static AGESA_STATUS amd_init_resume(AMD_RESUME_PARAMS *InitResumeParams)
{
AGESA_STATUS status;
OemInitResume(&InitResumeParams->S3DataBlock);
timestamp_add_now(TS_AGESA_INIT_RESUME_START);
status = amd_dispatch(InitResumeParams);
timestamp_add_now(TS_AGESA_INIT_RESUME_DONE);
return status;
}
static AGESA_STATUS amd_s3late_restore(AMD_S3LATE_PARAMS *S3LateParams)
{
AGESA_STATUS Status;
amd_initcpuio();
OemS3LateRestore(&S3LateParams->S3DataBlock);
timestamp_add_now(TS_AGESA_S3_LATE_START);
Status = amd_dispatch(S3LateParams);
timestamp_add_now(TS_AGESA_S3_LATE_DONE);
return Status;
}
static AGESA_STATUS amd_s3final_restore(AMD_S3FINAL_PARAMS *S3FinalParams)
{
AGESA_STATUS Status;
OemS3LateRestore(&S3FinalParams->S3DataBlock);
timestamp_add_now(TS_AGESA_S3_FINAL_START);
Status = amd_dispatch(S3FinalParams);
timestamp_add_now(TS_AGESA_S3_FINAL_DONE);
return Status;
}
static AGESA_STATUS romstage_dispatch(AMD_CONFIG_PARAMS *StdHeader)
{
void *Params = StdHeader;
switch (StdHeader->Func) {
case AMD_INIT_RESET:
return amd_init_reset(Params);
case AMD_INIT_EARLY:
return amd_init_early(Params);
case AMD_INIT_POST:
return amd_init_post(Params);
case AMD_INIT_RESUME:
return amd_init_resume(Params);
default:
return AGESA_UNSUPPORTED;
}
}
static AGESA_STATUS ramstage_dispatch(AMD_CONFIG_PARAMS *StdHeader)
{
void *Params = StdHeader;
switch (StdHeader->Func) {
case AMD_INIT_ENV:
return amd_init_env(Params);
case AMD_INIT_MID:
return amd_init_mid(Params);
case AMD_INIT_LATE:
return amd_init_late(Params);
case AMD_INIT_RTB:
return amd_init_rtb(Params);
case AMD_S3LATE_RESTORE:
return amd_s3late_restore(Params);
case AMD_S3FINAL_RESTORE:
return amd_s3final_restore(Params);
default:
return AGESA_UNSUPPORTED;
}
}
AGESA_STATUS agesa_execute_state(AGESA_STRUCT_NAME func)
{
AGESA_STATUS status = AGESA_UNSUPPORTED;
AMD_CONFIG_PARAMS template = {};
AMD_CONFIG_PARAMS *StdHeader = &template;
AMD_INTERFACE_PARAMS AmdParamStruct;
AMD_INTERFACE_PARAMS *aip = &AmdParamStruct;
union {
AMD_RESET_PARAMS ResetParams;
AMD_S3LATE_PARAMS S3LateParams;
AMD_S3FINAL_PARAMS S3FinalParams;
} sp;
if ((func == AMD_INIT_RESET) || (func == AMD_S3LATE_RESTORE) ||
(func == AMD_S3FINAL_RESTORE)) {
memset(&sp, 0, sizeof(sp));
amd_create_struct(aip, func, &sp, sizeof(sp));
} else {
amd_create_struct(aip, func, NULL, 0);
}
StdHeader = aip->NewStructPtr;
StdHeader->Func = func;
if (ENV_ROMSTAGE)
status = romstage_dispatch(StdHeader);
if (ENV_RAMSTAGE)
status = ramstage_dispatch(StdHeader);
amd_release_struct(aip);
return status;
}