Ryzen/AmiChipsetModulePkg/Library/SbResetLib/SbResetLib.c

459 lines
12 KiB
C
Raw Permalink Normal View History

2022-12-22 23:14:44 -08:00
//***********************************************************************
//* *
//* Copyright (c) 1985-2020, American Megatrends International LLC. *
//* *
//* All rights reserved. Subject to AMI licensing agreement. *
//* *
//***********************************************************************
//*************************************************************************
/** @file SbResetLib.c
This file contains code for SbResetLib.c
in the DXE stage.
**/
//*************************************************************************
//---------------------------------------------------------------------------
// Include(s)
//---------------------------------------------------------------------------
// UDK Header
#include <PiDxe.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/PciLib.h>
#include <Library/S3PciLib.h>
#include <AmiChipsetIoLib.h>
#include <Library/RtcLib.h>
#include <Guid/Rtc.h> //### TBD
#include <Library/DebugLib.h>
#include <Token.h>
// AMI Compatibility Header.
#include <AmiCspLib.h> // Optional. should use Mde Library instead.
#include <AmiLib.h>
#include <SbElinks.h>
// Produced Protocols
// Consumed Protocols
//---------------------------------------------------------------------------
// Constant, Macro and Type Definition(s)
//---------------------------------------------------------------------------
// Constant Definition(s)
static BOOLEAN IsFchFullHardReset;
#if HW_REDUCE_ACDCTIMER_SUPPORT
static BOOLEAN IsHwReduceSystem;
#endif
// Macro Definition(s)
// Type Definition(s)
typedef VOID (SB_OEM_S3_WARMRESET_CALLBACK) (VOID);
// Function Prototype(s)
BOOLEAN
SbGetCapsuleFlag (
);
VOID ShutdownUsbLegacy(VOID);
//---------------------------------------------------------------------------
// Variable and External Declaration(s)
//---------------------------------------------------------------------------
// Variable Declaration(s)
// GUID Definition(s)
// Protocol Definition(s)
// External Declaration(s)
extern SB_OEM_S3_WARMRESET_CALLBACK \
SB_OEM_S3_WARMRESET_CALLBACK_LIST EndOfList;
SB_OEM_S3_WARMRESET_CALLBACK* SbS3InsteadOfWarmResetCallBackList[] = \
{SB_OEM_S3_WARMRESET_CALLBACK_LIST NULL};
// Function Definition(s)
//---------------------------------------------------------------------------
/**
This function calls registered callbacks for S3 RTC/Timer
(WarmBoot) eLink.
@param VOID
@retval VOID
**/
VOID SBLib_S3InsteadOfWarmResetCallBack (VOID)
{
UINTN i;
for (i = 0; SbS3InsteadOfWarmResetCallBackList[i] != NULL; i++)
SbS3InsteadOfWarmResetCallBackList[i]();
}
/**
This function puts system into ACPI S3 State.
if token ENABLE_RTC_ONE_SECOND_WAKEUP = 1, then it setups RTC
1 second alarm as well.
@param VOID
@retval None system will enter ACPI S3 State.
**/
UINT32 gSbMMIOBASEADDR = SB_MMIO_BASE;
VOID SBLib_S3InsteadOfWarmReset (VOID)
{
UINT32 IoData;
UINT8 Hour, Minute, Second;
BOOLEAN inBCD = TRUE;
//flush caches befor going to S3
//#if (defined x64_BUILD && x64_BUILD == 1)
// flushcaches();
DisableCacheInCR0();
//#else
// _asm wbinvd
//#endif
// Read RTC Status Register 0xC
ReadRtcIndex(0xC);
// determine if RTC is in BCD mode
if( ReadRtcIndex(0xB) & 0x4 ) // bit 2
inBCD = FALSE;
// wait for time update to complete before reading the values
while( ReadRtcIndex(0xA) & 0x80 ); // while bit 7 is set the
// time update is in progress
//read current hour, minute, second
Hour = ReadRtcIndex(0x4);
Minute = ReadRtcIndex(0x2);
Second = ReadRtcIndex(0x0);
//convert second to decimal from BCD and increment by 1
if(inBCD)
BcdToDecimal8(Second);
Second += 3;
if(Second > 59){
Second -= 60;
if(inBCD)
Minute = (Minute >> 4) * 10 + (Minute & 0x0F);
Minute++;
if(Minute > 59){
Minute = 0;
if(inBCD)
Hour = (Hour >> 4) * 10 + (Hour & 0x0F);
Hour++;
// check 24 hour mode/12 hour mode
if( ReadRtcIndex(0xB) & 0x2 ) {// bit 1 1=24hour else 12 hour
if(Hour > 23)
Hour = 0;
} else {
if(Hour > 11)
Hour = 0;
}
if(inBCD)
Hour = Hour % 10 + ( (Hour / 10) << 4 ) ;
}
if(inBCD)
Minute = Minute % 10 + ( (Minute / 10) << 4 ) ;
}
//convert from decimal to BCD
if(inBCD)
DecimalToBcd8(Second);
//set the alarm
WriteRtcIndex(0x5, Hour);
WriteRtcIndex(0x3, Minute);
WriteRtcIndex(0x1, Second);
// don't alarm RTC Date.
WriteRtcIndex(0xD, ( ReadRtcIndex(0xD) & 0x80));
//enable the alarm
WriteRtcIndex(0xB, ( ReadRtcIndex(0xB) | ((UINT8)( 1 << 5 )) ));
// ========== PORTING REQUIRED ===========================================================
// Current implementation to simulate the Warm Reboot may not be sufficient on some platforms.
// S3 transition may require additional Chipset/Platform cooding.
// If needed add any necessary OEM hooks to be able to put the system into S3 at the end of this handler
//========================================================================================
//set RTC_EN bit in PM1_EN to wake up from the alarm
IoWrite16(PM_BASE_ADDRESS + 0x02, ( IoRead16(PM_BASE_ADDRESS + 0x02) | (1 << 10) ));
//modify power management control register to reflect S3
IoData = IoRead32(PM_BASE_ADDRESS + 0x04);
//following code is applicable to Intel PCH only.
IoData &= ~(0x1C00);
#ifndef AMD_PLATFROM_SUPPORT
//following code is applicable to Intel PCH only.
IoData |= 0x1400; //Suspend to RAM
IoWrite32(PM_BASE_ADDRESS + 0x04, IoData );
#else
*(volatile UINT8*)( gSbMMIOBASEADDR + 0x300+0xbe) |= BIT5; // Set SLP_TYPE to go to sleep ,not trigger smi
*(volatile UINT8*)( gSbMMIOBASEADDR + 0x300+0x0b) &= ~(BIT0 + BIT1);
*(volatile UINT8*)( gSbMMIOBASEADDR + 0x300+0x0b) |= BIT0;
*(volatile UINT8*)( gSbMMIOBASEADDR + 0x200+0xb0) &= ~(BIT2+BIT3);
#if HW_REDUCE_ACDCTIMER_SUPPORT
if(IsHwReduceSystem){
*(volatile UINT32*)( gSbMMIOBASEADDR + 0x1D00+0x08) = 0x03; // clear AC timer status
*(volatile UINT32*)( gSbMMIOBASEADDR + 0x1D00+0x18) = 0x03; // clear DC timer status
*(volatile UINT32*)( gSbMMIOBASEADDR + 0x1D00+0x00) = 0x05; // Set 5 s for AC timer.
*(volatile UINT32*)( gSbMMIOBASEADDR + 0x1D00+0x04) = 0x05; // Set 5 s for DC timer.
*(volatile UINT32*)( gSbMMIOBASEADDR + 0x1D00+0x20) |= (BIT8+BIT9); // Enabled Timer to wake up system.
}
#endif
IoData |= 0x00C00; //Write sleep type to PM base, sleep action will be processed by AGESA FchSmmSxDispatcher.c
IoWrite32(PM_BASE_ADDRESS + 0x04, IoData );
// Do any specific porting if needed.
SBLib_S3InsteadOfWarmResetCallBack();
IoWrite8(0x80,0x75);
//EFI_DEADLOOP(); //Go to AGESA FchSmmSxDispatcher.c
#endif
}
/**
@param VOID
@retval VOID
**/
VOID SB_CapsuleShutdown(VOID)
{
UINT16 Value16;
// clear the power button status
while (READ_MMIO8_SMI(FCH_SMI_REG84 + 2) & BIT03) {
RW_MMIO8_SMI(FCH_SMI_REG84 + 2, 0, BIT03);
}
WRITE_IO8_PMIO (FCH_PMIOA_REG5B, 0x02);
Value16 = IoRead16(PM_BASE_ADDRESS) | (UINT16)(1 << 8);
do {
IoWrite16(PM_BASE_ADDRESS, Value16);
for (Value16 = 0; Value16 < 0x100; Value16++)
IoWrite8(0xED, (UINT8)Value16);
Value16 = IoRead16(PM_BASE_ADDRESS);
} while (Value16 & 0x100);
Value16 = IoRead16(PM_BASE_ADDRESS+4) & ~(15 << 10);
//put to S5
IoWrite16(PM_BASE_ADDRESS + 4,(UINT16)(Value16 | (13 << 10)));
IoWrite8(0x80,0x05);
CpuDeadLoop (); //halt at this,never come here!
}
/**
do a warm reset
@param ResetType Reset Type
@retval EFI_SUCCESS Module initialized successfully
@retval EFI_ERROR Initialization failed (see error for more details)
**/
EFI_STATUS
EFIAPI
AmdWarmReset (
IN EFI_RESET_TYPE ResetType
)
{
EFI_STATUS Status = EFI_NOT_READY; // default is not entering capsule sleep.
BOOLEAN IsSbShutdownUsbLegacy = FixedPcdGetBool (SbShutdownUsbLegacyPolicy);
if(SbGetCapsuleFlag()) {
if (ResetType == EfiResetWarm) {
if ( IsSbShutdownUsbLegacy ){
// Shutdown Smm usb legacy
ShutdownUsbLegacy();
}
#if defined(CAPSULE_RESET_MODE) && CAPSULE_RESET_MODE == 1
WRITE_IO8(RESET_PORT, (SB_RST_CPU + SB_COLD_RESET));
EFI_DEADLOOP();
#else
SBLib_S3InsteadOfWarmReset();
#endif
} else if (ResetType == EfiResetShutdown) {
SB_CapsuleShutdown();
}
Status = EFI_SUCCESS; // Ready to do capsule sleep.
}
return Status;
}
/**
This function proccessed for trap S5 sleep to S3 for windows firmware update
@param VOID
@retval VOID
**/
VOID SbWindowsFirmwareUpdatePutS5InsteadReset(
IN EFI_RESET_TYPE ResetType
)
{
#if defined(CAPSULE_RESET_MODE) && CAPSULE_RESET_MODE == 0
UINT32 IoData;
if(SbGetCapsuleFlag()) {
// Go to S5 for OS FW update process
if (ResetType == EfiResetWarm) {
DEBUG ((DEBUG_INFO, "SbWindowsFirmwareUpdatePutS5InsteadReset put S5 trap for Capsule\n"));
IoData = IoRead32(PM_BASE_ADDRESS + 0x04);
IoData &= ~(0x1C00);
IoData |= 0x3400; //Write sleep type to PM base, S5 trap
IoWrite32(PM_BASE_ADDRESS + 0x04, IoData );
IoWrite8(0x80,0x53);// need nerver go to here.
EFI_DEADLOOP();
}
}
#endif
}
/**
SbRuntimeResetAmdWarmReset
@param ResetType Type of reset to perform
@param ResetStatus System status that caused the reset. if part
of normal operation then this should be
EFI_SUCCESS, Otherwise it should reflect the
state of the system that caused it
@param DataSize Size in bytes of the data to be logged
@param ResetData OPTIONAL Pointer to the data buffer that is to be logged
@retval VOID
**/
VOID
SbRuntimeResetAmdWarmReset (
IN EFI_RESET_TYPE ResetType,
IN EFI_STATUS ResetStatus,
IN UINTN DataSize,
IN VOID *ResetData OPTIONAL
)
{
EFI_STATUS Status = EFI_SUCCESS;
SbWindowsFirmwareUpdatePutS5InsteadReset(ResetType);
Status = AmdWarmReset(ResetType);
}
/**
This function saves the input ResetType in "ResetType"
variable
@param gRT efi runtime service.
@param ResetType Type of reset to be generated
@retval EFI_SUCCESS Module initialized successfully
@retval EFI_ERROR Initialization failed (see error for more details)
**/
EFI_STATUS SetResetType(
IN EFI_RUNTIME_SERVICES *gRT,
IN EFI_RESET_TYPE ResetType
)
{
EFI_STATUS Status = EFI_SUCCESS;
UINTN DataSize = sizeof(UINT32);
EFI_GUID VariableGuid = AMI_CSP_RESET_GUID;
UINT32 CurrentResetType = SoftReset;
// <AAV> use PCD instead.
Status = gRT->GetVariable(
L"CspResetType",
&VariableGuid,
NULL,
&DataSize,
&CurrentResetType);
if (!EFI_ERROR(Status))
{
if (CurrentResetType >= (UINT32)ResetType)
return EFI_SUCCESS;
}
CurrentResetType = ResetType;
Status = gRT->SetVariable(
L"CspResetType",
&VariableGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
DataSize,
&CurrentResetType);
return Status;
}
/**
Get PcdFchFullHardReset PCD
@param None.
@retval Return PCD value.
**/
BOOLEAN EFIAPI GetFchFullHardReset()
{
return IsFchFullHardReset;
}
/**
Update FchFullHardReset PCD value
@param PCD value.
@retval none.
**/
VOID EFIAPI UpdateFchFullHardResetValue(BOOLEAN Value)
{
IsFchFullHardReset = Value;
}
#if HW_REDUCE_ACDCTIMER_SUPPORT
/**
Update FchFullHardReset PCD value
@param PCD value.
@retval none.
**/
VOID EFIAPI UpdateHwReduceValue(BOOLEAN Value)
{
IsHwReduceSystem = Value;
}
#endif