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