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