+++ /dev/null
-/** @file\r
-\r
- Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>\r
- \r\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
- \r\r
-\r
-Module Name:\r
-\r
- Platform.c\r
-\r
-Abstract:\r
-\r
- This is a generic template for a child of the IchSmm driver.\r
-\r
-\r
---*/\r
-\r
-#include "SmmPlatform.h"\r
-#include <Protocol/CpuIo2.h>\r
-\r
-\r
-//\r
-// Local variables\r
-//\r
-typedef struct {\r
- UINT8 Device;\r
- UINT8 Function;\r
-} EFI_PCI_BUS_MASTER;\r
-\r
-EFI_PCI_BUS_MASTER mPciBm[] = {\r
- { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1 },\r
- { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_2 },\r
- { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_3 },\r
- { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_4 },\r
- { PCI_DEVICE_NUMBER_PCH_USB, PCI_FUNCTION_NUMBER_PCH_EHCI }\r
-};\r
-\r
-\r
-UINT16 mAcpiBaseAddr;\r
-SYSTEM_CONFIGURATION mSystemConfiguration;\r
-EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;\r
-EFI_GLOBAL_NVS_AREA_PROTOCOL *mGlobalNvsAreaPtr;\r
-\r
-UINT16 mPM1_SaveState16;\r
-UINT32 mGPE_SaveState32;\r
-\r
-BOOLEAN mSetSmmVariableProtocolSmiAllowed = TRUE;\r
-\r
-\r
-//\r
-// Variables. Need to initialize this from Setup\r
-//\r
-BOOLEAN mWakeOnLanS5Variable;\r
-BOOLEAN mWakeOnRtcVariable;\r
-UINT8 mWakeupDay;\r
-UINT8 mWakeupHour;\r
-UINT8 mWakeupMinute;\r
-UINT8 mWakeupSecond;\r
-\r
-//\r
-// Use an enum. 0 is Stay Off, 1 is Last State, 2 is Stay On\r
-//\r
-UINT8 mAcLossVariable;\r
-\r
-\r
-static\r
-UINT8 mTco1Sources[] = {\r
- IchnNmi\r
-};\r
-\r
-UINTN\r
-DevicePathSize (\r
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
- );\r
-\r
-VOID\r
-S4S5ProgClock();\r
-\r
-EFI_STATUS\r
-InitRuntimeScriptTable (\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- );\r
-\r
-VOID\r
-S5SleepWakeOnRtcCallBack (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext\r
- );\r
-\r
-\r
-VOID\r
-EnableS5WakeOnRtc();\r
-\r
-UINT8\r
-HexToBcd(\r
- UINT8 HexValue\r
- );\r
-\r
-UINT8\r
-BcdToHex(\r
- IN UINT8 BcdValue\r
- );\r
-\r
-\r
-VOID\r
-CpuSmmSxWorkAround(\r
- );\r
-\r
-/**\r
- Initializes the SMM Handler Driver\r
-\r
- @param ImageHandle\r
- @param SystemTable\r
-\r
- @retval None\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InitializePlatformSmm (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_SYSTEM_TABLE *SystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 Index;\r
- EFI_HANDLE Handle;\r
- EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT PowerButtonContext;\r
- EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL *PowerButtonDispatch;\r
- EFI_SMM_ICHN_DISPATCH_CONTEXT IchnContext;\r
- EFI_SMM_ICHN_DISPATCH_PROTOCOL *IchnDispatch;\r
- EFI_SMM_SX_DISPATCH_PROTOCOL *SxDispatch;\r
- EFI_SMM_SX_DISPATCH_CONTEXT EntryDispatchContext;\r
- EFI_SMM_SW_DISPATCH_PROTOCOL *SwDispatch;\r
- EFI_SMM_SW_DISPATCH_CONTEXT SwContext;\r
- UINTN VarSize;\r
- EFI_BOOT_MODE BootMode;\r
-\r
- Handle = NULL;\r
-\r
- //\r
- // Locate the Global NVS Protocol.\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiGlobalNvsAreaProtocolGuid,\r
- NULL,\r
- (void **)&mGlobalNvsAreaPtr\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
-\r
- //\r
- // Get the ACPI Base Address\r
- //\r
-\r
- mAcpiBaseAddr = PchLpcPciCfg16( R_PCH_LPC_ACPI_BASE ) & B_PCH_LPC_ACPI_BASE_BAR;\r
-\r
- VarSize = sizeof(SYSTEM_CONFIGURATION);\r
- Status = SystemTable->RuntimeServices->GetVariable(\r
- L"Setup",\r
- &gEfiSetupVariableGuid,\r
- NULL,\r
- &VarSize,\r
- &mSystemConfiguration\r
- );\r
- if (EFI_ERROR (Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {\r
- //The setup variable is corrupted\r
- VarSize = sizeof(SYSTEM_CONFIGURATION);\r
- Status = SystemTable->RuntimeServices->GetVariable(\r
- L"SetupRecovery",\r
- &gEfiSetupVariableGuid,\r
- NULL,\r
- &VarSize,\r
- &mSystemConfiguration\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- } \r
- if (!EFI_ERROR(Status)) {\r
- mAcLossVariable = mSystemConfiguration.StateAfterG3;\r
-\r
- //\r
- // If LAN is disabled, WOL function should be disabled too.\r
- //\r
- if (mSystemConfiguration.Lan == 0x01){\r
- mWakeOnLanS5Variable = mSystemConfiguration.WakeOnLanS5;\r
- } else {\r
- mWakeOnLanS5Variable = FALSE;\r
- }\r
-\r
- mWakeOnRtcVariable = mSystemConfiguration.WakeOnRtcS5;\r
- }\r
-\r
- BootMode = GetBootModeHob ();\r
-\r
- //\r
- // Get the Power Button protocol\r
- //\r
- Status = gBS->LocateProtocol(\r
- &gEfiSmmPowerButtonDispatchProtocolGuid,\r
- NULL,\r
- (void **)&PowerButtonDispatch\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- if (BootMode != BOOT_ON_FLASH_UPDATE) {\r
- //\r
- // Register for the power button event\r
- //\r
- PowerButtonContext.Phase = PowerButtonEntry;\r
- Status = PowerButtonDispatch->Register(\r
- PowerButtonDispatch,\r
- PowerButtonCallback,\r
- &PowerButtonContext,\r
- &Handle\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
- }\r
- //\r
- // Get the Sx dispatch protocol\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiSmmSxDispatchProtocolGuid,\r
- NULL,\r
- (void **)&SxDispatch\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- //\r
- // Register entry phase call back function\r
- //\r
- EntryDispatchContext.Type = SxS3;\r
- EntryDispatchContext.Phase = SxEntry;\r
-\r
- Status = SxDispatch->Register (\r
- SxDispatch,\r
- (EFI_SMM_SX_DISPATCH)SxSleepEntryCallBack,\r
- &EntryDispatchContext,\r
- &Handle\r
- );\r
-\r
-\r
- EntryDispatchContext.Type = SxS4;\r
-\r
- Status = SxDispatch->Register (\r
- SxDispatch,\r
- S4S5CallBack,\r
- &EntryDispatchContext,\r
- &Handle\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
-\r
- EntryDispatchContext.Type = SxS5;\r
-\r
- Status = SxDispatch->Register (\r
- SxDispatch,\r
- S4S5CallBack,\r
- &EntryDispatchContext,\r
- &Handle\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- Status = SxDispatch->Register (\r
- SxDispatch,\r
- S5SleepAcLossCallBack,\r
- &EntryDispatchContext,\r
- &Handle\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- //\r
- // Get the Sw dispatch protocol\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiSmmSwDispatchProtocolGuid,\r
- NULL,\r
- (void **)&SwDispatch\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- //\r
- // Register ACPI enable handler\r
- //\r
- SwContext.SwSmiInputValue = ACPI_ENABLE;\r
- Status = SwDispatch->Register (\r
- SwDispatch,\r
- EnableAcpiCallback,\r
- &SwContext,\r
- &Handle\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- //\r
- // Register ACPI disable handler\r
- //\r
- SwContext.SwSmiInputValue = ACPI_DISABLE;\r
- Status = SwDispatch->Register (\r
- SwDispatch,\r
- DisableAcpiCallback,\r
- &SwContext,\r
- &Handle\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
-\r
- //\r
- // Register for SmmReadyToBootCallback\r
- //\r
- SwContext.SwSmiInputValue = SMI_SET_SMMVARIABLE_PROTOCOL;\r
- Status = SwDispatch->Register(\r
- SwDispatch,\r
- SmmReadyToBootCallback,\r
- &SwContext,\r
- &Handle\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- //\r
- // Get the ICHn protocol\r
- //\r
- Status = gBS->LocateProtocol(\r
- &gEfiSmmIchnDispatchProtocolGuid,\r
- NULL,\r
- (void **)&IchnDispatch\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- //\r
- // Register for the events that may happen that we do not care.\r
- // This is true for SMI related to TCO since TCO is enabled by BIOS WP\r
- //\r
- for (Index = 0; Index < sizeof(mTco1Sources)/sizeof(UINT8); Index++) {\r
- IchnContext.Type = mTco1Sources[Index];\r
- Status = IchnDispatch->Register(\r
- IchnDispatch,\r
- (EFI_SMM_ICHN_DISPATCH)DummyTco1Callback,\r
- &IchnContext,\r
- &Handle\r
- );\r
- ASSERT_EFI_ERROR( Status );\r
- }\r
-\r
- //\r
- // Lock TCO_EN bit.\r
- //\r
- IoWrite16( mAcpiBaseAddr + R_PCH_TCO_CNT, IoRead16( mAcpiBaseAddr + R_PCH_TCO_CNT ) | B_PCH_TCO_CNT_LOCK );\r
-\r
- //\r
- // Set to power on from G3 dependent on WOL instead of AC Loss variable in order to support WOL from G3 feature.\r
- //\r
- //\r
- // Set wake from G3 dependent on AC Loss variable and Wake On LAN variable.\r
- // This is because no matter how, if WOL enabled or AC Loss variable not disabled, the board needs to wake from G3 to program the LAN WOL settings.\r
- // This needs to be done after LAN enable/disable so that the PWR_FLR state clear not impacted the WOL from G3 feature.\r
- //\r
- if (mAcLossVariable != 0x00) {\r
- SetAfterG3On (TRUE);\r
- } else {\r
- SetAfterG3On (FALSE);\r
- }\r
-\r
-\r
-\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-VOID\r
-EFIAPI\r
-SmmReadyToBootCallback (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- if (mSetSmmVariableProtocolSmiAllowed)\r
- {\r
- //\r
- // It is okay to use gBS->LocateProtocol here because\r
- // we are still in trusted execution.\r
- //\r
- Status = gBS->LocateProtocol(\r
- &gEfiSmmVariableProtocolGuid,\r
- NULL,\r
- (void **)&mSmmVariable\r
- );\r
-\r
- ASSERT_EFI_ERROR(Status);\r
-\r
- //\r
- // mSetSmmVariableProtocolSmiAllowed will prevent this function from\r
- // being executed more than 1 time.\r
- //\r
- mSetSmmVariableProtocolSmiAllowed = FALSE;\r
- }\r
-\r
-}\r
-\r
-/**\r
-\r
- @param DispatchHandle The handle of this callback, obtained when registering\r
- @param DispatchContext The predefined context which contained sleep type and phase\r
-\r
-\r
- @retval EFI_SUCCESS Operation successfully performed\r
-\r
-**/\r
-EFI_STATUS\r
-EFIAPI \r
-SxSleepEntryCallBack (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- Status = SaveRuntimeScriptTable ();\r
- if (EFI_ERROR(Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Workaround for S3 wake hang if C State is enabled\r
- //\r
- CpuSmmSxWorkAround();\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-VOID\r
-CpuSmmSxWorkAround(\r
- )\r
-{\r
- UINT64 MsrValue;\r
-\r
- MsrValue = AsmReadMsr64 (0xE2);\r
-\r
- if (MsrValue & BIT15) {\r
- return;\r
- }\r
-\r
- if (MsrValue & BIT10) {\r
- MsrValue &= ~BIT10;\r
- AsmWriteMsr64 (0xE2, MsrValue);\r
- }\r
-}\r
-\r
-VOID\r
-ClearP2PBusMaster(\r
- )\r
-{\r
- UINT8 Command;\r
- UINT8 Index;\r
-\r
- for (Index = 0; Index < sizeof(mPciBm)/sizeof(EFI_PCI_BUS_MASTER); Index++) {\r
- Command = MmioRead8 (\r
- MmPciAddress (0,\r
- DEFAULT_PCI_BUS_NUMBER_PCH,\r
- mPciBm[Index].Device,\r
- mPciBm[Index].Function,\r
- PCI_COMMAND_OFFSET\r
- )\r
- );\r
- Command &= ~EFI_PCI_COMMAND_BUS_MASTER;\r
- MmioWrite8 (\r
- MmPciAddress (0,\r
- DEFAULT_PCI_BUS_NUMBER_PCH,\r
- mPciBm[Index].Device,\r
- mPciBm[Index].Function,\r
- PCI_COMMAND_OFFSET\r
- ),\r
- Command\r
- );\r
- }\r
-}\r
-\r
-/**\r
-\r
- Set the AC Loss to turn on or off.\r
-\r
-**/\r
-VOID\r
-SetAfterG3On (\r
- BOOLEAN Enable\r
- )\r
-{\r
- UINT8 PmCon1;\r
-\r
- //\r
- // ICH handling portion\r
- //\r
- PmCon1 = MmioRead8 ( PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1 );\r
- PmCon1 &= ~B_PCH_PMC_GEN_PMCON_AFTERG3_EN;\r
- if (Enable) {\r
- PmCon1 |= B_PCH_PMC_GEN_PMCON_AFTERG3_EN;\r
- }\r
- MmioWrite8 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1, PmCon1);\r
-\r
-}\r
-\r
-/**\r
- When a power button event happens, it shuts off the machine\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-PowerButtonCallback (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT *DispatchContext\r
- )\r
-{\r
- //\r
- // Check what the state to return to after AC Loss. If Last State, then\r
- // set it to Off.\r
- //\r
- UINT16 data16;\r
-\r
- if (mWakeOnRtcVariable) {\r
- EnableS5WakeOnRtc();\r
- }\r
-\r
- if (mAcLossVariable == 1) {\r
- SetAfterG3On (TRUE);\r
- }\r
-\r
- ClearP2PBusMaster();\r
-\r
- //\r
- // Program clock chip\r
- //\r
- S4S5ProgClock();\r
-\r
-\r
- data16 = (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN));\r
- data16 &= B_PCH_ACPI_GPE0a_EN_PCI_EXP;\r
-\r
-\r
- //\r
- // Clear Sleep SMI Status\r
- //\r
- IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_STS,\r
- (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_STS) | B_PCH_SMI_STS_ON_SLP_EN));\r
- //\r
- // Clear Sleep Type Enable\r
- //\r
- IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_EN,\r
- (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_EN) & (~B_PCH_SMI_EN_ON_SLP_EN)));\r
-\r
- //\r
- // Clear Power Button Status\r
- //\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_PWRBTN);\r
-\r
- //\r
- // Shut it off now!\r
- //\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, V_PCH_ACPI_PM1_CNT_S5);\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, B_PCH_ACPI_PM1_CNT_SLP_EN | V_PCH_ACPI_PM1_CNT_S5);\r
-\r
- //\r
- // Should not return\r
- //\r
- CpuDeadLoop();\r
-}\r
-\r
-\r
-/**\r
- @param DispatchHandle - The handle of this callback, obtained when registering\r
-\r
- @param DispatchContext - The predefined context which contained sleep type and phase\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-S5SleepAcLossCallBack (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext\r
- )\r
-{\r
- //\r
- // Check what the state to return to after AC Loss. If Last State, then\r
- // set it to Off.\r
- //\r
- if (mAcLossVariable == 1) {\r
- SetAfterG3On (TRUE);\r
- }\r
-}\r
-\r
-/**\r
-\r
- @param DispatchHandle The handle of this callback, obtained when registering\r
- @param DispatchContext The predefined context which contained sleep type and phase\r
-\r
- @retval Clears the Save State bit in the clock.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-S4S5CallBack (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext\r
- )\r
-{\r
-\r
- UINT32 Data32;\r
-\r
- //\r
- // Enable/Disable USB Charging\r
- //\r
- if (mSystemConfiguration.UsbCharging == 0x01) {\r
- Data32 = IoRead32 (GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL);\r
- Data32 |= BIT8;\r
- IoWrite32(GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL, Data32);\r
- }\r
-\r
-}\r
-\r
-\r
-VOID\r
-S4S5ProgClock()\r
-{\r
-}\r
-\r
-/**\r
- SMI handler to enable ACPI mode\r
-\r
- Dispatched on reads from APM port with value 0xA0\r
-\r
- Disables the SW SMI Timer.\r
- ACPI events are disabled and ACPI event status is cleared.\r
- SCI mode is then enabled.\r
-\r
- Disable SW SMI Timer\r
-\r
- Clear all ACPI event status and disable all ACPI events\r
- Disable PM sources except power button\r
- Clear status bits\r
-\r
- Disable GPE0 sources\r
- Clear status bits\r
-\r
- Disable GPE1 sources\r
- Clear status bits\r
-\r
- Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")\r
-\r
- Enable SCI\r
-\r
- @param DispatchHandle - EFI Handle\r
- @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT\r
-\r
- @retval Nothing\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-EnableAcpiCallback (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext\r
- )\r
-{\r
- UINT32 SmiEn;\r
- UINT16 Pm1Cnt;\r
- UINT16 wordValue;\r
- UINT32 RegData32;\r
-\r
- //\r
- // Disable SW SMI Timer\r
- //\r
- SmiEn = IoRead32(mAcpiBaseAddr + R_PCH_SMI_EN);\r
- SmiEn &= ~B_PCH_SMI_STS_SWSMI_TMR;\r
- IoWrite32(mAcpiBaseAddr + R_PCH_SMI_EN, SmiEn);\r
-\r
- wordValue = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS);\r
- if(wordValue & B_PCH_ACPI_PM1_STS_WAK) {\r
- IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN), 0x0000);\r
- IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS), 0xffffffff);\r
- }\r
- else {\r
- mPM1_SaveState16 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN);\r
-\r
- //\r
- // Disable PM sources except power button\r
- //\r
- // power button is enabled only for PCAT. Disabled it on Tablet platform\r
- //\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, B_PCH_ACPI_PM1_EN_PWRBTN);\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);\r
-\r
- mGPE_SaveState32 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN);\r
- IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, 0x0000);\r
- IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff);\r
-\r
- }\r
-\r
- //\r
- // Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")\r
- // Clear Status D reg VM bit, Date of month Alarm to make Data in CMOS RAM is no longer Valid\r
- //\r
- IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D);\r
- IoWrite8 (PCAT_RTC_DATA_REGISTER, 0x0);\r
-\r
-\r
- RegData32 = IoRead32(ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN);\r
- RegData32 &= ~(BIT7);\r
- IoWrite32((ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN), RegData32);\r
-\r
-\r
- //\r
- // Enable SCI\r
- //\r
- Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT);\r
- Pm1Cnt |= B_PCH_ACPI_PM1_CNT_SCI_EN;\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt);\r
-\r
-\r
-}\r
-\r
-/**\r
- SMI handler to disable ACPI mode\r
-\r
- Dispatched on reads from APM port with value 0xA1\r
-\r
- ACPI events are disabled and ACPI event status is cleared.\r
- SCI mode is then disabled.\r
- Clear all ACPI event status and disable all ACPI events\r
- Disable PM sources except power button\r
- Clear status bits\r
- Disable GPE0 sources\r
- Clear status bits\r
- Disable GPE1 sources\r
- Clear status bits\r
- Disable SCI\r
-\r
- @param DispatchHandle - EFI Handle\r
- @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT\r
-\r
- @retval Nothing\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-DisableAcpiCallback (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext\r
- )\r
-{\r
- UINT16 Pm1Cnt;\r
-\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, mPM1_SaveState16);\r
-\r
- IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff);\r
- IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, mGPE_SaveState32);\r
-\r
- //\r
- // Disable SCI\r
- //\r
- Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT);\r
- Pm1Cnt &= ~B_PCH_ACPI_PM1_CNT_SCI_EN;\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt);\r
-\r
-}\r
-\r
-/**\r
- When an unknown event happen.\r
-\r
- @retval None\r
-\r
-**/\r
-VOID\r
-DummyTco1Callback (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext\r
- )\r
-{\r
-}\r
-\r
-UINTN\r
-DevicePathSize (\r
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
- )\r
-{\r
- EFI_DEVICE_PATH_PROTOCOL *Start;\r
-\r
- if (DevicePath == NULL) {\r
- return 0;\r
- }\r
-\r
- //\r
- // Search for the end of the device path structure\r
- //\r
- Start = DevicePath;\r
- while (!IsDevicePathEnd (DevicePath)) {\r
- DevicePath = NextDevicePathNode (DevicePath);\r
- }\r
-\r
- //\r
- // Compute the size and add back in the size of the end device path structure\r
- //\r
- return ((UINTN)DevicePath - (UINTN)Start) + sizeof(EFI_DEVICE_PATH_PROTOCOL);\r
-}\r
-\r
-/**\r
-\r
- @param DispatchHandle The handle of this callback, obtained when registering\r
- @param DispatchContext The predefined context which contained sleep type and phase\r
-\r
-**/\r
-VOID\r
-S5SleepWakeOnRtcCallBack (\r
- IN EFI_HANDLE DispatchHandle,\r
- IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext\r
- )\r
-{\r
- EnableS5WakeOnRtc();\r
-}\r
-\r
-/**\r
-\r
- @retval 1. Check Alarm interrupt is not set.\r
- 2. Clear Alarm interrupt.\r
- 2. Set RTC wake up date and time.\r
- 2. Enable RTC wake up alarm.\r
- 3. Enable ICH PM1 EN Bit 10(RTC_EN)\r
-\r
-**/\r
-VOID\r
-EnableS5WakeOnRtc()\r
-{\r
- UINT8 CmosData;\r
- UINTN i;\r
- EFI_STATUS Status;\r
- UINTN VarSize;\r
-\r
- //\r
- // make sure EFI_SMM_VARIABLE_PROTOCOL is available\r
- //\r
- if (!mSmmVariable) {\r
- return;\r
- }\r
-\r
- VarSize = sizeof(SYSTEM_CONFIGURATION);\r
-\r
- //\r
- // read the variable into the buffer\r
- //\r
- Status = mSmmVariable->SmmGetVariable(\r
- L"Setup",\r
- &gEfiSetupVariableGuid,\r
- NULL,\r
- &VarSize,\r
- &mSystemConfiguration\r
- );\r
- if (EFI_ERROR(Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {\r
- //The setup variable is corrupted\r
- VarSize = sizeof(SYSTEM_CONFIGURATION);\r
- Status = mSmmVariable->SmmGetVariable(\r
- L"SetupRecovery",\r
- &gEfiSetupVariableGuid,\r
- NULL,\r
- &VarSize,\r
- &mSystemConfiguration\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
- }\r
-\r
- if (!mSystemConfiguration.WakeOnRtcS5) {\r
- return;\r
- }\r
- mWakeupDay = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupDate);\r
- mWakeupHour = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeHour);\r
- mWakeupMinute = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeMinute);\r
- mWakeupSecond = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeSecond);\r
-\r
- //\r
- // Check RTC alarm interrupt is enabled. If enabled, someone already\r
- // grabbed RTC alarm. Just return.\r
- //\r
- IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);\r
- if(IoRead8(PCAT_RTC_DATA_REGISTER) & B_RTC_ALARM_INT_ENABLE){\r
- return;\r
- }\r
-\r
- //\r
- // Set Date\r
- //\r
- IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D);\r
- CmosData = IoRead8(PCAT_RTC_DATA_REGISTER);\r
- CmosData &= ~(B_RTC_DATE_ALARM_MASK);\r
- CmosData |= mWakeupDay ;\r
- for(i = 0 ; i < 0xffff ; i++){\r
- IoWrite8(PCAT_RTC_DATA_REGISTER, CmosData);\r
- SmmStall(1);\r
- if(((CmosData = IoRead8(PCAT_RTC_DATA_REGISTER)) & B_RTC_DATE_ALARM_MASK)\r
- == mWakeupDay){\r
- break;\r
- }\r
- }\r
-\r
- //\r
- // Set Second\r
- //\r
- IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECOND_ALARM);\r
- for(i = 0 ; i < 0xffff ; i++){\r
- IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupSecond);\r
- SmmStall(1);\r
- if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupSecond){\r
- break;\r
- }\r
- }\r
-\r
- //\r
- // Set Minute\r
- //\r
- IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTE_ALARM);\r
- for(i = 0 ; i < 0xffff ; i++){\r
- IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupMinute);\r
- SmmStall(1);\r
- if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupMinute){\r
- break;\r
- }\r
- }\r
-\r
- //\r
- // Set Hour\r
- //\r
- IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOUR_ALARM);\r
- for(i = 0 ; i < 0xffff ; i++){\r
- IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupHour);\r
- SmmStall(1);\r
- if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupHour){\r
- break;\r
- }\r
- }\r
-\r
- //\r
- // Wait for UIP to arm RTC alarm\r
- //\r
- IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);\r
- while (IoRead8(PCAT_RTC_DATA_REGISTER) & 0x80);\r
-\r
- //\r
- // Read RTC register 0C to clear pending RTC interrupts\r
- //\r
- IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);\r
- IoRead8(PCAT_RTC_DATA_REGISTER);\r
-\r
- //\r
- // Enable RTC Alarm Interrupt\r
- //\r
- IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);\r
- IoWrite8(PCAT_RTC_DATA_REGISTER, IoRead8(PCAT_RTC_DATA_REGISTER) | B_RTC_ALARM_INT_ENABLE);\r
-\r
- //\r
- // Clear ICH RTC Status\r
- //\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_RTC);\r
-\r
- //\r
- // Enable ICH RTC event\r
- //\r
- IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN,\r
- (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN) | B_PCH_ACPI_PM1_EN_RTC));\r
-}\r
-\r
-UINT8\r
-HexToBcd(\r
- IN UINT8 HexValue\r
- )\r
-{\r
- UINTN HighByte;\r
- UINTN LowByte;\r
-\r
- HighByte = (UINTN)HexValue / 10;\r
- LowByte = (UINTN)HexValue % 10;\r
-\r
- return ((UINT8)(LowByte + (HighByte << 4)));\r
-}\r
-\r
-UINT8\r
-BcdToHex(\r
- IN UINT8 BcdValue\r
- )\r
-{\r
- UINTN HighByte;\r
- UINTN LowByte;\r
-\r
- HighByte = (UINTN)((BcdValue >> 4) * 10);\r
- LowByte = (UINTN)(BcdValue & 0x0F);\r
-\r
- return ((UINT8)(LowByte + HighByte));\r
-}\r
-\r