From 33eb86541d9305fd33140931c4c70bd064af3ec3 Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Fri, 23 Dec 2016 14:33:06 +0800 Subject: BroxtonPlatformPkg: Add PlatformSmm Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../Common/PlatformSmm/Platform.c | 1074 ++++++++++++++++++++ .../Common/PlatformSmm/PlatformSmm.inf | 95 ++ .../BroxtonPlatformPkg/Common/PlatformSmm/S3Save.c | 82 ++ .../Common/PlatformSmm/SmmPlatform.h | 223 ++++ 4 files changed, 1474 insertions(+) create mode 100644 Platform/BroxtonPlatformPkg/Common/PlatformSmm/Platform.c create mode 100644 Platform/BroxtonPlatformPkg/Common/PlatformSmm/PlatformSmm.inf create mode 100644 Platform/BroxtonPlatformPkg/Common/PlatformSmm/S3Save.c create mode 100644 Platform/BroxtonPlatformPkg/Common/PlatformSmm/SmmPlatform.h (limited to 'Platform/BroxtonPlatformPkg/Common/PlatformSmm') diff --git a/Platform/BroxtonPlatformPkg/Common/PlatformSmm/Platform.c b/Platform/BroxtonPlatformPkg/Common/PlatformSmm/Platform.c new file mode 100644 index 0000000000..673df3aedd --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/PlatformSmm/Platform.c @@ -0,0 +1,1074 @@ +/** @file + This is a generic template for a child of the IchSmm driver. + + Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SmmPlatform.h" +#include +#include +#define PROGRESS_CODE_S3_SUSPEND_START _gPcd_FixedAtBuild_PcdProgressCodeS3SuspendStart + +#define NMI_REG_OFFSET 0x3330 +#define NMI_NOW BIT0 +#define NMI2SMI_EN BIT2 + + +// +// Local variables +// +typedef struct { + UINT8 Device; + UINT8 Function; +} EFI_PCI_BUS_MASTER; + +EFI_PCI_BUS_MASTER mPciBm[] = { + { PCI_DEVICE_NUMBER_SC_PCIE_DEVICE_1, PCI_FUNCTION_NUMBER_PCIE_ROOT_PORT_1 }, +}; + + +BOARD_AA_NUMBER_DECODE DefectiveBoardIdTable [] = { + {"E76523", 302}, //BLKD510MO + {"E76525", 301}, //LAD510MO + {"E67982", 303} //LAD510MOV +}; +UINTN DefectiveBoardIdTableSize = sizeof (DefectiveBoardIdTable) / sizeof (BOARD_AA_NUMBER_DECODE); + +EFI_SMM_SYSTEM_TABLE2 *mSmst; +UINT16 mAcpiBaseAddr; +SYSTEM_CONFIGURATION mSystemConfiguration; +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable; +EFI_GLOBAL_NVS_AREA_PROTOCOL *mGlobalNvsAreaPtr; +BOOLEAN mSetSmmVariableProtocolSmiAllowed = TRUE; + +// +// Variables. Need to initialize this from Setup +// +BOOLEAN mWakeOnLanS5Variable; +BOOLEAN mWakeOnRtcVariable; +BOOLEAN mWakeOnLanVariable; +UINT8 mWakeupDay; +UINT8 mWakeupHour; +UINT8 mWakeupMinute; +UINT8 mWakeupSecond; +UINT8 mDeepStandby=0; + +// +// Use an enum. 0 is Stay Off, 1 is Last State, 2 is Stay On +// +UINT8 mAcLossVariable; + +static +UINT8 mTco1Sources[] = { + IchnNmi +}; + +UINTN +DevicePathSize ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +EFI_STATUS +S5SleepWakeOnRtcCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + + +VOID +EnableS5WakeOnRtc (); + +EFI_STATUS +Stall ( + IN UINTN Microseconds + ); + +UINT8 +HexToBcd( + UINT8 HexValue + ); + +UINT8 +BcdToHex( + IN UINT8 BcdValue + ); + +EFI_STATUS +EfiSmmGetTime ( + IN OUT EFI_TIME *Time + ); + +VOID +CpuSmmSxWorkAround( + ); + + +/** + Initializes the SMM Handler Driver + + @param[in] ImageHandle A handle for the image that is initializing this driver. + @param[in] SystemTable A pointer to the EFI system table. + + @retval None + +**/ +EFI_STATUS +InitializePlatformSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINT8 Index; + EFI_HANDLE Handle; + EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButtonContext; + EFI_SMM_ICHN_DISPATCH_CONTEXT IchnContext; + EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL *PowerButtonDispatch; + EFI_SMM_ICHN_DISPATCH_PROTOCOL *IchnDispatch; + EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch; + EFI_SMM_SX_REGISTER_CONTEXT EntryDispatchContext; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; + EFI_SMM_SW_REGISTER_CONTEXT SwContext; + UINTN VarSize; + EFI_BOOT_MODE BootMode; + Handle = NULL; + + // + // Locate the Global NVS Protocol. + // + Status = gBS->LocateProtocol ( + &gEfiGlobalNvsAreaProtocolGuid, + NULL, + (VOID **) &mGlobalNvsAreaPtr + ); + ASSERT_EFI_ERROR (Status); + + // + // Initialize global variables + // + mSmst = gSmst; + + // + // Get the ACPI Base Address + // + mAcpiBaseAddr = (UINT16) PcdGet16 (PcdScAcpiIoPortBaseAddress); + + VarSize = sizeof (SYSTEM_CONFIGURATION); + Status = gRT->GetVariable ( + L"Setup", + &gEfiSetupVariableGuid, + NULL, + &VarSize, + &mSystemConfiguration + ); + + if (!EFI_ERROR (Status)) { + mAcLossVariable = mSystemConfiguration.StateAfterG3; + mDeepStandby = mSystemConfiguration.DeepStandby; + + // + // If LAN is disabled, WOL function should be disabled too. + // + if (mSystemConfiguration.Lan == 0x01) { + mWakeOnLanS5Variable = mSystemConfiguration.WakeOnLanS5; + } else { + mWakeOnLanS5Variable = FALSE; + } + + mWakeOnLanVariable = mSystemConfiguration.Wol; + mWakeOnRtcVariable = mSystemConfiguration.WakeOnRtcS5; + } + + BootMode = GetBootModeHob (); + + // + // Get the Power Button protocol + // + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmPowerButtonDispatch2ProtocolGuid, + NULL, + (VOID **) &PowerButtonDispatch + ); + ASSERT_EFI_ERROR (Status); + + if (BootMode != BOOT_ON_FLASH_UPDATE) { + // + // Register for the power button event + // + PowerButtonContext.Phase = EfiPowerButtonEntry; + Status = PowerButtonDispatch->Register( + PowerButtonDispatch, + PowerButtonCallback, + &PowerButtonContext, + &Handle + ); + ASSERT_EFI_ERROR (Status); + } + + // + // Get the Sx dispatch protocol + // + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmSxDispatch2ProtocolGuid, + NULL, + (VOID **) &SxDispatch + ); + ASSERT_EFI_ERROR (Status); + + // + // Register entry phase call back function + // + EntryDispatchContext.Type = SxS3; + EntryDispatchContext.Phase = SxEntry; + + Status = SxDispatch->Register ( + SxDispatch, + SxSleepEntryCallBack, + &EntryDispatchContext, + &Handle + ); + + EntryDispatchContext.Type = SxS4; + + Status = SxDispatch->Register ( + SxDispatch, + S4S5CallBack, + &EntryDispatchContext, + &Handle + ); + ASSERT_EFI_ERROR (Status); + + EntryDispatchContext.Type = SxS5; + + Status = SxDispatch->Register ( + SxDispatch, + S4S5CallBack, + &EntryDispatchContext, + &Handle + ); + ASSERT_EFI_ERROR (Status); + + Status = SxDispatch->Register ( + SxDispatch, + S5SleepAcLossCallBack, + &EntryDispatchContext, + &Handle + ); + ASSERT_EFI_ERROR (Status); + + // + // Get the Sw dispatch protocol + // + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmSwDispatch2ProtocolGuid, + NULL, + (VOID **) &SwDispatch + ); + ASSERT_EFI_ERROR (Status); + + // + // Register ACPI enable handler + // + SwContext.SwSmiInputValue = ACPI_ENABLE; + Status = SwDispatch->Register ( + SwDispatch, + EnableAcpiCallback, + &SwContext, + &Handle + ); + ASSERT_EFI_ERROR (Status); + + // + // Register ACPI disable handler + // + SwContext.SwSmiInputValue = ACPI_DISABLE; + Status = SwDispatch->Register ( + SwDispatch, + DisableAcpiCallback, + &SwContext, + &Handle + ); + ASSERT_EFI_ERROR (Status); + + // + // Register the TPM PTS & SMBS Handler + // + SwContext.SwSmiInputValue = 0x5A; + + Status = SwDispatch->Register ( + SwDispatch, + TpmPtsSmbsCallback, + &SwContext, + &Handle + ); + + ASSERT_EFI_ERROR (Status); + + // + // Get the ICHn protocol + // + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmIchnDispatchProtocolGuid, + NULL, + (VOID **) &IchnDispatch + ); + ASSERT_EFI_ERROR (Status); + + // + // Register for the events that may happen that we do not care. + // This is true for SMI related to TCO since TCO is enabled by BIOS WP + // + for (Index = 0; Index < sizeof (mTco1Sources) / sizeof (UINT8); Index++) { + IchnContext.Type = mTco1Sources[Index]; + Status = IchnDispatch->Register( + IchnDispatch, + DummyTco1Callback, + &IchnContext, + &Handle + ); + ASSERT_EFI_ERROR (Status); + } + + // + // Lock TCO_EN bit. + // + IoWrite16 (mAcpiBaseAddr + R_TCO_CNT, IoRead16 (mAcpiBaseAddr + R_TCO_CNT) | B_TCO_CNT_LOCK); + + // + // Set to power on from G3 dependent on WOL instead of AC Loss variable in order to support WOL from G3 feature. + // + // + // Set wake from G3 dependent on AC Loss variable and Wake On LAN variable. + // 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. + // This needs to be done after LAN enable/disable so that the PWR_FLR state clear not impacted the WOL from G3 feature. + // + if (mAcLossVariable != 0x00) { + SetAfterG3On (TRUE); + } else { + SetAfterG3On (FALSE); + } + + return EFI_SUCCESS; +} + + +VOID +StallInternalFunction( + IN UINTN Microseconds + ) +{ + UINTN Ticks; + UINTN Counts; + UINT32 CurrentTick; + UINT32 OriginalTick; + UINT64 RemainingTick; + + OriginalTick = IoRead32 (mAcpiBaseAddr + R_ACPI_PM1_TMR); + + CurrentTick = OriginalTick; + + // + //The timer frequency is 3.579545 MHz, so 1 ms corresponds 3.58 clocks + // + Ticks = Microseconds * 358 / 100 + OriginalTick + 1; + Counts = Ticks / V_ACPI_PM1_TMR_MAX_VAL; //The loops needed by timer overflow + RemainingTick = Ticks % V_ACPI_PM1_TMR_MAX_VAL; //remaining clocks within one loop + + // + //not intend to use TMROF_STS bit of register PM1_STS, because this adds extra + //one I/O operation, and maybe generate SMI + // + + while (Counts != 0) { + CurrentTick = IoRead32 (mAcpiBaseAddr + R_ACPI_PM1_TMR); + if (CurrentTick <= OriginalTick) { + Counts --; + } + OriginalTick = CurrentTick; + } + + while ((RemainingTick > CurrentTick) && (OriginalTick <= CurrentTick) ) { + OriginalTick = CurrentTick; + CurrentTick = IoRead32(mAcpiBaseAddr + R_ACPI_PM1_TMR); + } +} + + +/** + Waits for at least the given number of microseconds. + + @param[in] Microseconds Desired length of time to wait + + @retval EFI_SUCCESS If the desired amount of time passed. + +**/ +EFI_STATUS +Stall ( + IN UINTN Microseconds + ) +{ + if (Microseconds == 0) { + return EFI_SUCCESS; + } + + StallInternalFunction (Microseconds); + + return EFI_SUCCESS; +} + + +EFI_STATUS +SmmReadyToBootCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + + if (mSetSmmVariableProtocolSmiAllowed) { + // + // It is okay to use gBS->LocateProtocol here because + // we are still in trusted execution. + // + Status = gSmst->SmmLocateProtocol( + &gEfiSmmVariableProtocolGuid, + NULL, + (VOID **) &mSmmVariable + ); + + ASSERT_EFI_ERROR (Status); + + // + // mSetSmmVariableProtocolSmiAllowed will prevent this function from + // being executed more than 1 time. + // + mSetSmmVariableProtocolSmiAllowed = FALSE; + } + + return EFI_SUCCESS; +} + + +/** + The CallBack function of SxSleep Entry. + + @param[in] DispatchHandle The handle of this callback, obtained when registering + @param[in] DispatchContext The predefined context which contained sleep type and phase + + @retval EFI_SUCCESS Operation successfully performed + +**/ +EFI_STATUS +SxSleepEntryCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ) +{ + EFI_STATUS Status; + UINT32 Data32; + + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PROGRESS_CODE_S3_SUSPEND_START); + + Status = SaveRuntimeScriptTable (mSmst); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set GPIO_35 to low + // + Data32 = MmioRead32 (PcdGet32 (PcdP2SBBaseAddress) + N_GPIO_35); + Data32 = Data32 & ~(0x0100); + Data32 = Data32 & ~(0x1); + MmioWrite32 (PcdGet32 (PcdP2SBBaseAddress) + N_GPIO_35, Data32); + + // + // Enable GPIO TIER1 SCI EN bit for LID wake function. + // + IoOr32 (mAcpiBaseAddr + R_ACPI_GPE0a_EN, B_ACPI_GPE0a_EN_GPIO_TIER1_SCI_EN); + + // + // Enable PCIE WAKE EN bit if WOL feature is enabled + // + + if (mWakeOnLanVariable) { + IoOr32 (mAcpiBaseAddr + R_ACPI_GPE0a_EN, B_ACPI_GPE0a_EN_PCIE_WAKE0_EN); + IoOr32 (mAcpiBaseAddr + R_ACPI_GPE0a_EN, B_ACPI_GPE0a_EN_PCIE_WAKE1_EN); + IoOr32 (mAcpiBaseAddr + R_ACPI_GPE0a_EN, B_ACPI_GPE0a_EN_PCIE_WAKE2_EN); + } + + // + // Workaround for S3 wake hang if C State is enabled + // + CpuSmmSxWorkAround (); + + return EFI_SUCCESS; +} + + +VOID +CpuSmmSxWorkAround( + ) +{ + UINT64 MsrValue; + + MsrValue = AsmReadMsr64 (EFI_MSR_PMG_CST_CONFIG); + + if (MsrValue & B_EFI_MSR_PMG_CST_CONFIG_CST_CONTROL_LOCK) { + // + // Cannot do anything if the register is locked. + // + return; + } + + if (MsrValue & B_EFI_MSR_PMG_CST_CONFIG_IO_MWAIT_REDIRECTION_ENABLE) { + // + // If C State enabled, disable it before going into S3 + // The MSR will be restored back during S3 wake + // + MsrValue &= ~B_EFI_MSR_PMG_CST_CONFIG_IO_MWAIT_REDIRECTION_ENABLE; + AsmWriteMsr64 (EFI_MSR_PMG_CST_CONFIG, MsrValue); + } +} + + +VOID +ClearP2PBusMaster( + ) +{ + UINT8 Command; + UINT8 Index; + + for (Index = 0; Index < sizeof (mPciBm) / sizeof (EFI_PCI_BUS_MASTER); Index++) { + Command = MmioRead8 ( + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_SC, + mPciBm[Index].Device, + mPciBm[Index].Function, + PCI_COMMAND_OFFSET + ) + ); + Command &= ~EFI_PCI_COMMAND_BUS_MASTER; + MmioWrite8 ( + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_SC, + mPciBm[Index].Device, + mPciBm[Index].Function, + PCI_COMMAND_OFFSET + ), + Command + ); + } +} + + +/** + Set the AC Loss to turn on or off. + + @retval None + +**/ +VOID +SetAfterG3On ( + BOOLEAN Enable + ) +{ + UINT8 PmCon1; + + // + // SC handling portion + // + PmCon1 = MmioRead8 (PMC_BASE_ADDRESS + R_PMC_GEN_PMCON_1); + PmCon1 &= ~B_PMC_GEN_PMCON_AFTERG3_EN; + + if (Enable) { + PmCon1 |= B_PMC_GEN_PMCON_AFTERG3_EN; + } + + MmioWrite8 (PMC_BASE_ADDRESS + R_PMC_GEN_PMCON_1, PmCon1); +} + + +/** + When a power button event happens, it shuts off the machine + + @retval None + +**/ +EFI_STATUS +PowerButtonCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ) +{ + // + // Check what the state to return to after AC Loss. If Last State, then + // set it to Off. + // + UINT16 Data16; + + if (mWakeOnRtcVariable) { + EnableS5WakeOnRtc (); + } + + if (mAcLossVariable == 1) { + SetAfterG3On (TRUE); + } + + ClearP2PBusMaster (); + + Data16 = (UINT16)(IoRead16(mAcpiBaseAddr + R_ACPI_GPE0a_EN)); + Data16 &= B_ACPI_GPE0a_EN_PCIE_GPE_EN; + + // + // Clear Sleep SMI Status + // + IoWrite16 ( + mAcpiBaseAddr + R_SMI_STS, + (UINT16) (IoRead16 (mAcpiBaseAddr + R_SMI_STS) | B_SMI_STS_ON_SLP_EN) + ); + + // + // Clear Sleep Type Enable + // + IoWrite16 ( + mAcpiBaseAddr + R_SMI_EN, + (UINT16) (IoRead16 (mAcpiBaseAddr + R_SMI_EN) & (~B_SMI_EN_ON_SLP_EN)) + ); + + // + // Clear Power Button Status + // + IoWrite16 (mAcpiBaseAddr + R_ACPI_PM1_STS, B_ACPI_PM1_STS_PWRBTN); + + // + // Shut it off now! + // + IoWrite16 (mAcpiBaseAddr + R_ACPI_PM1_CNT, V_ACPI_PM1_CNT_S5); + IoWrite16 (mAcpiBaseAddr + R_ACPI_PM1_CNT, B_ACPI_PM1_CNT_SLP_EN | V_ACPI_PM1_CNT_S5); + + return EFI_SUCCESS; +} + + +VOID +PmeCallback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext + ) +{ + +} + + +EFI_STATUS +S5SleepAcLossCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ) +{ + // + // Check what the state to return to after AC Loss. If Last State, then + // set it to Off. + // + if (mAcLossVariable == 1) { + SetAfterG3On (TRUE); + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +S4S5CallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ) +{ + return EFI_SUCCESS; +} + + +/** + SMI handler to enable ACPI mode + + Dispatched on reads from APM port with value 0xA0 + + Disables the SW SMI Timer. + ACPI events are disabled and ACPI event status is cleared. + SCI mode is then enabled. + + Disable SW SMI Timer + + Clear all ACPI event status and disable all ACPI events + Disable PM sources except power button + Clear status bits + + Disable GPE0 sources + Clear status bits + + Disable GPE1 sources + Clear status bits + + Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4) + + Enable SCI + + @param[in] DispatchHandle EFI Handle + @param[in] DispatchContext Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT + + @retval Nothing + +**/ +EFI_STATUS +EnableAcpiCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + UINT8 OutputValue; + UINT32 SmiEn; + UINT16 Pm1Cnt; + + + // + // Disable SW SMI Timer + // + SmiEn = IoRead32 (mAcpiBaseAddr + R_SMI_EN); + SmiEn &= ~B_SMI_STS_SWSMI_TMR; + IoWrite32 (mAcpiBaseAddr + R_SMI_EN, SmiEn); + + + // + // Disable PM sources except power button + // + IoWrite16 (mAcpiBaseAddr + R_ACPI_PM1_EN, B_ACPI_PM1_EN_PWRBTN); + + // + // Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4) + // + OutputValue = RTC_ADDRESS_REGISTER_D; + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, OutputValue); + OutputValue = 0x0; + OutputValue = IoRead8 (PCAT_RTC_DATA_REGISTER); + + // + // Enable SCI + // + Pm1Cnt = IoRead16 (mAcpiBaseAddr + R_ACPI_PM1_CNT); + Pm1Cnt |= B_ACPI_PM1_CNT_SCI_EN; + IoWrite16 (mAcpiBaseAddr + R_ACPI_PM1_CNT, Pm1Cnt); + + return EFI_SUCCESS; +} + + +/** + SMI handler to disable ACPI mode + + Dispatched on reads from APM port with value 0xA1 + + ACPI events are disabled and ACPI event status is cleared. + SCI mode is then disabled. + Clear all ACPI event status and disable all ACPI events + Disable PM sources except power button + Clear status bits + Disable GPE0 sources + Clear status bits + Disable GPE1 sources + Clear status bits + + Disable SCI + + @param[in] DispatchHandle EFI Handle + @param[in] DispatchContext Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT + + @retval Nothing + +**/ +EFI_STATUS +DisableAcpiCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ) +{ + UINT16 Pm1Cnt; + + // + // Disable SCI + // + Pm1Cnt = IoRead16 (mAcpiBaseAddr + R_ACPI_PM1_CNT); + Pm1Cnt &= ~B_ACPI_PM1_CNT_SCI_EN; + IoWrite16 (mAcpiBaseAddr + R_ACPI_PM1_CNT, Pm1Cnt); + + return EFI_SUCCESS; +} + + +VOID +DummyTco1Callback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext + ) +{ +} + +UINTN +DevicePathSize ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *Start; + + if (DevicePath == NULL) { + return 0; + } + + // + // Search for the end of the device path structure + // + Start = DevicePath; + while (!IsDevicePathEnd (DevicePath)) { + DevicePath = NextDevicePathNode (DevicePath); + } + + // + // Compute the size and add back in the size of the end device path structure + // + return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL); +} + + +EFI_STATUS +S5SleepWakeOnRtcCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ) +{ + EnableS5WakeOnRtc (); + + return EFI_SUCCESS; +} + + +/** + Returns: + Check Alarm interrupt is not set. + Clear Alarm interrupt. + Set RTC wake up date and time. + Enable RTC wake up alarm. + Enable ICH PM1 EN Bit 10(RTC_EN) + +**/ +VOID +EnableS5WakeOnRtc ( + ) +{ + UINT8 CmosData; + UINTN i; + EFI_STATUS Status; + UINTN VarSize; + + // + // make sure EFI_SMM_VARIABLE_PROTOCOL is available + // + if (!mSmmVariable) { + return; + } + + VarSize = sizeof (SYSTEM_CONFIGURATION); + + Status = gRT->GetVariable ( + L"Setup", + &gEfiSetupVariableGuid, + NULL, + &VarSize, + &mSystemConfiguration + ); + + if (EFI_ERROR (Status) || (!mSystemConfiguration.WakeOnRtcS5)) { + return; + } + mWakeupDay = HexToBcd ((UINT8) mSystemConfiguration.RTCWakeupDate); + mWakeupHour = HexToBcd ((UINT8) mSystemConfiguration.RTCWakeupTimeHour); + mWakeupMinute = HexToBcd ((UINT8) mSystemConfiguration.RTCWakeupTimeMinute); + mWakeupSecond = HexToBcd ((UINT8) mSystemConfiguration.RTCWakeupTimeSecond); + + // + // Check RTC alarm interrupt is enabled. If enabled, someone already + // grabbed RTC alarm. Just return. + // + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B); + if (IoRead8 (PCAT_RTC_DATA_REGISTER) & B_RTC_ALARM_INT_ENABLE) { + return; + } + + // + // Set Date + // + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D); + CmosData = IoRead8 (PCAT_RTC_DATA_REGISTER); + CmosData &= ~(B_RTC_DATE_ALARM_MASK); + CmosData |= mWakeupDay ; + for (i = 0 ; i < 0xffff ; i++) { + IoWrite8 (PCAT_RTC_DATA_REGISTER, CmosData); + Stall (1); + if (((CmosData = IoRead8 (PCAT_RTC_DATA_REGISTER)) & B_RTC_DATE_ALARM_MASK) == mWakeupDay) { + break; + } + } + + // + // Set Second + // + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECOND_ALARM); + for (i = 0 ; i < 0xffff ; i++) { + IoWrite8 (PCAT_RTC_DATA_REGISTER, mWakeupSecond); + Stall (1); + if (IoRead8 (PCAT_RTC_DATA_REGISTER) == mWakeupSecond) { + break; + } + } + + // + // Set Minute + // + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTE_ALARM); + for (i = 0 ; i < 0xffff ; i++){ + IoWrite8 (PCAT_RTC_DATA_REGISTER, mWakeupMinute); + Stall (1); + if (IoRead8 (PCAT_RTC_DATA_REGISTER) == mWakeupMinute) { + break; + } + } + + // + // Set Hour + // + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOUR_ALARM); + for (i = 0 ; i < 0xffff ; i++) { + IoWrite8 (PCAT_RTC_DATA_REGISTER, mWakeupHour); + Stall (1); + if (IoRead8 (PCAT_RTC_DATA_REGISTER) == mWakeupHour) { + break; + } + } + + // + // Wait for UIP to arm RTC alarm + // + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A); + while (IoRead8 (PCAT_RTC_DATA_REGISTER) & 0x80); + + // + // Read RTC register 0C to clear pending RTC interrupts + // + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C); + IoRead8 (PCAT_RTC_DATA_REGISTER); + + // + // Enable RTC Alarm Interrupt + // + IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B); + IoWrite8 (PCAT_RTC_DATA_REGISTER, IoRead8(PCAT_RTC_DATA_REGISTER) | B_RTC_ALARM_INT_ENABLE); + + // + // Clear ICH RTC Status + // + IoWrite16 (mAcpiBaseAddr + R_ACPI_PM1_STS, B_ACPI_PM1_STS_RTC); + + // + // Enable ICH RTC event + // + IoWrite16 (mAcpiBaseAddr + R_ACPI_PM1_EN, + (UINT16) (IoRead16 (mAcpiBaseAddr + R_ACPI_PM1_EN) | B_ACPI_PM1_EN_RTC)); +} + + +UINT8 +HexToBcd( + IN UINT8 HexValue + ) +{ + UINTN HighByte; + UINTN LowByte; + + HighByte = (UINTN) HexValue / 10; + LowByte = (UINTN) HexValue % 10; + + return ((UINT8) (LowByte + (HighByte << 4))); +} + + +UINT8 +BcdToHex( + IN UINT8 BcdValue + ) +{ + UINTN HighByte; + UINTN LowByte; + + HighByte = (UINTN) ((BcdValue >> 4) * 10); + LowByte = (UINTN) (BcdValue & 0x0F); + + return ((UINT8) (LowByte + HighByte)); +} + + +/** + TPM Handler + + @param[in] DispatchHandle The handle of this callback, obtained when registering + @param[in] DispatchContext Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT + + @retval None. + +**/ +EFI_STATUS +TpmPtsSmbsCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ) +{ + UINT8 TpmSetting; + + // + // Setting MORD + // + TpmSetting = EFI_ACPI_TPM_MORD; + mSmst->SmmIo.Io.Write (&mSmst->SmmIo, SMM_IO_UINT8, 0x72, 1, &TpmSetting); + TpmSetting = mGlobalNvsAreaPtr->Area->MorData; + mSmst->SmmIo.Io.Write (&mSmst->SmmIo, SMM_IO_UINT8, 0x73, 1, &TpmSetting); + + return EFI_SUCCESS; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/PlatformSmm/PlatformSmm.inf b/Platform/BroxtonPlatformPkg/Common/PlatformSmm/PlatformSmm.inf new file mode 100644 index 0000000000..82a251cd19 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/PlatformSmm/PlatformSmm.inf @@ -0,0 +1,95 @@ +## @file +# Component description file for SMM Platform handler module. +# +# Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PlatformSmm + FILE_GUID = 99C20A37-042A-46e2-80F4-E4027FDBC86F + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitializePlatformSmm + PI_SPECIFICATION_VERSION = 0x0001000A + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + S3Save.c + Platform.c + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + SmmServicesTableLib + DebugLib + IoLib + PcdLib + BaseLib + BaseMemoryLib + DevicePathLib + HobLib + S3BootScriptLib + StallSmmLib + SideBandLib + ReportStatusCodeLib + GpioLib + +[Guids] + gEfiSetupVariableGuid + gDmiDataGuid + gEfiAcpiVariableCompatiblityGuid + gEfiPciLanInfoGuid + gEfiPciLanInfoGuid + +[Protocols] + gEfiSmmBase2ProtocolGuid + gEfiSmmIchnDispatchProtocolGuid + gEfiGlobalNvsAreaProtocolGuid + gEfiSmmSwDispatch2ProtocolGuid + gEfiSmmPowerButtonDispatch2ProtocolGuid + gEfiSmmSxDispatch2ProtocolGuid + gEfiSmmVariableProtocolGuid + gEfiSmmCpuProtocolGuid + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + IntelFrameworkPkg/IntelFrameworkPkg.dec + BroxtonSiPkg/BroxtonSiPkg.dec + BroxtonPlatformPkg/PlatformPkg.dec + IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec + +[Pcd] + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress + gEfiBxtTokenSpaceGuid.PcdScAcpiIoPortBaseAddress + gEfiBxtTokenSpaceGuid.PcdPmcGcrBaseAddress + gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart + gEfiBxtTokenSpaceGuid.PcdP2SBBaseAddress + +[Depex] + gEfiSmmBase2ProtocolGuid AND + gEfiSmmAccess2ProtocolGuid AND + gEfiSmmPowerButtonDispatch2ProtocolGuid AND + gEfiSmmSxDispatch2ProtocolGuid AND + gEfiSmmIchnDispatchProtocolGuid AND + gEfiSmmSwDispatch2ProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid AND + gEfiGlobalNvsAreaProtocolGuid + diff --git a/Platform/BroxtonPlatformPkg/Common/PlatformSmm/S3Save.c b/Platform/BroxtonPlatformPkg/Common/PlatformSmm/S3Save.c new file mode 100644 index 0000000000..4b3f34fc3f --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/PlatformSmm/S3Save.c @@ -0,0 +1,82 @@ +/** @file + SMM S3 handler Driver implementation file. + + Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "SmmPlatform.h" + +extern UINT16 mAcpiBaseAddr; + +EFI_STATUS +SaveRuntimeScriptTable ( + IN EFI_SMM_SYSTEM_TABLE2 *Smst + ) +{ + UINT32 Data32; + UINT16 Data16; + UINT8 Data8; + UINT32 DwordData; + UINT32 PciOffset; + + IoWrite8 (0x80, 0x53); + + for (PciOffset = 0x10; PciOffset < 0x0cf; PciOffset += 4) { + DwordData = MmioRead32 (MmPciAddress (0, SA_IGD_BUS, SA_IGD_DEV, SA_IGD_FUN_0, PciOffset)); + + S3BootScriptSaveMemWrite ( + S3BootScriptWidthUint32, + MmPciAddress (0, SA_IGD_BUS, SA_IGD_DEV, SA_IGD_FUN_0, PciOffset), + 1, + &DwordData + ); + } + + IoWrite8 (0x80, 0x53); + + // + // Save I/O ports to S3 script table + // + + // + // Selftest KBC + // + Data8 = 0xAA; + S3BootScriptSaveIoWrite ( + S3BootScriptWidthUint8, + 0x64, + (UINTN) 1, + &Data8 + ); + + Data32 = IoRead32 (mAcpiBaseAddr + R_SMI_EN); + S3BootScriptSaveIoWrite ( + S3BootScriptWidthUint32, + (mAcpiBaseAddr + R_SMI_EN), + 1, + &Data32 + ); + + // + // Save B_ICH_TCO_CNT_LOCK so it will be done on S3 resume path. + // + Data16 = IoRead16 (mAcpiBaseAddr + R_TCO_CNT); + S3BootScriptSaveIoWrite ( + S3BootScriptWidthUint16, + mAcpiBaseAddr + R_TCO_CNT, + 1, + &Data16 + ); + + return EFI_SUCCESS; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/PlatformSmm/SmmPlatform.h b/Platform/BroxtonPlatformPkg/Common/PlatformSmm/SmmPlatform.h new file mode 100644 index 0000000000..0689f31647 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/PlatformSmm/SmmPlatform.h @@ -0,0 +1,223 @@ +/** @file + Header file for Platform Smm driver. + + Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php. + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _PLATFORM_H +#define _PLATFORM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Protocol/GlobalNvsArea.h" +#include +#include +#include +#include +#include +#include "ScAccess.h" +#include "CpuRegs.h" +#include "CmosMap.h" +#include "PlatformBaseAddresses.h" +#include "SaRegs.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct { + UINT8 Register; + UINT8 Function; + UINT8 Device; + UINT8 Bus; + UINT32 ExtendedRegister; +} SMM_PCI_IO_ADDRESS; + +typedef struct { + CHAR8 BoardAaNumber[7]; + UINTN BoardFabNumber; +} BOARD_AA_NUMBER_DECODE; +// +// BugBug -- Need to get these two values from acpi.h, but right now, they are +// declared in platform-specific variants of this file, so no easy +// way to pick-up the include file and work across platforms. +// Need these definitions to go into a file like common\acpi.h. +// +#define ACPI_ENABLE 0xA0 +#define ACPI_DISABLE 0xA1 + +#define SMI_SET_SMMVARIABLE_PROTOCOL 0x51 // this is used in Cpu\Pentium\Smm\Base\SmmBase.c +#define SMI_CMD_GET_MSEG_STATUS 0x70 +#define SMI_CMD_UPDATE_MSEG_SIZE 0x71 +#define SMI_CMD_LOAD_STM 0x72 +#define SMI_CMD_UNLOAD_STM 0x73 +#define SMI_CMD_GET_SMRAM_RANGES 0x74 + +#define PCAT_RTC_ADDRESS_REGISTER 0x74 +#define PCAT_RTC_DATA_REGISTER 0x75 + +#define RTC_ADDRESS_SECOND 0x00 +#define RTC_ADDRESS_SECOND_ALARM 0x01 +#define RTC_ADDRESS_MINUTE 0x02 +#define RTC_ADDRESS_MINUTE_ALARM 0x03 +#define RTC_ADDRESS_HOUR 0x04 +#define RTC_ADDRESS_HOUR_ALARM 0x05 + +#define RTC_ADDRESS_REGISTER_A 0x0A +#define RTC_ADDRESS_REGISTER_B 0x0B +#define RTC_ADDRESS_REGISTER_C 0x0C +#define RTC_ADDRESS_REGISTER_D 0x0D + +#define B_RTC_ALARM_INT_ENABLE 0x20 +#define B_RTC_ALARM_INT_STATUS 0x20 + +#define B_RTC_DATE_ALARM_MASK 0x3F + +#define PCAT_CMOS_2_ADDRESS_REGISTER 0x72 +#define PCAT_CMOS_2_DATA_REGISTER 0x73 + +// +// Callback function prototypes +// +EFI_STATUS +PowerButtonCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + +EFI_STATUS +S5SleepWakeOnLanCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + +EFI_STATUS +S5SleepAcLossCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + + +EFI_STATUS +S4S5CallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + +EFI_STATUS +EnableAcpiCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + +EFI_STATUS +DisableAcpiCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + +EFI_STATUS +SmmReadyToBootCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + +VOID +DummyTco1Callback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext + ); + +VOID +PmeCallback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext + ); + +VOID +PerrSerrCallback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext + ); + + +VOID +EnableWatchdogCallback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext + ); + +VOID +SetAfterG3On ( + BOOLEAN Enable + ); + +VOID +TurnOffVregUsb ( + ); + +EFI_STATUS +SxSleepEntryCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + +EFI_STATUS +SaveRuntimeScriptTable ( + IN EFI_SMM_SYSTEM_TABLE2 *Smst + ); + +EFI_STATUS +TpmPtsSmbsCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *DispatchContext, + IN OUT VOID *CommBuffer OPTIONAL, + IN UINTN *CommBufferSize OPTIONAL + ); + +#endif + -- cgit v1.2.3