| /* 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 <amdblocks/ioapic.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 = GNB_IOAPIC_ID; |
| LateParams->GnbLateConfiguration.FchIoapicId = FCH_IOAPIC_ID; |
| } |
| |
| 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; |
| } |