3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
15 This is a generic template for a child of the IchSmm driver.
20 #include "SmmPlatform.h"
21 #include <Protocol/CpuIo2.h>
32 EFI_PCI_BUS_MASTER mPciBm
[] = {
33 { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS
, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1
},
34 { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS
, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_2
},
35 { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS
, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_3
},
36 { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS
, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_4
},
37 { PCI_DEVICE_NUMBER_PCH_USB
, PCI_FUNCTION_NUMBER_PCH_EHCI
}
42 SYSTEM_CONFIGURATION mSystemConfiguration
;
43 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
;
44 EFI_GLOBAL_NVS_AREA_PROTOCOL
*mGlobalNvsAreaPtr
;
46 UINT16 mPM1_SaveState16
;
47 UINT32 mGPE_SaveState32
;
49 BOOLEAN mSetSmmVariableProtocolSmiAllowed
= TRUE
;
53 // Variables. Need to initialize this from Setup
55 BOOLEAN mWakeOnLanS5Variable
;
56 BOOLEAN mWakeOnRtcVariable
;
63 // Use an enum. 0 is Stay Off, 1 is Last State, 2 is Stay On
65 UINT8 mAcLossVariable
;
69 UINT8 mTco1Sources
[] = {
75 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
82 InitRuntimeScriptTable (
83 IN EFI_SYSTEM_TABLE
*SystemTable
87 S5SleepWakeOnRtcCallBack (
88 IN EFI_HANDLE DispatchHandle
,
89 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
112 Initializes the SMM Handler Driver
122 InitializePlatformSmm (
123 IN EFI_HANDLE ImageHandle
,
124 IN EFI_SYSTEM_TABLE
*SystemTable
130 EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT PowerButtonContext
;
131 EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL
*PowerButtonDispatch
;
132 EFI_SMM_ICHN_DISPATCH_CONTEXT IchnContext
;
133 EFI_SMM_ICHN_DISPATCH_PROTOCOL
*IchnDispatch
;
134 EFI_SMM_SX_DISPATCH_PROTOCOL
*SxDispatch
;
135 EFI_SMM_SX_DISPATCH_CONTEXT EntryDispatchContext
;
136 EFI_SMM_SW_DISPATCH_PROTOCOL
*SwDispatch
;
137 EFI_SMM_SW_DISPATCH_CONTEXT SwContext
;
139 EFI_BOOT_MODE BootMode
;
144 // Locate the Global NVS Protocol.
146 Status
= gBS
->LocateProtocol (
147 &gEfiGlobalNvsAreaProtocolGuid
,
149 (void **)&mGlobalNvsAreaPtr
151 ASSERT_EFI_ERROR (Status
);
155 // Get the ACPI Base Address
158 mAcpiBaseAddr
= PchLpcPciCfg16( R_PCH_LPC_ACPI_BASE
) & B_PCH_LPC_ACPI_BASE_BAR
;
160 VarSize
= sizeof(SYSTEM_CONFIGURATION
);
161 Status
= SystemTable
->RuntimeServices
->GetVariable(
163 &gEfiSetupVariableGuid
,
166 &mSystemConfiguration
168 if (EFI_ERROR (Status
) || VarSize
!= sizeof(SYSTEM_CONFIGURATION
)) {
169 //The setup variable is corrupted
170 VarSize
= sizeof(SYSTEM_CONFIGURATION
);
171 Status
= SystemTable
->RuntimeServices
->GetVariable(
173 &gEfiSetupVariableGuid
,
176 &mSystemConfiguration
178 ASSERT_EFI_ERROR (Status
);
180 if (!EFI_ERROR(Status
)) {
181 mAcLossVariable
= mSystemConfiguration
.StateAfterG3
;
184 // If LAN is disabled, WOL function should be disabled too.
186 if (mSystemConfiguration
.Lan
== 0x01){
187 mWakeOnLanS5Variable
= mSystemConfiguration
.WakeOnLanS5
;
189 mWakeOnLanS5Variable
= FALSE
;
192 mWakeOnRtcVariable
= mSystemConfiguration
.WakeOnRtcS5
;
195 BootMode
= GetBootModeHob ();
198 // Get the Power Button protocol
200 Status
= gBS
->LocateProtocol(
201 &gEfiSmmPowerButtonDispatchProtocolGuid
,
203 (void **)&PowerButtonDispatch
205 ASSERT_EFI_ERROR(Status
);
207 if (BootMode
!= BOOT_ON_FLASH_UPDATE
) {
209 // Register for the power button event
211 PowerButtonContext
.Phase
= PowerButtonEntry
;
212 Status
= PowerButtonDispatch
->Register(
218 ASSERT_EFI_ERROR(Status
);
221 // Get the Sx dispatch protocol
223 Status
= gBS
->LocateProtocol (
224 &gEfiSmmSxDispatchProtocolGuid
,
228 ASSERT_EFI_ERROR(Status
);
231 // Register entry phase call back function
233 EntryDispatchContext
.Type
= SxS3
;
234 EntryDispatchContext
.Phase
= SxEntry
;
236 Status
= SxDispatch
->Register (
238 (EFI_SMM_SX_DISPATCH
)SxSleepEntryCallBack
,
239 &EntryDispatchContext
,
244 EntryDispatchContext
.Type
= SxS4
;
246 Status
= SxDispatch
->Register (
249 &EntryDispatchContext
,
252 ASSERT_EFI_ERROR(Status
);
255 EntryDispatchContext
.Type
= SxS5
;
257 Status
= SxDispatch
->Register (
260 &EntryDispatchContext
,
263 ASSERT_EFI_ERROR(Status
);
265 Status
= SxDispatch
->Register (
267 S5SleepAcLossCallBack
,
268 &EntryDispatchContext
,
271 ASSERT_EFI_ERROR(Status
);
274 // Get the Sw dispatch protocol
276 Status
= gBS
->LocateProtocol (
277 &gEfiSmmSwDispatchProtocolGuid
,
281 ASSERT_EFI_ERROR(Status
);
284 // Register ACPI enable handler
286 SwContext
.SwSmiInputValue
= ACPI_ENABLE
;
287 Status
= SwDispatch
->Register (
293 ASSERT_EFI_ERROR(Status
);
296 // Register ACPI disable handler
298 SwContext
.SwSmiInputValue
= ACPI_DISABLE
;
299 Status
= SwDispatch
->Register (
305 ASSERT_EFI_ERROR(Status
);
309 // Register for SmmReadyToBootCallback
311 SwContext
.SwSmiInputValue
= SMI_SET_SMMVARIABLE_PROTOCOL
;
312 Status
= SwDispatch
->Register(
314 SmmReadyToBootCallback
,
318 ASSERT_EFI_ERROR(Status
);
321 // Get the ICHn protocol
323 Status
= gBS
->LocateProtocol(
324 &gEfiSmmIchnDispatchProtocolGuid
,
326 (void **)&IchnDispatch
328 ASSERT_EFI_ERROR(Status
);
331 // Register for the events that may happen that we do not care.
332 // This is true for SMI related to TCO since TCO is enabled by BIOS WP
334 for (Index
= 0; Index
< sizeof(mTco1Sources
)/sizeof(UINT8
); Index
++) {
335 IchnContext
.Type
= mTco1Sources
[Index
];
336 Status
= IchnDispatch
->Register(
338 (EFI_SMM_ICHN_DISPATCH
)DummyTco1Callback
,
342 ASSERT_EFI_ERROR( Status
);
348 IoWrite16( mAcpiBaseAddr
+ R_PCH_TCO_CNT
, IoRead16( mAcpiBaseAddr
+ R_PCH_TCO_CNT
) | B_PCH_TCO_CNT_LOCK
);
351 // Set to power on from G3 dependent on WOL instead of AC Loss variable in order to support WOL from G3 feature.
354 // Set wake from G3 dependent on AC Loss variable and Wake On LAN variable.
355 // 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.
356 // This needs to be done after LAN enable/disable so that the PWR_FLR state clear not impacted the WOL from G3 feature.
358 if (mAcLossVariable
!= 0x00) {
361 SetAfterG3On (FALSE
);
372 SmmReadyToBootCallback (
373 IN EFI_HANDLE DispatchHandle
,
374 IN EFI_SMM_SW_DISPATCH_CONTEXT
*DispatchContext
379 if (mSetSmmVariableProtocolSmiAllowed
)
382 // It is okay to use gBS->LocateProtocol here because
383 // we are still in trusted execution.
385 Status
= gBS
->LocateProtocol(
386 &gEfiSmmVariableProtocolGuid
,
388 (void **)&mSmmVariable
391 ASSERT_EFI_ERROR(Status
);
394 // mSetSmmVariableProtocolSmiAllowed will prevent this function from
395 // being executed more than 1 time.
397 mSetSmmVariableProtocolSmiAllowed
= FALSE
;
404 @param DispatchHandle The handle of this callback, obtained when registering
405 @param DispatchContext The predefined context which contained sleep type and phase
408 @retval EFI_SUCCESS Operation successfully performed
413 SxSleepEntryCallBack (
414 IN EFI_HANDLE DispatchHandle
,
415 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
420 Status
= SaveRuntimeScriptTable ();
421 if (EFI_ERROR(Status
)) {
426 // Workaround for S3 wake hang if C State is enabled
428 CpuSmmSxWorkAround();
439 MsrValue
= AsmReadMsr64 (0xE2);
441 if (MsrValue
& BIT15
) {
445 if (MsrValue
& BIT10
) {
447 AsmWriteMsr64 (0xE2, MsrValue
);
458 for (Index
= 0; Index
< sizeof(mPciBm
)/sizeof(EFI_PCI_BUS_MASTER
); Index
++) {
459 Command
= MmioRead8 (
461 DEFAULT_PCI_BUS_NUMBER_PCH
,
462 mPciBm
[Index
].Device
,
463 mPciBm
[Index
].Function
,
467 Command
&= ~EFI_PCI_COMMAND_BUS_MASTER
;
470 DEFAULT_PCI_BUS_NUMBER_PCH
,
471 mPciBm
[Index
].Device
,
472 mPciBm
[Index
].Function
,
482 Set the AC Loss to turn on or off.
493 // ICH handling portion
495 PmCon1
= MmioRead8 ( PMC_BASE_ADDRESS
+ R_PCH_PMC_GEN_PMCON_1
);
496 PmCon1
&= ~B_PCH_PMC_GEN_PMCON_AFTERG3_EN
;
498 PmCon1
|= B_PCH_PMC_GEN_PMCON_AFTERG3_EN
;
500 MmioWrite8 (PMC_BASE_ADDRESS
+ R_PCH_PMC_GEN_PMCON_1
, PmCon1
);
505 When a power button event happens, it shuts off the machine
510 PowerButtonCallback (
511 IN EFI_HANDLE DispatchHandle
,
512 IN EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT
*DispatchContext
516 // Check what the state to return to after AC Loss. If Last State, then
521 if (mWakeOnRtcVariable
) {
525 if (mAcLossVariable
== 1) {
532 // Program clock chip
537 data16
= (UINT16
)(IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
));
538 data16
&= B_PCH_ACPI_GPE0a_EN_PCI_EXP
;
542 // Clear Sleep SMI Status
544 IoWrite16 (mAcpiBaseAddr
+ R_PCH_SMI_STS
,
545 (UINT16
)(IoRead16 (mAcpiBaseAddr
+ R_PCH_SMI_STS
) | B_PCH_SMI_STS_ON_SLP_EN
));
547 // Clear Sleep Type Enable
549 IoWrite16 (mAcpiBaseAddr
+ R_PCH_SMI_EN
,
550 (UINT16
)(IoRead16 (mAcpiBaseAddr
+ R_PCH_SMI_EN
) & (~B_PCH_SMI_EN_ON_SLP_EN
)));
553 // Clear Power Button Status
555 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
, B_PCH_ACPI_PM1_STS_PWRBTN
);
560 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
, V_PCH_ACPI_PM1_CNT_S5
);
561 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
, B_PCH_ACPI_PM1_CNT_SLP_EN
| V_PCH_ACPI_PM1_CNT_S5
);
571 @param DispatchHandle - The handle of this callback, obtained when registering
573 @param DispatchContext - The predefined context which contained sleep type and phase
578 S5SleepAcLossCallBack (
579 IN EFI_HANDLE DispatchHandle
,
580 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
584 // Check what the state to return to after AC Loss. If Last State, then
587 if (mAcLossVariable
== 1) {
594 @param DispatchHandle The handle of this callback, obtained when registering
595 @param DispatchContext The predefined context which contained sleep type and phase
597 @retval Clears the Save State bit in the clock.
603 IN EFI_HANDLE DispatchHandle
,
604 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
611 // Enable/Disable USB Charging
613 if (mSystemConfiguration
.UsbCharging
== 0x01) {
614 Data32
= IoRead32 (GPIO_BASE_ADDRESS
+ R_PCH_GPIO_SC_LVL
);
616 IoWrite32(GPIO_BASE_ADDRESS
+ R_PCH_GPIO_SC_LVL
, Data32
);
628 SMI handler to enable ACPI mode
630 Dispatched on reads from APM port with value 0xA0
632 Disables the SW SMI Timer.
633 ACPI events are disabled and ACPI event status is cleared.
634 SCI mode is then enabled.
638 Clear all ACPI event status and disable all ACPI events
639 Disable PM sources except power button
648 Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
652 @param DispatchHandle - EFI Handle
653 @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
661 IN EFI_HANDLE DispatchHandle
,
662 IN EFI_SMM_SW_DISPATCH_CONTEXT
*DispatchContext
671 // Disable SW SMI Timer
673 SmiEn
= IoRead32(mAcpiBaseAddr
+ R_PCH_SMI_EN
);
674 SmiEn
&= ~B_PCH_SMI_STS_SWSMI_TMR
;
675 IoWrite32(mAcpiBaseAddr
+ R_PCH_SMI_EN
, SmiEn
);
677 wordValue
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
);
678 if(wordValue
& B_PCH_ACPI_PM1_STS_WAK
) {
679 IoWrite32((mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
), 0x0000);
680 IoWrite32((mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_STS
), 0xffffffff);
683 mPM1_SaveState16
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
);
686 // Disable PM sources except power button
688 // power button is enabled only for PCAT. Disabled it on Tablet platform
690 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
, B_PCH_ACPI_PM1_EN_PWRBTN
);
691 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
, 0xffff);
693 mGPE_SaveState32
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
);
694 IoWrite32(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
, 0x0000);
695 IoWrite32(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_STS
, 0xffffffff);
700 // Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
701 // Clear Status D reg VM bit, Date of month Alarm to make Data in CMOS RAM is no longer Valid
703 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_D
);
704 IoWrite8 (PCAT_RTC_DATA_REGISTER
, 0x0);
707 RegData32
= IoRead32(ACPI_BASE_ADDRESS
+ R_PCH_ALT_GP_SMI_EN
);
708 RegData32
&= ~(BIT7
);
709 IoWrite32((ACPI_BASE_ADDRESS
+ R_PCH_ALT_GP_SMI_EN
), RegData32
);
715 Pm1Cnt
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
);
716 Pm1Cnt
|= B_PCH_ACPI_PM1_CNT_SCI_EN
;
717 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
, Pm1Cnt
);
723 SMI handler to disable ACPI mode
725 Dispatched on reads from APM port with value 0xA1
727 ACPI events are disabled and ACPI event status is cleared.
728 SCI mode is then disabled.
729 Clear all ACPI event status and disable all ACPI events
730 Disable PM sources except power button
738 @param DispatchHandle - EFI Handle
739 @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
746 DisableAcpiCallback (
747 IN EFI_HANDLE DispatchHandle
,
748 IN EFI_SMM_SW_DISPATCH_CONTEXT
*DispatchContext
753 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
, 0xffff);
754 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
, mPM1_SaveState16
);
756 IoWrite32(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_STS
, 0xffffffff);
757 IoWrite32(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
, mGPE_SaveState32
);
762 Pm1Cnt
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
);
763 Pm1Cnt
&= ~B_PCH_ACPI_PM1_CNT_SCI_EN
;
764 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
, Pm1Cnt
);
769 When an unknown event happen.
776 IN EFI_HANDLE DispatchHandle
,
777 IN EFI_SMM_ICHN_DISPATCH_CONTEXT
*DispatchContext
784 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
787 EFI_DEVICE_PATH_PROTOCOL
*Start
;
789 if (DevicePath
== NULL
) {
794 // Search for the end of the device path structure
797 while (!IsDevicePathEnd (DevicePath
)) {
798 DevicePath
= NextDevicePathNode (DevicePath
);
802 // Compute the size and add back in the size of the end device path structure
804 return ((UINTN
)DevicePath
- (UINTN
)Start
) + sizeof(EFI_DEVICE_PATH_PROTOCOL
);
809 @param DispatchHandle The handle of this callback, obtained when registering
810 @param DispatchContext The predefined context which contained sleep type and phase
814 S5SleepWakeOnRtcCallBack (
815 IN EFI_HANDLE DispatchHandle
,
816 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
824 @retval 1. Check Alarm interrupt is not set.
825 2. Clear Alarm interrupt.
826 2. Set RTC wake up date and time.
827 2. Enable RTC wake up alarm.
828 3. Enable ICH PM1 EN Bit 10(RTC_EN)
840 // make sure EFI_SMM_VARIABLE_PROTOCOL is available
846 VarSize
= sizeof(SYSTEM_CONFIGURATION
);
849 // read the variable into the buffer
851 Status
= mSmmVariable
->SmmGetVariable(
853 &gEfiSetupVariableGuid
,
856 &mSystemConfiguration
858 if (EFI_ERROR(Status
) || VarSize
!= sizeof(SYSTEM_CONFIGURATION
)) {
859 //The setup variable is corrupted
860 VarSize
= sizeof(SYSTEM_CONFIGURATION
);
861 Status
= mSmmVariable
->SmmGetVariable(
863 &gEfiSetupVariableGuid
,
866 &mSystemConfiguration
868 ASSERT_EFI_ERROR (Status
);
871 if (!mSystemConfiguration
.WakeOnRtcS5
) {
874 mWakeupDay
= HexToBcd((UINT8
)mSystemConfiguration
.RTCWakeupDate
);
875 mWakeupHour
= HexToBcd((UINT8
)mSystemConfiguration
.RTCWakeupTimeHour
);
876 mWakeupMinute
= HexToBcd((UINT8
)mSystemConfiguration
.RTCWakeupTimeMinute
);
877 mWakeupSecond
= HexToBcd((UINT8
)mSystemConfiguration
.RTCWakeupTimeSecond
);
880 // Check RTC alarm interrupt is enabled. If enabled, someone already
881 // grabbed RTC alarm. Just return.
883 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_B
);
884 if(IoRead8(PCAT_RTC_DATA_REGISTER
) & B_RTC_ALARM_INT_ENABLE
){
891 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_D
);
892 CmosData
= IoRead8(PCAT_RTC_DATA_REGISTER
);
893 CmosData
&= ~(B_RTC_DATE_ALARM_MASK
);
894 CmosData
|= mWakeupDay
;
895 for(i
= 0 ; i
< 0xffff ; i
++){
896 IoWrite8(PCAT_RTC_DATA_REGISTER
, CmosData
);
898 if(((CmosData
= IoRead8(PCAT_RTC_DATA_REGISTER
)) & B_RTC_DATE_ALARM_MASK
)
907 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_SECOND_ALARM
);
908 for(i
= 0 ; i
< 0xffff ; i
++){
909 IoWrite8(PCAT_RTC_DATA_REGISTER
, mWakeupSecond
);
911 if(IoRead8(PCAT_RTC_DATA_REGISTER
) == mWakeupSecond
){
919 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_MINUTE_ALARM
);
920 for(i
= 0 ; i
< 0xffff ; i
++){
921 IoWrite8(PCAT_RTC_DATA_REGISTER
, mWakeupMinute
);
923 if(IoRead8(PCAT_RTC_DATA_REGISTER
) == mWakeupMinute
){
931 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_HOUR_ALARM
);
932 for(i
= 0 ; i
< 0xffff ; i
++){
933 IoWrite8(PCAT_RTC_DATA_REGISTER
, mWakeupHour
);
935 if(IoRead8(PCAT_RTC_DATA_REGISTER
) == mWakeupHour
){
941 // Wait for UIP to arm RTC alarm
943 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_A
);
944 while (IoRead8(PCAT_RTC_DATA_REGISTER
) & 0x80);
947 // Read RTC register 0C to clear pending RTC interrupts
949 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_C
);
950 IoRead8(PCAT_RTC_DATA_REGISTER
);
953 // Enable RTC Alarm Interrupt
955 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_B
);
956 IoWrite8(PCAT_RTC_DATA_REGISTER
, IoRead8(PCAT_RTC_DATA_REGISTER
) | B_RTC_ALARM_INT_ENABLE
);
959 // Clear ICH RTC Status
961 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
, B_PCH_ACPI_PM1_STS_RTC
);
964 // Enable ICH RTC event
966 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
,
967 (UINT16
)(IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
) | B_PCH_ACPI_PM1_EN_RTC
));
978 HighByte
= (UINTN
)HexValue
/ 10;
979 LowByte
= (UINTN
)HexValue
% 10;
981 return ((UINT8
)(LowByte
+ (HighByte
<< 4)));
992 HighByte
= (UINTN
)((BcdValue
>> 4) * 10);
993 LowByte
= (UINTN
)(BcdValue
& 0x0F);
995 return ((UINT8
)(LowByte
+ HighByte
));