]> git.proxmox.com Git - mirror_edk2.git/blob - Vlv2TbltDevicePkg/PlatformSmm/Platform.c
UefiCpuPkg/PiSmmCpuDxeSmm: patch "gSmiCr3" with PatchInstructionX86()
[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) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {
174 //The setup variable is corrupted
175 VarSize = sizeof(SYSTEM_CONFIGURATION);
176 Status = SystemTable->RuntimeServices->GetVariable(
177 L"SetupRecovery",
178 &gEfiSetupVariableGuid,
179 NULL,
180 &VarSize,
181 &mSystemConfiguration
182 );
183 ASSERT_EFI_ERROR (Status);
184 }
185 if (!EFI_ERROR(Status)) {
186 mAcLossVariable = mSystemConfiguration.StateAfterG3;
187
188 //
189 // If LAN is disabled, WOL function should be disabled too.
190 //
191 if (mSystemConfiguration.Lan == 0x01){
192 mWakeOnLanS5Variable = mSystemConfiguration.WakeOnLanS5;
193 } else {
194 mWakeOnLanS5Variable = FALSE;
195 }
196
197 mWakeOnRtcVariable = mSystemConfiguration.WakeOnRtcS5;
198 }
199
200 BootMode = GetBootModeHob ();
201
202 //
203 // Get the Power Button protocol
204 //
205 Status = gBS->LocateProtocol(
206 &gEfiSmmPowerButtonDispatchProtocolGuid,
207 NULL,
208 (void **)&PowerButtonDispatch
209 );
210 ASSERT_EFI_ERROR(Status);
211
212 if (BootMode != BOOT_ON_FLASH_UPDATE) {
213 //
214 // Register for the power button event
215 //
216 PowerButtonContext.Phase = PowerButtonEntry;
217 Status = PowerButtonDispatch->Register(
218 PowerButtonDispatch,
219 PowerButtonCallback,
220 &PowerButtonContext,
221 &Handle
222 );
223 ASSERT_EFI_ERROR(Status);
224 }
225 //
226 // Get the Sx dispatch protocol
227 //
228 Status = gBS->LocateProtocol (
229 &gEfiSmmSxDispatchProtocolGuid,
230 NULL,
231 (void **)&SxDispatch
232 );
233 ASSERT_EFI_ERROR(Status);
234
235 //
236 // Register entry phase call back function
237 //
238 EntryDispatchContext.Type = SxS3;
239 EntryDispatchContext.Phase = SxEntry;
240
241 Status = SxDispatch->Register (
242 SxDispatch,
243 (EFI_SMM_SX_DISPATCH)SxSleepEntryCallBack,
244 &EntryDispatchContext,
245 &Handle
246 );
247
248
249 EntryDispatchContext.Type = SxS4;
250
251 Status = SxDispatch->Register (
252 SxDispatch,
253 S4S5CallBack,
254 &EntryDispatchContext,
255 &Handle
256 );
257 ASSERT_EFI_ERROR(Status);
258
259
260 EntryDispatchContext.Type = SxS5;
261
262 Status = SxDispatch->Register (
263 SxDispatch,
264 S4S5CallBack,
265 &EntryDispatchContext,
266 &Handle
267 );
268 ASSERT_EFI_ERROR(Status);
269
270 Status = SxDispatch->Register (
271 SxDispatch,
272 S5SleepAcLossCallBack,
273 &EntryDispatchContext,
274 &Handle
275 );
276 ASSERT_EFI_ERROR(Status);
277
278 //
279 // Get the Sw dispatch protocol
280 //
281 Status = gBS->LocateProtocol (
282 &gEfiSmmSwDispatchProtocolGuid,
283 NULL,
284 (void **)&SwDispatch
285 );
286 ASSERT_EFI_ERROR(Status);
287
288 //
289 // Register ACPI enable handler
290 //
291 SwContext.SwSmiInputValue = ACPI_ENABLE;
292 Status = SwDispatch->Register (
293 SwDispatch,
294 EnableAcpiCallback,
295 &SwContext,
296 &Handle
297 );
298 ASSERT_EFI_ERROR(Status);
299
300 //
301 // Register ACPI disable handler
302 //
303 SwContext.SwSmiInputValue = ACPI_DISABLE;
304 Status = SwDispatch->Register (
305 SwDispatch,
306 DisableAcpiCallback,
307 &SwContext,
308 &Handle
309 );
310 ASSERT_EFI_ERROR(Status);
311
312
313 //
314 // Register for SmmReadyToBootCallback
315 //
316 SwContext.SwSmiInputValue = SMI_SET_SMMVARIABLE_PROTOCOL;
317 Status = SwDispatch->Register(
318 SwDispatch,
319 SmmReadyToBootCallback,
320 &SwContext,
321 &Handle
322 );
323 ASSERT_EFI_ERROR(Status);
324
325 //
326 // Get the ICHn protocol
327 //
328 Status = gBS->LocateProtocol(
329 &gEfiSmmIchnDispatchProtocolGuid,
330 NULL,
331 (void **)&IchnDispatch
332 );
333 ASSERT_EFI_ERROR(Status);
334
335 //
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
338 //
339 for (Index = 0; Index < sizeof(mTco1Sources)/sizeof(UINT8); Index++) {
340 IchnContext.Type = mTco1Sources[Index];
341 Status = IchnDispatch->Register(
342 IchnDispatch,
343 (EFI_SMM_ICHN_DISPATCH)DummyTco1Callback,
344 &IchnContext,
345 &Handle
346 );
347 ASSERT_EFI_ERROR( Status );
348 }
349
350 //
351 // Lock TCO_EN bit.
352 //
353 IoWrite16( mAcpiBaseAddr + R_PCH_TCO_CNT, IoRead16( mAcpiBaseAddr + R_PCH_TCO_CNT ) | B_PCH_TCO_CNT_LOCK );
354
355 //
356 // Set to power on from G3 dependent on WOL instead of AC Loss variable in order to support WOL from G3 feature.
357 //
358 //
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.
362 //
363 if (mAcLossVariable != 0x00) {
364 SetAfterG3On (TRUE);
365 } else {
366 SetAfterG3On (FALSE);
367 }
368
369
370
371
372 return EFI_SUCCESS;
373 }
374
375 VOID
376 EFIAPI
377 SmmReadyToBootCallback (
378 IN EFI_HANDLE DispatchHandle,
379 IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
380 )
381 {
382 EFI_STATUS Status;
383
384 if (mSetSmmVariableProtocolSmiAllowed)
385 {
386 //
387 // It is okay to use gBS->LocateProtocol here because
388 // we are still in trusted execution.
389 //
390 Status = gBS->LocateProtocol(
391 &gEfiSmmVariableProtocolGuid,
392 NULL,
393 (void **)&mSmmVariable
394 );
395
396 ASSERT_EFI_ERROR(Status);
397
398 //
399 // mSetSmmVariableProtocolSmiAllowed will prevent this function from
400 // being executed more than 1 time.
401 //
402 mSetSmmVariableProtocolSmiAllowed = FALSE;
403 }
404
405 }
406
407 /**
408
409 @param DispatchHandle The handle of this callback, obtained when registering
410 @param DispatchContext The predefined context which contained sleep type and phase
411
412
413 @retval EFI_SUCCESS Operation successfully performed
414
415 **/
416 EFI_STATUS
417 EFIAPI
418 SxSleepEntryCallBack (
419 IN EFI_HANDLE DispatchHandle,
420 IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
421 )
422 {
423 EFI_STATUS Status;
424
425 Status = SaveRuntimeScriptTable ();
426 if (EFI_ERROR(Status)) {
427 return Status;
428 }
429
430 //
431 // Workaround for S3 wake hang if C State is enabled
432 //
433 CpuSmmSxWorkAround();
434
435 return EFI_SUCCESS;
436 }
437
438 VOID
439 CpuSmmSxWorkAround(
440 )
441 {
442 UINT64 MsrValue;
443
444 MsrValue = AsmReadMsr64 (0xE2);
445
446 if (MsrValue & BIT15) {
447 return;
448 }
449
450 if (MsrValue & BIT10) {
451 MsrValue &= ~BIT10;
452 AsmWriteMsr64 (0xE2, MsrValue);
453 }
454 }
455
456 VOID
457 ClearP2PBusMaster(
458 )
459 {
460 UINT8 Command;
461 UINT8 Index;
462
463 for (Index = 0; Index < sizeof(mPciBm)/sizeof(EFI_PCI_BUS_MASTER); Index++) {
464 Command = MmioRead8 (
465 MmPciAddress (0,
466 DEFAULT_PCI_BUS_NUMBER_PCH,
467 mPciBm[Index].Device,
468 mPciBm[Index].Function,
469 PCI_COMMAND_OFFSET
470 )
471 );
472 Command &= ~EFI_PCI_COMMAND_BUS_MASTER;
473 MmioWrite8 (
474 MmPciAddress (0,
475 DEFAULT_PCI_BUS_NUMBER_PCH,
476 mPciBm[Index].Device,
477 mPciBm[Index].Function,
478 PCI_COMMAND_OFFSET
479 ),
480 Command
481 );
482 }
483 }
484
485 /**
486
487 Set the AC Loss to turn on or off.
488
489 **/
490 VOID
491 SetAfterG3On (
492 BOOLEAN Enable
493 )
494 {
495 UINT8 PmCon1;
496
497 //
498 // ICH handling portion
499 //
500 PmCon1 = MmioRead8 ( PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1 );
501 PmCon1 &= ~B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
502 if (Enable) {
503 PmCon1 |= B_PCH_PMC_GEN_PMCON_AFTERG3_EN;
504 }
505 MmioWrite8 (PMC_BASE_ADDRESS + R_PCH_PMC_GEN_PMCON_1, PmCon1);
506
507 }
508
509 /**
510 When a power button event happens, it shuts off the machine
511
512 **/
513 VOID
514 EFIAPI
515 PowerButtonCallback (
516 IN EFI_HANDLE DispatchHandle,
517 IN EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT *DispatchContext
518 )
519 {
520 //
521 // Check what the state to return to after AC Loss. If Last State, then
522 // set it to Off.
523 //
524 UINT16 data16;
525
526 if (mWakeOnRtcVariable) {
527 EnableS5WakeOnRtc();
528 }
529
530 if (mAcLossVariable == 1) {
531 SetAfterG3On (TRUE);
532 }
533
534 ClearP2PBusMaster();
535
536 //
537 // Program clock chip
538 //
539 S4S5ProgClock();
540
541
542 data16 = (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN));
543 data16 &= B_PCH_ACPI_GPE0a_EN_PCI_EXP;
544
545
546 //
547 // Clear Sleep SMI Status
548 //
549 IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_STS,
550 (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_STS) | B_PCH_SMI_STS_ON_SLP_EN));
551 //
552 // Clear Sleep Type Enable
553 //
554 IoWrite16 (mAcpiBaseAddr + R_PCH_SMI_EN,
555 (UINT16)(IoRead16 (mAcpiBaseAddr + R_PCH_SMI_EN) & (~B_PCH_SMI_EN_ON_SLP_EN)));
556
557 //
558 // Clear Power Button Status
559 //
560 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_PWRBTN);
561
562 //
563 // Shut it off now!
564 //
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);
567
568 //
569 // Should not return
570 //
571 CpuDeadLoop();
572 }
573
574
575 /**
576 @param DispatchHandle - The handle of this callback, obtained when registering
577
578 @param DispatchContext - The predefined context which contained sleep type and phase
579
580 **/
581 VOID
582 EFIAPI
583 S5SleepAcLossCallBack (
584 IN EFI_HANDLE DispatchHandle,
585 IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
586 )
587 {
588 //
589 // Check what the state to return to after AC Loss. If Last State, then
590 // set it to Off.
591 //
592 if (mAcLossVariable == 1) {
593 SetAfterG3On (TRUE);
594 }
595 }
596
597 /**
598
599 @param DispatchHandle The handle of this callback, obtained when registering
600 @param DispatchContext The predefined context which contained sleep type and phase
601
602 @retval Clears the Save State bit in the clock.
603
604 **/
605 VOID
606 EFIAPI
607 S4S5CallBack (
608 IN EFI_HANDLE DispatchHandle,
609 IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
610 )
611 {
612
613 UINT32 Data32;
614
615 //
616 // Enable/Disable USB Charging
617 //
618 if (mSystemConfiguration.UsbCharging == 0x01) {
619 Data32 = IoRead32 (GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL);
620 Data32 |= BIT8;
621 IoWrite32(GPIO_BASE_ADDRESS + R_PCH_GPIO_SC_LVL, Data32);
622 }
623
624 }
625
626
627 VOID
628 S4S5ProgClock()
629 {
630 }
631
632 /**
633 SMI handler to enable ACPI mode
634
635 Dispatched on reads from APM port with value 0xA0
636
637 Disables the SW SMI Timer.
638 ACPI events are disabled and ACPI event status is cleared.
639 SCI mode is then enabled.
640
641 Disable SW SMI Timer
642
643 Clear all ACPI event status and disable all ACPI events
644 Disable PM sources except power button
645 Clear status bits
646
647 Disable GPE0 sources
648 Clear status bits
649
650 Disable GPE1 sources
651 Clear status bits
652
653 Guarantee day-of-month alarm is invalid (ACPI 5.0 Section 4.8.2.4 "Real Time Clock Alarm")
654
655 Enable SCI
656
657 @param DispatchHandle - EFI Handle
658 @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
659
660 @retval Nothing
661
662 **/
663 VOID
664 EFIAPI
665 EnableAcpiCallback (
666 IN EFI_HANDLE DispatchHandle,
667 IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
668 )
669 {
670 UINT32 SmiEn;
671 UINT16 Pm1Cnt;
672 UINT16 wordValue;
673 UINT32 RegData32;
674
675 //
676 // Disable SW SMI Timer
677 //
678 SmiEn = IoRead32(mAcpiBaseAddr + R_PCH_SMI_EN);
679 SmiEn &= ~B_PCH_SMI_STS_SWSMI_TMR;
680 IoWrite32(mAcpiBaseAddr + R_PCH_SMI_EN, SmiEn);
681
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);
686 }
687 else {
688 mPM1_SaveState16 = IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN);
689
690 //
691 // Disable PM sources except power button
692 //
693 // power button is enabled only for PCAT. Disabled it on Tablet platform
694 //
695 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, B_PCH_ACPI_PM1_EN_PWRBTN);
696 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);
697
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);
701
702 }
703
704 //
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
707 //
708 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_D);
709 IoWrite8 (PCAT_RTC_DATA_REGISTER, 0x0);
710
711
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);
715
716
717 //
718 // Enable SCI
719 //
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);
723
724
725 }
726
727 /**
728 SMI handler to disable ACPI mode
729
730 Dispatched on reads from APM port with value 0xA1
731
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
736 Clear status bits
737 Disable GPE0 sources
738 Clear status bits
739 Disable GPE1 sources
740 Clear status bits
741 Disable SCI
742
743 @param DispatchHandle - EFI Handle
744 @param DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
745
746 @retval Nothing
747
748 **/
749 VOID
750 EFIAPI
751 DisableAcpiCallback (
752 IN EFI_HANDLE DispatchHandle,
753 IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext
754 )
755 {
756 UINT16 Pm1Cnt;
757
758 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, 0xffff);
759 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN, mPM1_SaveState16);
760
761 IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS, 0xffffffff);
762 IoWrite32(mAcpiBaseAddr + R_PCH_ACPI_GPE0a_EN, mGPE_SaveState32);
763
764 //
765 // Disable SCI
766 //
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);
770
771 }
772
773 /**
774 When an unknown event happen.
775
776 @retval None
777
778 **/
779 VOID
780 DummyTco1Callback (
781 IN EFI_HANDLE DispatchHandle,
782 IN EFI_SMM_ICHN_DISPATCH_CONTEXT *DispatchContext
783 )
784 {
785 }
786
787 UINTN
788 DevicePathSize (
789 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
790 )
791 {
792 EFI_DEVICE_PATH_PROTOCOL *Start;
793
794 if (DevicePath == NULL) {
795 return 0;
796 }
797
798 //
799 // Search for the end of the device path structure
800 //
801 Start = DevicePath;
802 while (!IsDevicePathEnd (DevicePath)) {
803 DevicePath = NextDevicePathNode (DevicePath);
804 }
805
806 //
807 // Compute the size and add back in the size of the end device path structure
808 //
809 return ((UINTN)DevicePath - (UINTN)Start) + sizeof(EFI_DEVICE_PATH_PROTOCOL);
810 }
811
812 /**
813
814 @param DispatchHandle The handle of this callback, obtained when registering
815 @param DispatchContext The predefined context which contained sleep type and phase
816
817 **/
818 VOID
819 S5SleepWakeOnRtcCallBack (
820 IN EFI_HANDLE DispatchHandle,
821 IN EFI_SMM_SX_DISPATCH_CONTEXT *DispatchContext
822 )
823 {
824 EnableS5WakeOnRtc();
825 }
826
827 /**
828
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)
834
835 **/
836 VOID
837 EnableS5WakeOnRtc()
838 {
839 UINT8 CmosData;
840 UINTN i;
841 EFI_STATUS Status;
842 UINTN VarSize;
843
844 //
845 // make sure EFI_SMM_VARIABLE_PROTOCOL is available
846 //
847 if (!mSmmVariable) {
848 return;
849 }
850
851 VarSize = sizeof(SYSTEM_CONFIGURATION);
852
853 //
854 // read the variable into the buffer
855 //
856 Status = mSmmVariable->SmmGetVariable(
857 L"Setup",
858 &gEfiSetupVariableGuid,
859 NULL,
860 &VarSize,
861 &mSystemConfiguration
862 );
863 if (EFI_ERROR(Status) || VarSize != sizeof(SYSTEM_CONFIGURATION)) {
864 //The setup variable is corrupted
865 VarSize = sizeof(SYSTEM_CONFIGURATION);
866 Status = mSmmVariable->SmmGetVariable(
867 L"SetupRecovery",
868 &gEfiSetupVariableGuid,
869 NULL,
870 &VarSize,
871 &mSystemConfiguration
872 );
873 ASSERT_EFI_ERROR (Status);
874 }
875
876 if (!mSystemConfiguration.WakeOnRtcS5) {
877 return;
878 }
879 mWakeupDay = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupDate);
880 mWakeupHour = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeHour);
881 mWakeupMinute = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeMinute);
882 mWakeupSecond = HexToBcd((UINT8)mSystemConfiguration.RTCWakeupTimeSecond);
883
884 //
885 // Check RTC alarm interrupt is enabled. If enabled, someone already
886 // grabbed RTC alarm. Just return.
887 //
888 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_B);
889 if(IoRead8(PCAT_RTC_DATA_REGISTER) & B_RTC_ALARM_INT_ENABLE){
890 return;
891 }
892
893 //
894 // Set Date
895 //
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);
902 SmmStall(1);
903 if(((CmosData = IoRead8(PCAT_RTC_DATA_REGISTER)) & B_RTC_DATE_ALARM_MASK)
904 == mWakeupDay){
905 break;
906 }
907 }
908
909 //
910 // Set Second
911 //
912 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_SECOND_ALARM);
913 for(i = 0 ; i < 0xffff ; i++){
914 IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupSecond);
915 SmmStall(1);
916 if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupSecond){
917 break;
918 }
919 }
920
921 //
922 // Set Minute
923 //
924 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_MINUTE_ALARM);
925 for(i = 0 ; i < 0xffff ; i++){
926 IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupMinute);
927 SmmStall(1);
928 if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupMinute){
929 break;
930 }
931 }
932
933 //
934 // Set Hour
935 //
936 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_HOUR_ALARM);
937 for(i = 0 ; i < 0xffff ; i++){
938 IoWrite8(PCAT_RTC_DATA_REGISTER, mWakeupHour);
939 SmmStall(1);
940 if(IoRead8(PCAT_RTC_DATA_REGISTER) == mWakeupHour){
941 break;
942 }
943 }
944
945 //
946 // Wait for UIP to arm RTC alarm
947 //
948 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_A);
949 while (IoRead8(PCAT_RTC_DATA_REGISTER) & 0x80);
950
951 //
952 // Read RTC register 0C to clear pending RTC interrupts
953 //
954 IoWrite8(PCAT_RTC_ADDRESS_REGISTER, RTC_ADDRESS_REGISTER_C);
955 IoRead8(PCAT_RTC_DATA_REGISTER);
956
957 //
958 // Enable RTC Alarm Interrupt
959 //
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);
962
963 //
964 // Clear ICH RTC Status
965 //
966 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_STS, B_PCH_ACPI_PM1_STS_RTC);
967
968 //
969 // Enable ICH RTC event
970 //
971 IoWrite16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN,
972 (UINT16)(IoRead16(mAcpiBaseAddr + R_PCH_ACPI_PM1_EN) | B_PCH_ACPI_PM1_EN_RTC));
973 }
974
975 UINT8
976 HexToBcd(
977 IN UINT8 HexValue
978 )
979 {
980 UINTN HighByte;
981 UINTN LowByte;
982
983 HighByte = (UINTN)HexValue / 10;
984 LowByte = (UINTN)HexValue % 10;
985
986 return ((UINT8)(LowByte + (HighByte << 4)));
987 }
988
989 UINT8
990 BcdToHex(
991 IN UINT8 BcdValue
992 )
993 {
994 UINTN HighByte;
995 UINTN LowByte;
996
997 HighByte = (UINTN)((BcdValue >> 4) * 10);
998 LowByte = (UINTN)(BcdValue & 0x0F);
999
1000 return ((UINT8)(LowByte + HighByte));
1001 }
1002