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