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