]> git.proxmox.com Git - mirror_edk2.git/blob - Vlv2TbltDevicePkg/PlatformSmm/Platform.c
Upload BSD-licensed Vlv2TbltDevicePkg and Vlv2DeviceRefCodePkg to
[mirror_edk2.git] / Vlv2TbltDevicePkg / PlatformSmm / Platform.c
1 /** @file
2
3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
4
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.
9
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.
12
13
14 Module Name:
15
16 Platform.c
17
18 Abstract:
19
20 This is a generic template for a child of the IchSmm driver.
21
22
23 --*/
24
25 #include "SmmPlatform.h"
26 #include <Protocol/CpuIo2.h>
27
28
29 //
30 // Local variables
31 //
32 typedef struct {
33 UINT8 Device;
34 UINT8 Function;
35 } EFI_PCI_BUS_MASTER;
36
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 }
43 };
44
45
46 UINT16 mAcpiBaseAddr;
47 SYSTEM_CONFIGURATION mSystemConfiguration;
48 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
49 EFI_GLOBAL_NVS_AREA_PROTOCOL *mGlobalNvsAreaPtr;
50
51 UINT16 mPM1_SaveState16;
52 UINT32 mGPE_SaveState32;
53
54 BOOLEAN mSetSmmVariableProtocolSmiAllowed = TRUE;
55
56
57 //
58 // Variables. Need to initialize this from Setup
59 //
60 BOOLEAN mWakeOnLanS5Variable;
61 BOOLEAN mWakeOnRtcVariable;
62 UINT8 mWakeupDay;
63 UINT8 mWakeupHour;
64 UINT8 mWakeupMinute;
65 UINT8 mWakeupSecond;
66
67 //
68 // Use an enum. 0 is Stay Off, 1 is Last State, 2 is Stay On
69 //
70 UINT8 mAcLossVariable;
71
72
73 static
74 UINT8 mTco1Sources[] = {
75 IchnNmi
76 };
77
78 UINTN
79 DevicePathSize (
80 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
81 );
82
83 VOID
84 S4S5ProgClock();
85
86 EFI_STATUS
87 InitRuntimeScriptTable (
88 IN EFI_SYSTEM_TABLE *SystemTable
89 );
90
91 VOID
92 S5SleepWakeOnRtcCallBack (
93 IN EFI_HANDLE DispatchHandle,
94 IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
95 );
96
97
98 VOID
99 EnableS5WakeOnRtc();
100
101 UINT8
102 HexToBcd(
103 UINT8 HexValue
104 );
105
106 UINT8
107 BcdToHex(
108 IN UINT8 BcdValue
109 );
110
111
112 VOID
113 CpuSmmSxWorkAround(
114 );
115
116 /**
117 Initializes the SMM Handler Driver
118
119 @param ImageHandle
120 @param SystemTable
121
122 @retval None
123
124 **/
125 EFI_STATUS
126 EFIAPI
127 InitializePlatformSmm (
128 IN EFI_HANDLE ImageHandle,
129 IN EFI_SYSTEM_TABLE *SystemTable
130 )
131 {
132 EFI_STATUS Status;
133 UINT8 Index;
134 EFI_HANDLE Handle;
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;
143 UINTN VarSize;
144 EFI_BOOT_MODE BootMode;
145
146 Handle = NULL;
147
148 //
149 // Locate the Global NVS Protocol.
150 //
151 Status = gBS->LocateProtocol (
152 &gEfiGlobalNvsAreaProtocolGuid,
153 NULL,
154 (void **)&mGlobalNvsAreaPtr
155 );
156 ASSERT_EFI_ERROR (Status);
157
158
159 //
160 // Get the ACPI Base Address
161 //
162
163 mAcpiBaseAddr = PchLpcPciCfg16( R_PCH_LPC_ACPI_BASE ) & B_PCH_LPC_ACPI_BASE_BAR;
164
165 VarSize = sizeof(SYSTEM_CONFIGURATION);
166 Status = SystemTable->RuntimeServices->GetVariable(
167 L"Setup",
168 &gEfiSetupVariableGuid,
169 NULL,
170 &VarSize,
171 &mSystemConfiguration
172 );
173 if (!EFI_ERROR(Status)) {
174 mAcLossVariable = mSystemConfiguration.StateAfterG3;
175
176 //
177 // If LAN is disabled, WOL function should be disabled too.
178 //
179 if (mSystemConfiguration.Lan == 0x01){
180 mWakeOnLanS5Variable = mSystemConfiguration.WakeOnLanS5;
181 } else {
182 mWakeOnLanS5Variable = FALSE;
183 }
184
185 mWakeOnRtcVariable = mSystemConfiguration.WakeOnRtcS5;
186 }
187
188 BootMode = GetBootModeHob ();
189
190 //
191 // Get the Power Button protocol
192 //
193 Status = gBS->LocateProtocol(
194 &gEfiSmmPowerButtonDispatchProtocolGuid,
195 NULL,
196 (void **)&PowerButtonDispatch
197 );
198 ASSERT_EFI_ERROR(Status);
199
200 if (BootMode != BOOT_ON_FLASH_UPDATE) {
201 //
202 // Register for the power button event
203 //
204 PowerButtonContext.Phase = PowerButtonEntry;
205 Status = PowerButtonDispatch->Register(
206 PowerButtonDispatch,
207 PowerButtonCallback,
208 &PowerButtonContext,
209 &Handle
210 );
211 ASSERT_EFI_ERROR(Status);
212 }
213 //
214 // Get the Sx dispatch protocol
215 //
216 Status = gBS->LocateProtocol (
217 &gEfiSmmSxDispatchProtocolGuid,
218 NULL,
219 (void **)&SxDispatch
220 );
221 ASSERT_EFI_ERROR(Status);
222
223 //
224 // Register entry phase call back function
225 //
226 EntryDispatchContext.Type = SxS3;
227 EntryDispatchContext.Phase = SxEntry;
228
229 Status = SxDispatch->Register (
230 SxDispatch,
231 (EFI_SMM_SX_DISPATCH)SxSleepEntryCallBack,
232 &EntryDispatchContext,
233 &Handle
234 );
235
236
237 EntryDispatchContext.Type = SxS4;
238
239 Status = SxDispatch->Register (
240 SxDispatch,
241 S4S5CallBack,
242 &EntryDispatchContext,
243 &Handle
244 );
245 ASSERT_EFI_ERROR(Status);
246
247
248 EntryDispatchContext.Type = SxS5;
249
250 Status = SxDispatch->Register (
251 SxDispatch,
252 S4S5CallBack,
253 &EntryDispatchContext,
254 &Handle
255 );
256 ASSERT_EFI_ERROR(Status);
257
258 Status = SxDispatch->Register (
259 SxDispatch,
260 S5SleepAcLossCallBack,
261 &EntryDispatchContext,
262 &Handle
263 );
264 ASSERT_EFI_ERROR(Status);
265
266 //
267 // Get the Sw dispatch protocol
268 //
269 Status = gBS->LocateProtocol (
270 &gEfiSmmSwDispatchProtocolGuid,
271 NULL,
272 (void **)&SwDispatch
273 );
274 ASSERT_EFI_ERROR(Status);
275
276 //
277 // Register ACPI enable handler
278 //
279 SwContext.SwSmiInputValue = ACPI_ENABLE;
280 Status = SwDispatch->Register (
281 SwDispatch,
282 EnableAcpiCallback,
283 &SwContext,
284 &Handle
285 );
286 ASSERT_EFI_ERROR(Status);
287
288 //
289 // Register ACPI disable handler
290 //
291 SwContext.SwSmiInputValue = ACPI_DISABLE;
292 Status = SwDispatch->Register (
293 SwDispatch,
294 DisableAcpiCallback,
295 &SwContext,
296 &Handle
297 );
298 ASSERT_EFI_ERROR(Status);
299
300
301 //
302 // Register for SmmReadyToBootCallback
303 //
304 SwContext.SwSmiInputValue = SMI_SET_SMMVARIABLE_PROTOCOL;
305 Status = SwDispatch->Register(
306 SwDispatch,
307 SmmReadyToBootCallback,
308 &SwContext,
309 &Handle
310 );
311 ASSERT_EFI_ERROR(Status);
312
313 //
314 // Get the ICHn protocol
315 //
316 Status = gBS->LocateProtocol(
317 &gEfiSmmIchnDispatchProtocolGuid,
318 NULL,
319 (void **)&IchnDispatch
320 );
321 ASSERT_EFI_ERROR(Status);
322
323 //
324 // Register for the events that may happen that we do not care.
325 // This is true for SMI related to TCO since TCO is enabled by BIOS WP
326 //
327 for (Index = 0; Index < sizeof(mTco1Sources)/sizeof(UINT8); Index++) {
328 IchnContext.Type = mTco1Sources[Index];
329 Status = IchnDispatch->Register(
330 IchnDispatch,
331 (EFI_SMM_ICHN_DISPATCH)DummyTco1Callback,
332 &IchnContext,
333 &Handle
334 );
335 ASSERT_EFI_ERROR( Status );
336 }
337
338 //
339 // Lock TCO_EN bit.
340 //
341 IoWrite16( mAcpiBaseAddr + R_PCH_TCO_CNT, IoRead16( mAcpiBaseAddr + R_PCH_TCO_CNT ) | B_PCH_TCO_CNT_LOCK );
342
343 //
344 // Set to power on from G3 dependent on WOL instead of AC Loss variable in order to support WOL from G3 feature.
345 //
346 //
347 // Set wake from G3 dependent on AC Loss variable and Wake On LAN variable.
348 // 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.
349 // This needs to be done after LAN enable/disable so that the PWR_FLR state clear not impacted the WOL from G3 feature.
350 //
351 if (mAcLossVariable != 0x00) {
352 SetAfterG3On (TRUE);
353 } else {
354 SetAfterG3On (FALSE);
355 }
356
357
358
359
360 return EFI_SUCCESS;
361 }
362
363 VOID
364 EFIAPI
365 SmmReadyToBootCallback (
366 IN EFI_HANDLE DispatchHandle,
367 IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
368 )
369 {
370 EFI_STATUS Status;
371
372 if (mSetSmmVariableProtocolSmiAllowed)
373 {
374 //
375 // It is okay to use gBS->LocateProtocol here because
376 // we are still in trusted execution.
377 //
378 Status = gBS->LocateProtocol(
379 &gEfiSmmVariableProtocolGuid,
380 NULL,
381 (void **)&mSmmVariable
382 );
383
384 ASSERT_EFI_ERROR(Status);
385
386 //
387 // mSetSmmVariableProtocolSmiAllowed will prevent this function from
388 // being executed more than 1 time.
389 //
390 mSetSmmVariableProtocolSmiAllowed = FALSE;
391 }
392
393 }
394
395 /**
396
397 @param DispatchHandle The handle of this callback, obtained when registering
398 @param DispatchContext The predefined context which contained sleep type and phase
399
400
401 @retval EFI_SUCCESS Operation successfully performed
402
403 **/
404 EFI_STATUS
405 EFIAPI
406 SxSleepEntryCallBack (
407 IN EFI_HANDLE DispatchHandle,
408 IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
409 )
410 {
411 EFI_STATUS Status;
412
413 Status = SaveRuntimeScriptTable ();
414 if (EFI_ERROR(Status)) {
415 return Status;
416 }
417
418 //
419 // Workaround for S3 wake hang if C State is enabled
420 //
421 CpuSmmSxWorkAround();
422
423 return EFI_SUCCESS;
424 }
425
426 VOID
427 CpuSmmSxWorkAround(
428 )
429 {
430 UINT64 MsrValue;
431
432 MsrValue = AsmReadMsr64 (0xE2);
433
434 if (MsrValue & BIT15) {
435 return;
436 }
437
438 if (MsrValue & BIT10) {
439 MsrValue &= ~BIT10;
440 AsmWriteMsr64 (0xE2, MsrValue);
441 }
442 }
443
444 VOID
445 ClearP2PBusMaster(
446 )
447 {
448 UINT8 Command;
449 UINT8 Index;
450
451 for (Index = 0; Index < sizeof(mPciBm)/sizeof(EFI_PCI_BUS_MASTER); Index++) {
452 Command = MmioRead8 (
453 MmPciAddress (0,
454 DEFAULT_PCI_BUS_NUMBER_PCH,
455 mPciBm[Index].Device,
456 mPciBm[Index].Function,
457 PCI_COMMAND_OFFSET
458 )
459 );
460 Command &= ~EFI_PCI_COMMAND_BUS_MASTER;
461 MmioWrite8 (
462 MmPciAddress (0,
463 DEFAULT_PCI_BUS_NUMBER_PCH,
464 mPciBm[Index].Device,
465 mPciBm[Index].Function,
466 PCI_COMMAND_OFFSET
467 ),
468 Command
469 );
470 }
471 }
472
473 /**
474
475 Set the AC Loss to turn on or off.
476
477 **/
478 VOID
479 SetAfterG3On (
480 BOOLEAN Enable
481 )
482 {
483 UINT8 PmCon1;
484
485 //
486 // ICH handling portion
487 //
488 PmCon1 = MmioRead8 ( PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1 );
489 PmCon1 &= ~B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
490 if (Enable) {
491 PmCon1 |= B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
492 }
493 MmioWrite8 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1, PmCon1);
494
495 }
496
497 /**
498 When a power button event happens, it shuts off the machine
499
500 **/
501 VOID
502 EFIAPI
503 PowerButtonCallback (
504 IN EFI_HANDLE DispatchHandle,
505 IN EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT *DispatchContext
506 )
507 {
508 //
509 // Check what the state to return to after AC Loss. If Last State, then
510 // set it to Off.
511 //
512 UINT16 data16;
513
514 if (mWakeOnRtcVariable) {
515 EnableS5WakeOnRtc();
516 }
517
518 if (mAcLossVariable == 1) {
519 SetAfterG3On (TRUE);
520 }
521
522 ClearP2PBusMaster();
523
524 //
525 // Program clock chip
526 //
527 S4S5ProgClock();
528
529
530 data16 = (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN));
531 data16 &= B_PCH_ACPI_GPE0a_EN_PCI_EXP;
532
533
534 //
535 // Clear Sleep SMI Status
536 //
537 IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_STS,
538 (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_STS) | B_PCH_SMI_STS_ON_SLP_EN));
539 //
540 // Clear Sleep Type Enable
541 //
542 IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_EN,
543 (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_EN) & (~B_PCH_SMI_EN_ON_SLP_EN)));
544
545 //
546 // Clear Power Button Status
547 //
548 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_PWRBTN);
549
550 //
551 // Shut it off now!
552 //
553 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, V_PCH_ACPI_PM1_CNT_S5);
554 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, B_PCH_ACPI_PM1_CNT_SLP_EN | V_PCH_ACPI_PM1_CNT_S5);
555
556 //
557 // Should not return
558 //
559 CpuDeadLoop();
560 }
561
562
563 /**
564 @param DispatchHandle - The handle of this callback, obtained when registering
565
566 @param DispatchContext - The predefined context which contained sleep type and phase
567
568 **/
569 VOID
570 EFIAPI
571 S5SleepAcLossCallBack (
572 IN EFI_HANDLE DispatchHandle,
573 IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
574 )
575 {
576 //
577 // Check what the state to return to after AC Loss. If Last State, then
578 // set it to Off.
579 //
580 if (mAcLossVariable == 1) {
581 SetAfterG3On (TRUE);
582 }
583 }
584
585 /**
586
587 @param DispatchHandle The handle of this callback, obtained when registering
588 @param DispatchContext The predefined context which contained sleep type and phase
589
590 @retval Clears the Save State bit in the clock.
591
592 **/
593 VOID
594 EFIAPI
595 S4S5CallBack (
596 IN EFI_HANDLE DispatchHandle,
597 IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
598 )
599 {
600
601 UINT32 Data32;
602
603 //
604 // Enable/Disable USB Charging
605 //
606 if (mSystemConfiguration.UsbCharging == 0x01) {
607 Data32 = IoRead32 (GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL);
608 Data32 |= BIT8;
609 IoWrite32(GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL, Data32);
610 }
611
612 }
613
614
615 VOID
616 S4S5ProgClock()
617 {
618 }
619
620 /**
621 SMI handler to enable ACPI mode
622
623 Dispatched on reads from APM port with value 0xA0
624
625 Disables the SW SMI Timer.
626 ACPI events are disabled and ACPI event status is cleared.
627 SCI mode is then enabled.
628
629 Disable SW SMI Timer
630
631 Clear all ACPI event status and disable all ACPI events
632 Disable PM sources except power button
633 Clear status bits
634
635 Disable GPE0 sources
636 Clear status bits
637
638 Disable GPE1 sources
639 Clear status bits
640
641 Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
642
643 Enable SCI
644
645 @param DispatchHandle - EFI Handle
646 @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
647
648 @retval Nothing
649
650 **/
651 VOID
652 EFIAPI
653 EnableAcpiCallback (
654 IN EFI_HANDLE DispatchHandle,
655 IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
656 )
657 {
658 UINT32 SmiEn;
659 UINT16 Pm1Cnt;
660 UINT16 wordValue;
661 UINT32 RegData32;
662
663 //
664 // Disable SW SMI Timer
665 //
666 SmiEn = IoRead32(mAcpiBaseAddr + R_PCH_SMI_EN);
667 SmiEn &= ~B_PCH_SMI_STS_SWSMI_TMR;
668 IoWrite32(mAcpiBaseAddr + R_PCH_SMI_EN, SmiEn);
669
670 wordValue = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS);
671 if(wordValue & B_PCH_ACPI_PM1_STS_WAK) {
672 IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN), 0x0000);
673 IoWrite32((mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS), 0xffffffff);
674 }
675 else {
676 mPM1_SaveState16 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN);
677
678 //
679 // Disable PM sources except power button
680 //
681 // power button is enabled only for PCAT. Disabled it on Tablet platform
682 //
683 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, B_PCH_ACPI_PM1_EN_PWRBTN);
684 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);
685
686 mGPE_SaveState32 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN);
687 IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, 0x0000);
688 IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff);
689
690 }
691
692 //
693 // Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
694 // Clear Status D reg VM bit, Date of month Alarm to make Data in CMOS RAM is no longer Valid
695 //
696 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D);
697 IoWrite8 (PCAT_RTC_DATA_REGISTER, 0x0);
698
699
700 RegData32 = IoRead32(ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN);
701 RegData32 &= ~(BIT7);
702 IoWrite32((ACPI_BASE_ADDRESS + R_PCH_ALT_GP_SMI_EN), RegData32);
703
704
705 //
706 // Enable SCI
707 //
708 Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT);
709 Pm1Cnt |= B_PCH_ACPI_PM1_CNT_SCI_EN;
710 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt);
711
712
713 }
714
715 /**
716 SMI handler to disable ACPI mode
717
718 Dispatched on reads from APM port with value 0xA1
719
720 ACPI events are disabled and ACPI event status is cleared.
721 SCI mode is then disabled.
722 Clear all ACPI event status and disable all ACPI events
723 Disable PM sources except power button
724 Clear status bits
725 Disable GPE0 sources
726 Clear status bits
727 Disable GPE1 sources
728 Clear status bits
729 Disable SCI
730
731 @param DispatchHandle - EFI Handle
732 @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
733
734 @retval Nothing
735
736 **/
737 VOID
738 EFIAPI
739 DisableAcpiCallback (
740 IN EFI_HANDLE DispatchHandle,
741 IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
742 )
743 {
744 UINT16 Pm1Cnt;
745
746 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);
747 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, mPM1_SaveState16);
748
749 IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff);
750 IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, mGPE_SaveState32);
751
752 //
753 // Disable SCI
754 //
755 Pm1Cnt = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT);
756 Pm1Cnt &= ~B_PCH_ACPI_PM1_CNT_SCI_EN;
757 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT, Pm1Cnt);
758
759 }
760
761 /**
762 When an unknown event happen.
763
764 @retval None
765
766 **/
767 VOID
768 DummyTco1Callback (
769 IN EFI_HANDLE DispatchHandle,
770 IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext
771 )
772 {
773 }
774
775 UINTN
776 DevicePathSize (
777 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
778 )
779 {
780 EFI_DEVICE_PATH_PROTOCOL *Start;
781
782 if (DevicePath == NULL) {
783 return 0;
784 }
785
786 //
787 // Search for the end of the device path structure
788 //
789 Start = DevicePath;
790 while (!IsDevicePathEnd (DevicePath)) {
791 DevicePath = NextDevicePathNode (DevicePath);
792 }
793
794 //
795 // Compute the size and add back in the size of the end device path structure
796 //
797 return ((UINTN)DevicePath - (UINTN)Start) + sizeof(EFI_DEVICE_PATH_PROTOCOL);
798 }
799
800 /**
801
802 @param DispatchHandle The handle of this callback, obtained when registering
803 @param DispatchContext The predefined context which contained sleep type and phase
804
805 **/
806 VOID
807 S5SleepWakeOnRtcCallBack (
808 IN EFI_HANDLE DispatchHandle,
809 IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
810 )
811 {
812 EnableS5WakeOnRtc();
813 }
814
815 /**
816
817 @retval 1. Check Alarm interrupt is not set.
818 2. Clear Alarm interrupt.
819 2. Set RTC wake up date and time.
820 2. Enable RTC wake up alarm.
821 3. Enable ICH PM1 EN Bit 10(RTC_EN)
822
823 **/
824 VOID
825 EnableS5WakeOnRtc()
826 {
827 UINT8 CmosData;
828 UINTN i;
829 EFI_STATUS Status;
830 UINTN VarSize;
831
832 //
833 // make sure EFI_SMM_VARIABLE_PROTOCOL is available
834 //
835 if (!mSmmVariable) {
836 return;
837 }
838
839 VarSize = sizeof(SYSTEM_CONFIGURATION);
840
841 //
842 // read the variable into the buffer
843 //
844 Status = mSmmVariable->SmmGetVariable(
845 L"Setup",
846 &gEfiSetupVariableGuid,
847 NULL,
848 &VarSize,
849 &mSystemConfiguration
850 );
851 if (EFI_ERROR(Status) || (!mSystemConfiguration.WakeOnRtcS5)) {
852 return;
853 }
854 mWakeupDay = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupDate);
855 mWakeupHour = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeHour);
856 mWakeupMinute = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeMinute);
857 mWakeupSecond = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeSecond);
858
859 //
860 // Check RTC alarm interrupt is enabled. If enabled, someone already
861 // grabbed RTC alarm. Just return.
862 //
863 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
864 if(IoRead8(PCAT_RTC_DATA_REGISTER) & B_RTC_ALARM_INT_ENABLE){
865 return;
866 }
867
868 //
869 // Set Date
870 //
871 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D);
872 CmosData = IoRead8(PCAT_RTC_DATA_REGISTER);
873 CmosData &= ~(B_RTC_DATE_ALARM_MASK);
874 CmosData |= mWakeupDay ;
875 for(i = 0 ; i < 0xffff ; i++){
876 IoWrite8(PCAT_RTC_DATA_REGISTER, CmosData);
877 SmmStall(1);
878 if(((CmosData = IoRead8(PCAT_RTC_DATA_REGISTER)) & B_RTC_DATE_ALARM_MASK)
879 == mWakeupDay){
880 break;
881 }
882 }
883
884 //
885 // Set Second
886 //
887 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECOND_ALARM);
888 for(i = 0 ; i < 0xffff ; i++){
889 IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupSecond);
890 SmmStall(1);
891 if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupSecond){
892 break;
893 }
894 }
895
896 //
897 // Set Minute
898 //
899 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTE_ALARM);
900 for(i = 0 ; i < 0xffff ; i++){
901 IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupMinute);
902 SmmStall(1);
903 if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupMinute){
904 break;
905 }
906 }
907
908 //
909 // Set Hour
910 //
911 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOUR_ALARM);
912 for(i = 0 ; i < 0xffff ; i++){
913 IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupHour);
914 SmmStall(1);
915 if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupHour){
916 break;
917 }
918 }
919
920 //
921 // Wait for UIP to arm RTC alarm
922 //
923 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
924 while (IoRead8(PCAT_RTC_DATA_REGISTER) & 0x80);
925
926 //
927 // Read RTC register 0C to clear pending RTC interrupts
928 //
929 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
930 IoRead8(PCAT_RTC_DATA_REGISTER);
931
932 //
933 // Enable RTC Alarm Interrupt
934 //
935 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
936 IoWrite8(PCAT_RTC_DATA_REGISTER, IoRead8(PCAT_RTC_DATA_REGISTER) | B_RTC_ALARM_INT_ENABLE);
937
938 //
939 // Clear ICH RTC Status
940 //
941 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_RTC);
942
943 //
944 // Enable ICH RTC event
945 //
946 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN,
947 (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN) | B_PCH_ACPI_PM1_EN_RTC));
948 }
949
950 UINT8
951 HexToBcd(
952 IN UINT8 HexValue
953 )
954 {
955 UINTN HighByte;
956 UINTN LowByte;
957
958 HighByte = (UINTN)HexValue / 10;
959 LowByte = (UINTN)HexValue % 10;
960
961 return ((UINT8)(LowByte + (HighByte << 4)));
962 }
963
964 UINT8
965 BcdToHex(
966 IN UINT8 BcdValue
967 )
968 {
969 UINTN HighByte;
970 UINTN LowByte;
971
972 HighByte = (UINTN)((BcdValue >> 4) * 10);
973 LowByte = (UINTN)(BcdValue & 0x0F);
974
975 return ((UINT8)(LowByte + HighByte));
976 }
977