Home | History | Annotate | Download | only in PlatformSmm
      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