1 /** @file 2 3 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR> 4 5 This program and the accompanying materials are licensed and made available under 7 the terms and conditions of the BSD License that accompanies this distribution. 9 The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php. 13 15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 17 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 19 21 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 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 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; 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 ); 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 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 /** 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 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 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 **/ 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); 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 /** 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; 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