/** @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; }