3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available under
6 the terms and conditions of the BSD License that accompanies this distribution.
7 The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php.
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 This is a generic template for a child of the IchSmm driver.
25 #include "SmmPlatform.h"
26 #include <Protocol/CpuIo2.h>
37 EFI_PCI_BUS_MASTER mPciBm
[] = {
38 { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS
, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1
},
39 { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS
, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_2
},
40 { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS
, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_3
},
41 { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS
, PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_4
},
42 { PCI_DEVICE_NUMBER_PCH_USB
, PCI_FUNCTION_NUMBER_PCH_EHCI
}
47 SYSTEM_CONFIGURATION mSystemConfiguration
;
48 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
;
49 EFI_GLOBAL_NVS_AREA_PROTOCOL
*mGlobalNvsAreaPtr
;
51 UINT16 mPM1_SaveState16
;
52 UINT32 mGPE_SaveState32
;
54 BOOLEAN mSetSmmVariableProtocolSmiAllowed
= TRUE
;
58 // Variables. Need to initialize this from Setup
60 BOOLEAN mWakeOnLanS5Variable
;
61 BOOLEAN mWakeOnRtcVariable
;
68 // Use an enum. 0 is Stay Off, 1 is Last State, 2 is Stay On
70 UINT8 mAcLossVariable
;
74 UINT8 mTco1Sources
[] = {
80 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
87 InitRuntimeScriptTable (
88 IN EFI_SYSTEM_TABLE
*SystemTable
92 S5SleepWakeOnRtcCallBack (
93 IN EFI_HANDLE DispatchHandle
,
94 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
117 Initializes the SMM Handler Driver
127 InitializePlatformSmm (
128 IN EFI_HANDLE ImageHandle
,
129 IN EFI_SYSTEM_TABLE
*SystemTable
135 EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT PowerButtonContext
;
136 EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL
*PowerButtonDispatch
;
137 EFI_SMM_ICHN_DISPATCH_CONTEXT IchnContext
;
138 EFI_SMM_ICHN_DISPATCH_PROTOCOL
*IchnDispatch
;
139 EFI_SMM_SX_DISPATCH_PROTOCOL
*SxDispatch
;
140 EFI_SMM_SX_DISPATCH_CONTEXT EntryDispatchContext
;
141 EFI_SMM_SW_DISPATCH_PROTOCOL
*SwDispatch
;
142 EFI_SMM_SW_DISPATCH_CONTEXT SwContext
;
144 EFI_BOOT_MODE BootMode
;
149 // Locate the Global NVS Protocol.
151 Status
= gBS
->LocateProtocol (
152 &gEfiGlobalNvsAreaProtocolGuid
,
154 (void **)&mGlobalNvsAreaPtr
156 ASSERT_EFI_ERROR (Status
);
160 // Get the ACPI Base Address
163 mAcpiBaseAddr
= PchLpcPciCfg16( R_PCH_LPC_ACPI_BASE
) & B_PCH_LPC_ACPI_BASE_BAR
;
165 VarSize
= sizeof(SYSTEM_CONFIGURATION
);
166 Status
= SystemTable
->RuntimeServices
->GetVariable(
168 &gEfiSetupVariableGuid
,
171 &mSystemConfiguration
173 if (EFI_ERROR (Status
) || VarSize
!= sizeof(SYSTEM_CONFIGURATION
)) {
174 //The setup variable is corrupted
175 VarSize
= sizeof(SYSTEM_CONFIGURATION
);
176 Status
= SystemTable
->RuntimeServices
->GetVariable(
178 &gEfiSetupVariableGuid
,
181 &mSystemConfiguration
183 ASSERT_EFI_ERROR (Status
);
185 if (!EFI_ERROR(Status
)) {
186 mAcLossVariable
= mSystemConfiguration
.StateAfterG3
;
189 // If LAN is disabled, WOL function should be disabled too.
191 if (mSystemConfiguration
.Lan
== 0x01){
192 mWakeOnLanS5Variable
= mSystemConfiguration
.WakeOnLanS5
;
194 mWakeOnLanS5Variable
= FALSE
;
197 mWakeOnRtcVariable
= mSystemConfiguration
.WakeOnRtcS5
;
200 BootMode
= GetBootModeHob ();
203 // Get the Power Button protocol
205 Status
= gBS
->LocateProtocol(
206 &gEfiSmmPowerButtonDispatchProtocolGuid
,
208 (void **)&PowerButtonDispatch
210 ASSERT_EFI_ERROR(Status
);
212 if (BootMode
!= BOOT_ON_FLASH_UPDATE
) {
214 // Register for the power button event
216 PowerButtonContext
.Phase
= PowerButtonEntry
;
217 Status
= PowerButtonDispatch
->Register(
223 ASSERT_EFI_ERROR(Status
);
226 // Get the Sx dispatch protocol
228 Status
= gBS
->LocateProtocol (
229 &gEfiSmmSxDispatchProtocolGuid
,
233 ASSERT_EFI_ERROR(Status
);
236 // Register entry phase call back function
238 EntryDispatchContext
.Type
= SxS3
;
239 EntryDispatchContext
.Phase
= SxEntry
;
241 Status
= SxDispatch
->Register (
243 (EFI_SMM_SX_DISPATCH
)SxSleepEntryCallBack
,
244 &EntryDispatchContext
,
249 EntryDispatchContext
.Type
= SxS4
;
251 Status
= SxDispatch
->Register (
254 &EntryDispatchContext
,
257 ASSERT_EFI_ERROR(Status
);
260 EntryDispatchContext
.Type
= SxS5
;
262 Status
= SxDispatch
->Register (
265 &EntryDispatchContext
,
268 ASSERT_EFI_ERROR(Status
);
270 Status
= SxDispatch
->Register (
272 S5SleepAcLossCallBack
,
273 &EntryDispatchContext
,
276 ASSERT_EFI_ERROR(Status
);
279 // Get the Sw dispatch protocol
281 Status
= gBS
->LocateProtocol (
282 &gEfiSmmSwDispatchProtocolGuid
,
286 ASSERT_EFI_ERROR(Status
);
289 // Register ACPI enable handler
291 SwContext
.SwSmiInputValue
= ACPI_ENABLE
;
292 Status
= SwDispatch
->Register (
298 ASSERT_EFI_ERROR(Status
);
301 // Register ACPI disable handler
303 SwContext
.SwSmiInputValue
= ACPI_DISABLE
;
304 Status
= SwDispatch
->Register (
310 ASSERT_EFI_ERROR(Status
);
314 // Register for SmmReadyToBootCallback
316 SwContext
.SwSmiInputValue
= SMI_SET_SMMVARIABLE_PROTOCOL
;
317 Status
= SwDispatch
->Register(
319 SmmReadyToBootCallback
,
323 ASSERT_EFI_ERROR(Status
);
326 // Get the ICHn protocol
328 Status
= gBS
->LocateProtocol(
329 &gEfiSmmIchnDispatchProtocolGuid
,
331 (void **)&IchnDispatch
333 ASSERT_EFI_ERROR(Status
);
336 // Register for the events that may happen that we do not care.
337 // This is true for SMI related to TCO since TCO is enabled by BIOS WP
339 for (Index
= 0; Index
< sizeof(mTco1Sources
)/sizeof(UINT8
); Index
++) {
340 IchnContext
.Type
= mTco1Sources
[Index
];
341 Status
= IchnDispatch
->Register(
343 (EFI_SMM_ICHN_DISPATCH
)DummyTco1Callback
,
347 ASSERT_EFI_ERROR( Status
);
353 IoWrite16( mAcpiBaseAddr
+ R_PCH_TCO_CNT
, IoRead16( mAcpiBaseAddr
+ R_PCH_TCO_CNT
) | B_PCH_TCO_CNT_LOCK
);
356 // Set to power on from G3 dependent on WOL instead of AC Loss variable in order to support WOL from G3 feature.
359 // Set wake from G3 dependent on AC Loss variable and Wake On LAN variable.
360 // 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.
361 // This needs to be done after LAN enable/disable so that the PWR_FLR state clear not impacted the WOL from G3 feature.
363 if (mAcLossVariable
!= 0x00) {
366 SetAfterG3On (FALSE
);
377 SmmReadyToBootCallback (
378 IN EFI_HANDLE DispatchHandle
,
379 IN EFI_SMM_SW_DISPATCH_CONTEXT
*DispatchContext
384 if (mSetSmmVariableProtocolSmiAllowed
)
387 // It is okay to use gBS->LocateProtocol here because
388 // we are still in trusted execution.
390 Status
= gBS
->LocateProtocol(
391 &gEfiSmmVariableProtocolGuid
,
393 (void **)&mSmmVariable
396 ASSERT_EFI_ERROR(Status
);
399 // mSetSmmVariableProtocolSmiAllowed will prevent this function from
400 // being executed more than 1 time.
402 mSetSmmVariableProtocolSmiAllowed
= FALSE
;
409 @param DispatchHandle The handle of this callback, obtained when registering
410 @param DispatchContext The predefined context which contained sleep type and phase
413 @retval EFI_SUCCESS Operation successfully performed
418 SxSleepEntryCallBack (
419 IN EFI_HANDLE DispatchHandle
,
420 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
425 Status
= SaveRuntimeScriptTable ();
426 if (EFI_ERROR(Status
)) {
431 // Workaround for S3 wake hang if C State is enabled
433 CpuSmmSxWorkAround();
444 MsrValue
= AsmReadMsr64 (0xE2);
446 if (MsrValue
& BIT15
) {
450 if (MsrValue
& BIT10
) {
452 AsmWriteMsr64 (0xE2, MsrValue
);
463 for (Index
= 0; Index
< sizeof(mPciBm
)/sizeof(EFI_PCI_BUS_MASTER
); Index
++) {
464 Command
= MmioRead8 (
466 DEFAULT_PCI_BUS_NUMBER_PCH
,
467 mPciBm
[Index
].Device
,
468 mPciBm
[Index
].Function
,
472 Command
&= ~EFI_PCI_COMMAND_BUS_MASTER
;
475 DEFAULT_PCI_BUS_NUMBER_PCH
,
476 mPciBm
[Index
].Device
,
477 mPciBm
[Index
].Function
,
487 Set the AC Loss to turn on or off.
498 // ICH handling portion
500 PmCon1
= MmioRead8 ( PMC_BASE_ADDRESS
+ R_PCH_PMC_GEN_PMCON_1
);
501 PmCon1
&= ~B_PCH_PMC_GEN_PMCON_AFTERG3_EN
;
503 PmCon1
|= B_PCH_PMC_GEN_PMCON_AFTERG3_EN
;
505 MmioWrite8 (PMC_BASE_ADDRESS
+ R_PCH_PMC_GEN_PMCON_1
, PmCon1
);
510 When a power button event happens, it shuts off the machine
515 PowerButtonCallback (
516 IN EFI_HANDLE DispatchHandle
,
517 IN EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT
*DispatchContext
521 // Check what the state to return to after AC Loss. If Last State, then
526 if (mWakeOnRtcVariable
) {
530 if (mAcLossVariable
== 1) {
537 // Program clock chip
542 data16
= (UINT16
)(IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
));
543 data16
&= B_PCH_ACPI_GPE0a_EN_PCI_EXP
;
547 // Clear Sleep SMI Status
549 IoWrite16 (mAcpiBaseAddr
+ R_PCH_SMI_STS
,
550 (UINT16
)(IoRead16 (mAcpiBaseAddr
+ R_PCH_SMI_STS
) | B_PCH_SMI_STS_ON_SLP_EN
));
552 // Clear Sleep Type Enable
554 IoWrite16 (mAcpiBaseAddr
+ R_PCH_SMI_EN
,
555 (UINT16
)(IoRead16 (mAcpiBaseAddr
+ R_PCH_SMI_EN
) & (~B_PCH_SMI_EN_ON_SLP_EN
)));
558 // Clear Power Button Status
560 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
, B_PCH_ACPI_PM1_STS_PWRBTN
);
565 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
, V_PCH_ACPI_PM1_CNT_S5
);
566 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
, B_PCH_ACPI_PM1_CNT_SLP_EN
| V_PCH_ACPI_PM1_CNT_S5
);
576 @param DispatchHandle - The handle of this callback, obtained when registering
578 @param DispatchContext - The predefined context which contained sleep type and phase
583 S5SleepAcLossCallBack (
584 IN EFI_HANDLE DispatchHandle
,
585 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
589 // Check what the state to return to after AC Loss. If Last State, then
592 if (mAcLossVariable
== 1) {
599 @param DispatchHandle The handle of this callback, obtained when registering
600 @param DispatchContext The predefined context which contained sleep type and phase
602 @retval Clears the Save State bit in the clock.
608 IN EFI_HANDLE DispatchHandle
,
609 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
616 // Enable/Disable USB Charging
618 if (mSystemConfiguration
.UsbCharging
== 0x01) {
619 Data32
= IoRead32 (GPIO_BASE_ADDRESS
+ R_PCH_GPIO_SC_LVL
);
621 IoWrite32(GPIO_BASE_ADDRESS
+ R_PCH_GPIO_SC_LVL
, Data32
);
633 SMI handler to enable ACPI mode
635 Dispatched on reads from APM port with value 0xA0
637 Disables the SW SMI Timer.
638 ACPI events are disabled and ACPI event status is cleared.
639 SCI mode is then enabled.
643 Clear all ACPI event status and disable all ACPI events
644 Disable PM sources except power button
653 Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
657 @param DispatchHandle - EFI Handle
658 @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
666 IN EFI_HANDLE DispatchHandle
,
667 IN EFI_SMM_SW_DISPATCH_CONTEXT
*DispatchContext
676 // Disable SW SMI Timer
678 SmiEn
= IoRead32(mAcpiBaseAddr
+ R_PCH_SMI_EN
);
679 SmiEn
&= ~B_PCH_SMI_STS_SWSMI_TMR
;
680 IoWrite32(mAcpiBaseAddr
+ R_PCH_SMI_EN
, SmiEn
);
682 wordValue
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
);
683 if(wordValue
& B_PCH_ACPI_PM1_STS_WAK
) {
684 IoWrite32((mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
), 0x0000);
685 IoWrite32((mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_STS
), 0xffffffff);
688 mPM1_SaveState16
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
);
691 // Disable PM sources except power button
693 // power button is enabled only for PCAT. Disabled it on Tablet platform
695 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
, B_PCH_ACPI_PM1_EN_PWRBTN
);
696 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
, 0xffff);
698 mGPE_SaveState32
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
);
699 IoWrite32(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
, 0x0000);
700 IoWrite32(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_STS
, 0xffffffff);
705 // Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
706 // Clear Status D reg VM bit, Date of month Alarm to make Data in CMOS RAM is no longer Valid
708 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_D
);
709 IoWrite8 (PCAT_RTC_DATA_REGISTER
, 0x0);
712 RegData32
= IoRead32(ACPI_BASE_ADDRESS
+ R_PCH_ALT_GP_SMI_EN
);
713 RegData32
&= ~(BIT7
);
714 IoWrite32((ACPI_BASE_ADDRESS
+ R_PCH_ALT_GP_SMI_EN
), RegData32
);
720 Pm1Cnt
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
);
721 Pm1Cnt
|= B_PCH_ACPI_PM1_CNT_SCI_EN
;
722 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
, Pm1Cnt
);
728 SMI handler to disable ACPI mode
730 Dispatched on reads from APM port with value 0xA1
732 ACPI events are disabled and ACPI event status is cleared.
733 SCI mode is then disabled.
734 Clear all ACPI event status and disable all ACPI events
735 Disable PM sources except power button
743 @param DispatchHandle - EFI Handle
744 @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
751 DisableAcpiCallback (
752 IN EFI_HANDLE DispatchHandle
,
753 IN EFI_SMM_SW_DISPATCH_CONTEXT
*DispatchContext
758 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
, 0xffff);
759 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
, mPM1_SaveState16
);
761 IoWrite32(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_STS
, 0xffffffff);
762 IoWrite32(mAcpiBaseAddr
+ R_PCH_ACPI_GPE0a_EN
, mGPE_SaveState32
);
767 Pm1Cnt
= IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
);
768 Pm1Cnt
&= ~B_PCH_ACPI_PM1_CNT_SCI_EN
;
769 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_CNT
, Pm1Cnt
);
774 When an unknown event happen.
781 IN EFI_HANDLE DispatchHandle
,
782 IN EFI_SMM_ICHN_DISPATCH_CONTEXT
*DispatchContext
789 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
792 EFI_DEVICE_PATH_PROTOCOL
*Start
;
794 if (DevicePath
== NULL
) {
799 // Search for the end of the device path structure
802 while (!IsDevicePathEnd (DevicePath
)) {
803 DevicePath
= NextDevicePathNode (DevicePath
);
807 // Compute the size and add back in the size of the end device path structure
809 return ((UINTN
)DevicePath
- (UINTN
)Start
) + sizeof(EFI_DEVICE_PATH_PROTOCOL
);
814 @param DispatchHandle The handle of this callback, obtained when registering
815 @param DispatchContext The predefined context which contained sleep type and phase
819 S5SleepWakeOnRtcCallBack (
820 IN EFI_HANDLE DispatchHandle
,
821 IN EFI_SMM_SX_DISPATCH_CONTEXT
*DispatchContext
829 @retval 1. Check Alarm interrupt is not set.
830 2. Clear Alarm interrupt.
831 2. Set RTC wake up date and time.
832 2. Enable RTC wake up alarm.
833 3. Enable ICH PM1 EN Bit 10(RTC_EN)
845 // make sure EFI_SMM_VARIABLE_PROTOCOL is available
851 VarSize
= sizeof(SYSTEM_CONFIGURATION
);
854 // read the variable into the buffer
856 Status
= mSmmVariable
->SmmGetVariable(
858 &gEfiSetupVariableGuid
,
861 &mSystemConfiguration
863 if (EFI_ERROR(Status
) || VarSize
!= sizeof(SYSTEM_CONFIGURATION
)) {
864 //The setup variable is corrupted
865 VarSize
= sizeof(SYSTEM_CONFIGURATION
);
866 Status
= mSmmVariable
->SmmGetVariable(
868 &gEfiSetupVariableGuid
,
871 &mSystemConfiguration
873 ASSERT_EFI_ERROR (Status
);
876 if (!mSystemConfiguration
.WakeOnRtcS5
) {
879 mWakeupDay
= HexToBcd((UINT8
)mSystemConfiguration
.RTCWakeupDate
);
880 mWakeupHour
= HexToBcd((UINT8
)mSystemConfiguration
.RTCWakeupTimeHour
);
881 mWakeupMinute
= HexToBcd((UINT8
)mSystemConfiguration
.RTCWakeupTimeMinute
);
882 mWakeupSecond
= HexToBcd((UINT8
)mSystemConfiguration
.RTCWakeupTimeSecond
);
885 // Check RTC alarm interrupt is enabled. If enabled, someone already
886 // grabbed RTC alarm. Just return.
888 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_B
);
889 if(IoRead8(PCAT_RTC_DATA_REGISTER
) & B_RTC_ALARM_INT_ENABLE
){
896 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_D
);
897 CmosData
= IoRead8(PCAT_RTC_DATA_REGISTER
);
898 CmosData
&= ~(B_RTC_DATE_ALARM_MASK
);
899 CmosData
|= mWakeupDay
;
900 for(i
= 0 ; i
< 0xffff ; i
++){
901 IoWrite8(PCAT_RTC_DATA_REGISTER
, CmosData
);
903 if(((CmosData
= IoRead8(PCAT_RTC_DATA_REGISTER
)) & B_RTC_DATE_ALARM_MASK
)
912 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_SECOND_ALARM
);
913 for(i
= 0 ; i
< 0xffff ; i
++){
914 IoWrite8(PCAT_RTC_DATA_REGISTER
, mWakeupSecond
);
916 if(IoRead8(PCAT_RTC_DATA_REGISTER
) == mWakeupSecond
){
924 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_MINUTE_ALARM
);
925 for(i
= 0 ; i
< 0xffff ; i
++){
926 IoWrite8(PCAT_RTC_DATA_REGISTER
, mWakeupMinute
);
928 if(IoRead8(PCAT_RTC_DATA_REGISTER
) == mWakeupMinute
){
936 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_HOUR_ALARM
);
937 for(i
= 0 ; i
< 0xffff ; i
++){
938 IoWrite8(PCAT_RTC_DATA_REGISTER
, mWakeupHour
);
940 if(IoRead8(PCAT_RTC_DATA_REGISTER
) == mWakeupHour
){
946 // Wait for UIP to arm RTC alarm
948 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_A
);
949 while (IoRead8(PCAT_RTC_DATA_REGISTER
) & 0x80);
952 // Read RTC register 0C to clear pending RTC interrupts
954 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_C
);
955 IoRead8(PCAT_RTC_DATA_REGISTER
);
958 // Enable RTC Alarm Interrupt
960 IoWrite8(PCAT_RTC_ADDRESS_REGISTER
, RTC_ADDRESS_REGISTER_B
);
961 IoWrite8(PCAT_RTC_DATA_REGISTER
, IoRead8(PCAT_RTC_DATA_REGISTER
) | B_RTC_ALARM_INT_ENABLE
);
964 // Clear ICH RTC Status
966 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_STS
, B_PCH_ACPI_PM1_STS_RTC
);
969 // Enable ICH RTC event
971 IoWrite16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
,
972 (UINT16
)(IoRead16(mAcpiBaseAddr
+ R_PCH_ACPI_PM1_EN
) | B_PCH_ACPI_PM1_EN_RTC
));
983 HighByte
= (UINTN
)HexValue
/ 10;
984 LowByte
= (UINTN
)HexValue
% 10;
986 return ((UINT8
)(LowByte
+ (HighByte
<< 4)));
997 HighByte
= (UINTN
)((BcdValue
>> 4) * 10);
998 LowByte
= (UINTN
)(BcdValue
& 0x0F);
1000 return ((UINT8
)(LowByte
+ HighByte
));