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