/** @file
The PEI Library Implements OcWdt Support.
Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
static WDT_PPI mWdtPpi = {
WdtReloadAndStart,
WdtCheckStatus,
WdtDisable,
WdtAllowKnownReset,
IsWdtRequired,
IsWdtEnabled
};
static EFI_PEI_PPI_DESCRIPTOR mInstallWdtPpi = {
(EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
&gWdtPpiGuid,
&mWdtPpi
};
/**
Reads PCH registers to check if platform wakes from S3/S4
@retval TRUE if platfrom wakes from S3/S4
@retval FALSE otherwise
**/
BOOLEAN
IsWakeFromS3S4 (
VOID
)
{
UINT16 ABase;
UINT16 SleepType;
PchAcpiBaseGet (&ABase);
if (IoRead16 (ABase + R_PCH_ACPI_PM1_STS) & B_PCH_ACPI_PM1_STS_WAK) {
SleepType = IoRead16 (ABase + R_PCH_ACPI_PM1_CNT) & B_PCH_ACPI_PM1_CNT_SLP_TYP;
if ((SleepType == V_PCH_ACPI_PM1_CNT_S3) || (SleepType == V_PCH_ACPI_PM1_CNT_S4)) {
return TRUE;
}
}
return FALSE;
}
/**
Check for unexpected reset.
If there was an unexpected reset, enforces WDT expiration.
**/
VOID
OcWdtResetCheck (
VOID
)
{
UINT32 Readback;
Readback = IoRead32 (WdtGetAddress ());
DEBUG ((DEBUG_ERROR, "(WDT) OcWdtResetCheck\n"));
///
/// If there was a WDT expiration, set Failure Status and clear timeout status bits
/// Timeout status bits are cleared by writing '1'
///
if (Readback & (B_PCH_OC_WDT_CTL_ICCSURV_STS | B_PCH_OC_WDT_CTL_NO_ICCSURV_STS)) {
DEBUG ((DEBUG_ERROR, "(WDT) Expiration detected.\n", Readback));
Readback |= B_PCH_OC_WDT_CTL_FAILURE_STS;
Readback |= (B_PCH_OC_WDT_CTL_ICCSURV_STS | B_PCH_OC_WDT_CTL_NO_ICCSURV_STS);
Readback &= ~(B_PCH_OC_WDT_CTL_UNXP_RESET_STS);
} else {
///
/// If there was unexpected reset but no WDT expiration and no resume from S3/S4,
/// clear unexpected reset status and enforce expiration. This is to inform Firmware
/// which has no access to unexpected reset status bit, that something went wrong.
///
if ((Readback & B_PCH_OC_WDT_CTL_UNXP_RESET_STS) && !IsWakeFromS3S4 ()) {
#ifndef MDEPKG_NDEBUG
DEBUG ((DEBUG_ERROR, "(WDT) Unexpected reset detected and ignored.\n"));
Readback &= ~(B_PCH_OC_WDT_CTL_FAILURE_STS | B_PCH_OC_WDT_CTL_UNXP_RESET_STS);
Readback |= (B_PCH_OC_WDT_CTL_ICCSURV_STS | B_PCH_OC_WDT_CTL_NO_ICCSURV_STS);
#else
DEBUG ((DEBUG_ERROR, "(WDT) Unexpected reset detected. Enforcing Wdt expiration.\n"));
WdtReloadAndStart (1);
///
/// wait for reboot caused by WDT expiration
///
CpuDeadLoop ();
#endif
} else {
///
/// No WDT expiration and no unexpected reset - clear Failure status
///
DEBUG ((DEBUG_INFO, "(WDT) Status OK.\n", Readback));
Readback &= ~(B_PCH_OC_WDT_CTL_FAILURE_STS);
Readback |= (B_PCH_OC_WDT_CTL_ICCSURV_STS | B_PCH_OC_WDT_CTL_NO_ICCSURV_STS);
}
}
IoWrite32 (WdtGetAddress (), Readback);
}
/**
This function install WDT PPI
@retval EFI_STATUS Results of the installation of the WDT PPI
**/
EFI_STATUS
EFIAPI
OcWdtInit (
VOID
)
{
EFI_STATUS Status;
Status = PeiServicesInstallPpi (&mInstallWdtPpi);
ASSERT_EFI_ERROR (Status);
return Status;
}