Home | History | Annotate | Download | only in AcpiSmm
      1 /** @file
      2 ACPISMM Driver implementation file.
      3 
      4 This is QNC Smm platform driver
      5 
      6 Copyright (c) 2013-2016 Intel Corporation.
      7 
      8 This program and the accompanying materials
      9 are licensed and made available under the terms and conditions of the BSD License
     10 which accompanies this distribution.  The full text of the license may be found at
     11 http://opensource.org/licenses/bsd-license.php
     12 
     13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     15 
     16 
     17 **/
     18 
     19 #include <AcpiSmmPlatform.h>
     20 
     21 #define PCILIB_TO_COMMON_ADDRESS(Address) \
     22         ((UINT64) ((((UINTN) ((Address>>20) & 0xff)) << 24) + (((UINTN) ((Address>>15) & 0x1f)) << 16) + (((UINTN) ((Address>>12) & 0x07)) << 8) + ((UINTN) (Address & 0xfff ))))
     23 
     24 //
     25 // Modular variables needed by this driver
     26 //
     27 EFI_ACPI_SMM_DEV                 mAcpiSmm;
     28 
     29 UINT8  mPciCfgRegTable[] = {
     30   //
     31   // Logic to decode the table masks to arrive at the registers saved
     32   // Dword Registers are saved. For a given mask, the Base+offset register
     33   // will be saved as in the table below.
     34   // (example) To save register 0x24, 0x28 the mask at the Base 0x20 will be 0x06
     35   //     Base      0x00   0x20   0x40  0x60  0x80  0xA0  0xC0  0xE0
     36   // Mask  offset
     37   // 0x01   0x00
     38   // 0x02   0x04
     39   // 0x04   0x08
     40   // 0x08   0x0C
     41   // 0x10   0x10
     42   // 0x20   0x14
     43   // 0x40   0x18
     44   // 0x80   0x1C
     45   //
     46 
     47   //
     48   // Bus,   Dev,  Func,
     49   // 00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF
     50   // Only Bus 0 device is supported now
     51   //
     52 
     53   //
     54   // Quark South Cluster devices
     55   //
     56   PCI_DEVICE   (0, 20, 0),
     57   PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     58 
     59   PCI_DEVICE   (0, 20, 1),
     60   PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     61 
     62   PCI_DEVICE   (0, 20, 2),
     63   PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     64 
     65   PCI_DEVICE   (0, 20, 3),
     66   PCI_REG_MASK (0x18, 0x98, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00),
     67 
     68   PCI_DEVICE   (0, 20, 4),
     69   PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     70 
     71   PCI_DEVICE   (0, 20, 5),
     72   PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     73 
     74   PCI_DEVICE   (0, 20, 6),
     75   PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     76 
     77   PCI_DEVICE   (0, 20, 7),
     78   PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     79 
     80   PCI_DEVICE   (0, 21, 0),
     81   PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     82 
     83   PCI_DEVICE   (0, 21, 1),
     84   PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     85 
     86   PCI_DEVICE   (0, 21, 2),
     87   PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     88 
     89   //
     90   // Quark North Cluster devices
     91   //
     92   PCI_DEVICE   (0, 0, 0),
     93   PCI_REG_MASK (0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),
     94 
     95   PCI_DEVICE   (0, 23, 0),
     96   PCI_REG_MASK (0xC0, 0x8F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00),
     97 
     98   PCI_DEVICE   (0, 23, 1),
     99   PCI_REG_MASK (0xC0, 0x8F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00),
    100 
    101   PCI_DEVICE   (0, 31, 0),
    102   PCI_REG_MASK (0x00, 0x08, 0x4E, 0x03, 0x02, 0x00, 0x60, 0x10),
    103 
    104   PCI_DEVICE_END
    105 };
    106 
    107 EFI_PLATFORM_TYPE                         mPlatformType;
    108 
    109   // These registers have to set in byte order
    110 const UINT8  QNCS3SaveExtReg[] = {
    111     QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, // SMRAM settings
    112 
    113     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL,
    114     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXH,
    115     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM,
    116     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXWM,
    117 
    118     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXL,
    119     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXH,
    120     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXRM,
    121     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXWM,
    122 
    123     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXL,
    124     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXH,
    125     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXRM,
    126     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXWM,
    127 
    128     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXL,
    129     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXH,
    130     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXRM,
    131     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXWM,
    132 
    133     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXL,
    134     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXH,
    135     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXRM,
    136     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXWM,
    137 
    138     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXL,
    139     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXH,
    140     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXRM,
    141     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXWM,
    142 
    143     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXL,
    144     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXH,
    145     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXRM,
    146     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXWM,
    147 
    148     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL,
    149     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXH,
    150     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXRM,
    151     QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM,
    152 
    153     QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_END_MEM_REG, // ECC Scrub settings
    154     QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_START_MEM_REG,
    155     QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_NEXT_READ_REG,
    156     QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG,
    157 
    158     0xFF
    159     };
    160 
    161 /**
    162   Allocate EfiACPIMemoryNVS below 4G memory address.
    163 
    164   This function allocates EfiACPIMemoryNVS below 4G memory address.
    165 
    166   @param Size   Size of memory to allocate.
    167 
    168   @return       Allocated address for output.
    169 
    170 **/
    171 VOID*
    172 AllocateAcpiNvsMemoryBelow4G (
    173   IN UINTN  Size
    174   )
    175 {
    176   UINTN                 Pages;
    177   EFI_PHYSICAL_ADDRESS  Address;
    178   EFI_STATUS            Status;
    179   VOID*                 Buffer;
    180 
    181   Pages = EFI_SIZE_TO_PAGES (Size);
    182   Address = 0xffffffff;
    183 
    184   Status  = gBS->AllocatePages (
    185                    AllocateMaxAddress,
    186                    EfiACPIMemoryNVS,
    187                    Pages,
    188                    &Address
    189                    );
    190   if (EFI_ERROR (Status)) {
    191     return NULL;
    192   }
    193 
    194   Buffer = (VOID *) (UINTN) Address;
    195   ZeroMem (Buffer, Size);
    196 
    197   return Buffer;
    198 }
    199 
    200 EFI_STATUS
    201 EFIAPI
    202 ReservedS3Memory (
    203   UINTN  SystemMemoryLength
    204 
    205   )
    206 /*++
    207 
    208 Routine Description:
    209 
    210   Reserved S3 memory for InstallS3Memory
    211 
    212 Arguments:
    213 
    214 
    215 Returns:
    216 
    217   EFI_OUT_OF_RESOURCES  -  Insufficient resources to complete function.
    218   EFI_SUCCESS           -  Function has completed successfully.
    219 
    220 --*/
    221 {
    222 
    223   VOID                                      *GuidHob;
    224   EFI_SMRAM_HOB_DESCRIPTOR_BLOCK            *DescriptorBlock;
    225   VOID                                      *AcpiReservedBase;
    226 
    227   UINTN                                     TsegIndex;
    228   UINTN                                     TsegSize;
    229   UINTN                                     TsegBase;
    230   RESERVED_ACPI_S3_RANGE                    *AcpiS3Range;
    231   //
    232   // Get Hob list for SMRAM desc
    233   //
    234   GuidHob    = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);
    235   ASSERT (GuidHob);
    236   DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);
    237   ASSERT (DescriptorBlock);
    238 
    239   //
    240   // Use the hob to get SMRAM capabilities
    241   //
    242   TsegIndex = DescriptorBlock->NumberOfSmmReservedRegions - 1;
    243   ASSERT (TsegIndex <= (MAX_SMRAM_RANGES - 1));
    244   TsegBase  = (UINTN)DescriptorBlock->Descriptor[TsegIndex].PhysicalStart;
    245   TsegSize  = (UINTN)DescriptorBlock->Descriptor[TsegIndex].PhysicalSize;
    246 
    247   DEBUG ((EFI_D_INFO, "SMM  Base: %08X\n", TsegBase));
    248   DEBUG ((EFI_D_INFO, "SMM  Size: %08X\n", TsegSize));
    249 
    250   //
    251   // Now find the location of the data structure that is used to store the address
    252   // of the S3 reserved memory.
    253   //
    254   AcpiS3Range = (RESERVED_ACPI_S3_RANGE*) (UINTN) (TsegBase + RESERVED_ACPI_S3_RANGE_OFFSET);
    255 
    256   //
    257   // Allocate reserved ACPI memory for S3 resume.  Pointer to this region is
    258   // stored in SMRAM in the first page of TSEG.
    259   //
    260   AcpiReservedBase = AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdS3AcpiReservedMemorySize));
    261   if (AcpiReservedBase != NULL) {
    262     AcpiS3Range->AcpiReservedMemoryBase = (UINT32)(UINTN) AcpiReservedBase;
    263     AcpiS3Range->AcpiReservedMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize);
    264   }
    265   AcpiS3Range->SystemMemoryLength = (UINT32)SystemMemoryLength;
    266 
    267   DEBUG ((EFI_D_INFO, "S3 Memory  Base:    %08X\n", AcpiS3Range->AcpiReservedMemoryBase));
    268   DEBUG ((EFI_D_INFO, "S3 Memory  Size:    %08X\n", AcpiS3Range->AcpiReservedMemorySize));
    269   DEBUG ((EFI_D_INFO, "S3 SysMemoryLength: %08X\n", AcpiS3Range->SystemMemoryLength));
    270 
    271   return EFI_SUCCESS;
    272 }
    273 
    274 
    275 EFI_STATUS
    276 EFIAPI
    277 InitAcpiSmmPlatform (
    278   IN EFI_HANDLE        ImageHandle,
    279   IN EFI_SYSTEM_TABLE  *SystemTable
    280   )
    281 /*++
    282 
    283 Routine Description:
    284 
    285   Initializes the SMM S3 Handler Driver.
    286 
    287 Arguments:
    288 
    289   ImageHandle  -  The image handle of Sleep State Wake driver.
    290   SystemTable  -  The starndard EFI system table.
    291 
    292 Returns:
    293 
    294   EFI_OUT_OF_RESOURCES  -  Insufficient resources to complete function.
    295   EFI_SUCCESS           -  Function has completed successfully.
    296   Other                 -  Error occured during execution.
    297 
    298 --*/
    299 {
    300   EFI_STATUS                      Status;
    301   EFI_GLOBAL_NVS_AREA_PROTOCOL    *AcpiNvsProtocol = NULL;
    302   UINTN                           MemoryLength;
    303   EFI_PEI_HOB_POINTERS            Hob;
    304 
    305   Status = gBS->LocateProtocol (
    306                   &gEfiGlobalNvsAreaProtocolGuid,
    307                   NULL,
    308                   (VOID **) &AcpiNvsProtocol
    309                   );
    310   ASSERT_EFI_ERROR (Status);
    311 
    312   mAcpiSmm.BootScriptSaved  = 0;
    313 
    314   mPlatformType = (EFI_PLATFORM_TYPE)PcdGet16 (PcdPlatformType);
    315 
    316   //
    317   // Calculate the system memory length by memory hobs
    318   //
    319   MemoryLength  = 0x100000;
    320   Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
    321   ASSERT (Hob.Raw != NULL);
    322   while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) {
    323     if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
    324       //
    325       // Skip the memory region below 1MB
    326       //
    327       if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {
    328         MemoryLength += (UINTN)Hob.ResourceDescriptor->ResourceLength;
    329       }
    330     }
    331     Hob.Raw = GET_NEXT_HOB (Hob);
    332     Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
    333   }
    334 
    335   ReservedS3Memory(MemoryLength);
    336 
    337   //
    338   // Locate and Register to Parent driver
    339   //
    340   Status = RegisterToDispatchDriver ();
    341   ASSERT_EFI_ERROR (Status);
    342 
    343   return EFI_SUCCESS;
    344 }
    345 
    346 EFI_STATUS
    347 RegisterToDispatchDriver (
    348   VOID
    349   )
    350 /*++
    351 
    352 Routine Description:
    353 
    354   Register to dispatch driver.
    355 
    356 Arguments:
    357 
    358   None.
    359 
    360 Returns:
    361 
    362   EFI_SUCCESS  -  Successfully init the device.
    363   Other        -  Error occured whening calling Dxe lib functions.
    364 
    365 --*/
    366 {
    367   UINTN                         Length;
    368   EFI_STATUS                    Status;
    369   EFI_SMM_SX_DISPATCH2_PROTOCOL  *SxDispatch;
    370   EFI_SMM_SW_DISPATCH2_PROTOCOL  *SwDispatch;
    371   EFI_SMM_SX_REGISTER_CONTEXT   *EntryDispatchContext;
    372   EFI_SMM_SX_REGISTER_CONTEXT   *EntryS1DispatchContext;
    373   EFI_SMM_SX_REGISTER_CONTEXT   *EntryS3DispatchContext;
    374   EFI_SMM_SX_REGISTER_CONTEXT   *EntryS4DispatchContext;
    375   EFI_SMM_SX_REGISTER_CONTEXT   *EntryS5DispatchContext;
    376   EFI_SMM_SW_REGISTER_CONTEXT   *SwContext;
    377   EFI_SMM_SW_REGISTER_CONTEXT   *AcpiDisableSwContext;
    378   EFI_SMM_SW_REGISTER_CONTEXT   *AcpiEnableSwContext;
    379 
    380   Status = gSmst->SmmLocateProtocol (
    381                   &gEfiSmmSxDispatch2ProtocolGuid,
    382                   NULL,
    383                   (VOID **) &SxDispatch
    384                   );
    385   if (EFI_ERROR (Status)) {
    386     return Status;
    387   }
    388 
    389   Status = gSmst->SmmLocateProtocol (
    390                   &gEfiSmmSwDispatch2ProtocolGuid,
    391                   NULL,
    392                   (VOID **) &SwDispatch
    393                   );
    394   if (EFI_ERROR (Status)) {
    395     return Status;
    396   }
    397 
    398   Length = sizeof (EFI_SMM_SX_REGISTER_CONTEXT) * 4 + sizeof (EFI_SMM_SW_REGISTER_CONTEXT) * 2;
    399   Status = gSmst->SmmAllocatePool (
    400                       EfiRuntimeServicesData,
    401                       Length,
    402                       (VOID **) &EntryDispatchContext
    403                       );
    404   if (EFI_ERROR (Status)) {
    405     return Status;
    406   }
    407 
    408   SetMem (EntryDispatchContext, Length, 0);
    409 
    410   EntryS1DispatchContext  = EntryDispatchContext++;
    411   EntryS3DispatchContext  = EntryDispatchContext++;
    412   EntryS4DispatchContext  = EntryDispatchContext++;
    413   EntryS5DispatchContext  = EntryDispatchContext++;
    414 
    415   SwContext = (EFI_SMM_SW_REGISTER_CONTEXT *)EntryDispatchContext;
    416   AcpiDisableSwContext = SwContext++;
    417   AcpiEnableSwContext  = SwContext++;
    418 
    419   //
    420   // Register the enable handler
    421   //
    422   AcpiEnableSwContext->SwSmiInputValue = EFI_ACPI_ACPI_ENABLE;
    423   Status = SwDispatch->Register (
    424                         SwDispatch,
    425                         EnableAcpiCallback,
    426                         AcpiEnableSwContext,
    427                         &(mAcpiSmm.DisableAcpiHandle)
    428                         );
    429 
    430   //
    431   // Register the disable handler
    432   //
    433   AcpiDisableSwContext->SwSmiInputValue = EFI_ACPI_ACPI_DISABLE;
    434   Status = SwDispatch->Register (
    435                         SwDispatch,
    436                         DisableAcpiCallback,
    437                         AcpiDisableSwContext,
    438                         &(mAcpiSmm.EnableAcpiHandle)
    439                         );
    440 
    441 
    442   //
    443   // Register entry phase call back function for S1
    444   //
    445   EntryS1DispatchContext->Type  = SxS1;
    446   EntryS1DispatchContext->Phase = SxEntry;
    447   Status = SxDispatch->Register (
    448                         SxDispatch,
    449                         SxSleepEntryCallBack,
    450                         EntryS1DispatchContext,
    451                         &(mAcpiSmm.S1SleepEntryHandle)
    452                         );
    453 
    454   //
    455   // Register entry phase call back function
    456   //
    457   EntryS3DispatchContext->Type  = SxS3;
    458   EntryS3DispatchContext->Phase = SxEntry;
    459   Status = SxDispatch->Register (
    460                         SxDispatch,
    461                         SxSleepEntryCallBack,
    462                         EntryS3DispatchContext,
    463                         &(mAcpiSmm.S3SleepEntryHandle)
    464                         );
    465 
    466   //
    467   // Register entry phase call back function for S4
    468   //
    469   EntryS4DispatchContext->Type  = SxS4;
    470   EntryS4DispatchContext->Phase = SxEntry;
    471   Status = SxDispatch->Register (
    472                         SxDispatch,
    473                         SxSleepEntryCallBack,
    474                         EntryS4DispatchContext,
    475                         &(mAcpiSmm.S4SleepEntryHandle)
    476                         );
    477 
    478   //
    479   // Register callback for S5 in order to workaround the LAN shutdown issue
    480   //
    481   EntryS5DispatchContext->Type  = SxS5;
    482   EntryS5DispatchContext->Phase = SxEntry;
    483   Status = SxDispatch->Register (
    484                         SxDispatch,
    485                         SxSleepEntryCallBack,
    486                         EntryS5DispatchContext,
    487                         &(mAcpiSmm.S5SoftOffEntryHandle)
    488                         );
    489 
    490   return Status;
    491 }
    492 
    493 
    494 EFI_STATUS
    495 RestoreQncS3SwCallback (
    496   IN  EFI_HANDLE                    DispatchHandle,
    497   IN  CONST VOID                    *DispatchContext,
    498   IN  OUT VOID                      *CommBuffer,
    499   IN  OUT UINTN                     *CommBufferSize
    500   )
    501 /*++
    502 
    503 Routine Description:
    504   SMI handler to restore QncS3 code & context for S3 path
    505   This will be only triggered when BootScript got executed during resume
    506 
    507 Arguments:
    508   DispatchHandle  - EFI Handle
    509   DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
    510 
    511 Returns:
    512   Nothing
    513 
    514 --*/
    515 {
    516   //
    517   // Restore to original address by default
    518   //
    519   RestoreLockBox(&gQncS3CodeInLockBoxGuid, NULL, NULL);
    520   RestoreLockBox(&gQncS3ContextInLockBoxGuid, NULL, NULL);
    521   return EFI_SUCCESS;
    522 }
    523 
    524 EFI_STATUS
    525 DisableAcpiCallback (
    526   IN  EFI_HANDLE                    DispatchHandle,
    527   IN  CONST VOID                    *DispatchContext,
    528   IN  OUT VOID                      *CommBuffer,
    529   IN  OUT UINTN                     *CommBufferSize
    530   )
    531 /*++
    532 
    533 Routine Description:
    534   SMI handler to disable ACPI mode
    535 
    536   Dispatched on reads from APM port with value 0xA1
    537 
    538   ACPI events are disabled and ACPI event status is cleared.
    539   SCI mode is then disabled.
    540    Clear all ACPI event status and disable all ACPI events
    541    Disable PM sources except power button
    542    Clear status bits
    543    Disable GPE0 sources
    544    Clear status bits
    545    Disable GPE1 sources
    546    Clear status bits
    547    Disable SCI
    548 
    549 Arguments:
    550   DispatchHandle  - EFI Handle
    551   DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
    552 
    553 Returns:
    554   Nothing
    555 
    556 --*/
    557 {
    558   EFI_STATUS  Status;
    559   UINT16      Pm1Cnt;
    560 
    561   Status = GetAllQncPmBase (gSmst);
    562   ASSERT_EFI_ERROR (Status);
    563   Pm1Cnt = IoRead16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C);
    564 
    565   //
    566   // Disable SCI
    567   //
    568   Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SCIEN;
    569 
    570   IoWrite16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C, Pm1Cnt);
    571 
    572   return EFI_SUCCESS;
    573 }
    574 
    575 EFI_STATUS
    576 EnableAcpiCallback (
    577   IN  EFI_HANDLE                    DispatchHandle,
    578   IN  CONST VOID                    *DispatchContext,
    579   IN  OUT VOID                      *CommBuffer,
    580   IN  OUT UINTN                     *CommBufferSize
    581   )
    582 /*++
    583 
    584 Routine Description:
    585   SMI handler to enable ACPI mode
    586 
    587   Dispatched on reads from APM port with value 0xA0
    588 
    589   Disables the SW SMI Timer.
    590   ACPI events are disabled and ACPI event status is cleared.
    591   SCI mode is then enabled.
    592 
    593    Disable SW SMI Timer
    594 
    595    Clear all ACPI event status and disable all ACPI events
    596    Disable PM sources except power button
    597    Clear status bits
    598 
    599    Disable GPE0 sources
    600    Clear status bits
    601 
    602    Disable GPE1 sources
    603    Clear status bits
    604 
    605    Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4)
    606 
    607    Enable SCI
    608 
    609 Arguments:
    610   DispatchHandle  - EFI Handle
    611   DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT
    612 
    613 Returns:
    614   Nothing
    615 
    616 --*/
    617 {
    618   EFI_STATUS  Status;
    619   UINT32      SmiEn;
    620   UINT16      Pm1Cnt;
    621   UINT8       Data8;
    622 
    623   Status  = GetAllQncPmBase (gSmst);
    624   ASSERT_EFI_ERROR (Status);
    625 
    626   SmiEn = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE);
    627 
    628   //
    629   // Disable SW SMI Timer
    630   //
    631   SmiEn &= ~(B_QNC_GPE0BLK_SMIE_SWT);
    632   IoWrite32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE, SmiEn);
    633 
    634   //
    635   // Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4)
    636   //
    637   Data8 = RTC_ADDRESS_REGISTER_D;
    638   IoWrite8 (R_IOPORT_CMOS_STANDARD_INDEX, Data8);
    639   Data8 = 0x0;
    640   IoWrite8 (R_IOPORT_CMOS_STANDARD_DATA, Data8);
    641 
    642   //
    643   // Enable SCI
    644   //
    645   Pm1Cnt = IoRead16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C);
    646   Pm1Cnt |= B_QNC_PM1BLK_PM1C_SCIEN;
    647   IoWrite16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C, Pm1Cnt);
    648 
    649   //
    650   // Do platform specific stuff for ACPI enable SMI
    651   //
    652 
    653 
    654   return EFI_SUCCESS;
    655 }
    656 
    657 EFI_STATUS
    658 SxSleepEntryCallBack (
    659   IN  EFI_HANDLE                    DispatchHandle,
    660   IN  CONST VOID                    *DispatchContext,
    661   IN  OUT VOID                      *CommBuffer,
    662   IN  OUT UINTN                     *CommBufferSize
    663   )
    664 /*++
    665 
    666 Routine Description:
    667 
    668   Callback function entry for Sx sleep state.
    669 
    670 Arguments:
    671 
    672   DispatchHandle   -  The handle of this callback, obtained when registering.
    673   DispatchContext  -  The predefined context which contained sleep type and phase.
    674 
    675 Returns:
    676 
    677   EFI_SUCCESS            -  Operation successfully performed.
    678   EFI_INVALID_PARAMETER  -  Invalid parameter passed in.
    679 
    680 --*/
    681 {
    682   EFI_STATUS  Status;
    683   UINT8       Data8;
    684   UINT16      Data16;
    685   UINT32      Data32;
    686 
    687   REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeS3SuspendStart));
    688 
    689   //
    690   // Reget QNC power mgmr regs base in case of OS changing it at runtime
    691   //
    692   Status  = GetAllQncPmBase (gSmst);
    693 
    694   //
    695   // Clear RTC Alarm (if set)
    696   //
    697   Data8 = RTC_ADDRESS_REGISTER_C;
    698   IoWrite8 (R_IOPORT_CMOS_STANDARD_INDEX, Data8);
    699   Data8 = IoRead8 (R_IOPORT_CMOS_STANDARD_DATA);
    700 
    701   //
    702   // Clear all ACPI status bits
    703   //
    704   Data32 = B_QNC_GPE0BLK_GPE0S_ALL;
    705   Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0S, 1, &Data32 );
    706   Data16 = B_QNC_PM1BLK_PM1S_ALL;
    707   Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1S, 1, &Data16 );
    708 
    709   //
    710   // Handling S1 - setting appropriate wake bits in GPE0_EN
    711   //
    712   if ((DispatchHandle == mAcpiSmm.S1SleepEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS1)) {
    713     //
    714     // Enable bit13 (EGPE), 14 (GPIO) ,17 (PCIE) in GPE0_EN
    715     //
    716     Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );
    717     Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE);
    718     Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );
    719 
    720     //
    721     // Enable bit10 (RTC) in PM1E
    722     //
    723     Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );
    724     Data16 |= B_QNC_PM1BLK_PM1E_RTC;
    725     Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );
    726 
    727     return EFI_SUCCESS;
    728   }
    729 
    730   //
    731   // Handling S4, S5 and WOL - setting appropriate wake bits in GPE0_EN
    732   //
    733   if (((DispatchHandle == mAcpiSmm.S4SleepEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS4)) ||
    734       ((DispatchHandle == mAcpiSmm.S5SoftOffEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS5))
    735      ) {
    736     //
    737     // Enable bit13 (EGPE), 14 (GPIO) ,17 (PCIE) in GPE0_EN
    738     // Enable the WOL bits in GPE0_EN reg here for PME
    739     //
    740     Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );
    741     Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE);
    742     Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );
    743 
    744     //
    745     // Enable bit10 (RTC) in PM1E
    746     //
    747     Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );
    748     Data16 |= B_QNC_PM1BLK_PM1E_RTC;
    749     Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );
    750 
    751   } else {
    752 
    753     if ((DispatchHandle != mAcpiSmm.S3SleepEntryHandle) || (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type != SxS3)) {
    754       return EFI_INVALID_PARAMETER;
    755     }
    756 
    757     Status  = SaveRuntimeScriptTable (gSmst);
    758     if (EFI_ERROR (Status)) {
    759       return Status;
    760     }
    761 
    762     //
    763     // Enable bit13 (EGPE), 14 (GPIO), 17 (PCIE) in GPE0_EN
    764     // Enable the WOL bits in GPE0_EN reg here for PME
    765     //
    766     Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );
    767     Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE);
    768     Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );
    769 
    770     //
    771     // Enable bit10 (RTC) in PM1E
    772     //
    773     Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );
    774     Data16 |= B_QNC_PM1BLK_PM1E_RTC;
    775     Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );
    776   }
    777 
    778   //
    779   // When entering a power-managed state like S3,
    780   // PERST# must be asserted in advance of power-off.
    781   //
    782   PlatformPERSTAssert (mPlatformType);
    783 
    784   return EFI_SUCCESS;
    785 }
    786 
    787 EFI_STATUS
    788 GetAllQncPmBase (
    789   IN EFI_SMM_SYSTEM_TABLE2       *Smst
    790   )
    791 /*++
    792 
    793 Routine Description:
    794 
    795   Get QNC chipset LPC Power Management I/O Base at runtime.
    796 
    797 Arguments:
    798 
    799   Smst  -  The standard SMM system table.
    800 
    801 Returns:
    802 
    803   EFI_SUCCESS  -  Successfully init the device.
    804   Other        -  Error occured whening calling Dxe lib functions.
    805 
    806 --*/
    807 {
    808   mAcpiSmm.QncPmBase    = PciRead16 (PCI_LIB_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, R_QNC_LPC_PM1BLK)) & B_QNC_LPC_PM1BLK_MASK;
    809   mAcpiSmm.QncGpe0Base  = PciRead16 (PCI_LIB_ADDRESS(PCI_BUS_NUMBER_QNC, PCI_DEVICE_NUMBER_QNC_LPC, 0, R_QNC_LPC_GPE0BLK)) & B_QNC_LPC_GPE0BLK_MASK;
    810 
    811   //
    812   // Quark does not support Changing Primary SoC IOBARs from what was
    813   // setup in SEC/PEI UEFI stages.
    814   //
    815   ASSERT (mAcpiSmm.QncPmBase == (UINT32) PcdGet16 (PcdPm1blkIoBaseAddress));
    816   ASSERT (mAcpiSmm.QncGpe0Base == (UINT32) PcdGet16 (PcdGpe0blkIoBaseAddress));
    817   return EFI_SUCCESS;
    818 }
    819 
    820 EFI_STATUS
    821 SaveRuntimeScriptTable (
    822   IN EFI_SMM_SYSTEM_TABLE2       *Smst
    823   )
    824 {
    825   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS  PciAddress;
    826   UINT32                Data32;
    827   UINT16                Data16;
    828   UINT8                 Mask;
    829   UINTN                 Index;
    830   UINTN                 Offset;
    831   UINT16                DeviceId;
    832 
    833   //
    834   // Check what Soc we are running on (read Host bridge DeviceId)
    835   //
    836   DeviceId = QncGetSocDeviceId();
    837 
    838   //
    839   // Save PCI-Host bridge settings (0, 0, 0). 0x90, 94 and 9c are changed by CSM
    840   // and vital to S3 resume. That's why we put save code here
    841   //
    842   Index = 0;
    843   while (mPciCfgRegTable[Index] != PCI_DEVICE_END) {
    844 
    845     PciAddress.Bus              = mPciCfgRegTable[Index++];
    846     PciAddress.Device           = mPciCfgRegTable[Index++];
    847     PciAddress.Function         = mPciCfgRegTable[Index++];
    848     PciAddress.Register         = 0;
    849     PciAddress.ExtendedRegister = 0;
    850 
    851     Data16 = PciRead16 (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register));
    852     if (Data16 == 0xFFFF) {
    853       Index += 8;
    854       continue;
    855     }
    856 
    857     for (Offset = 0, Mask = 0x01; Offset < 256; Offset += 4, Mask <<= 1) {
    858 
    859       if (Mask == 0x00) {
    860         Mask = 0x01;
    861       }
    862 
    863       if (mPciCfgRegTable[Index + Offset / 32] & Mask) {
    864 
    865         PciAddress.Register = (UINT8) Offset;
    866         Data32 = PciRead32 (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register));
    867 
    868 
    869         //
    870         // Save latest settings to runtime script table
    871         //
    872         S3BootScriptSavePciCfgWrite (
    873              S3BootScriptWidthUint32,
    874              PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)),
    875              1,
    876              &Data32
    877              );
    878       }
    879     }
    880 
    881     Index += 8;
    882 
    883   }
    884 
    885   //
    886   // Save message bus registers
    887   //
    888   Index = 0;
    889   while (QNCS3SaveExtReg[Index] != 0xFF) {
    890     Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);
    891 
    892     //
    893     // Save IMR settings with IMR protection disabled initially
    894     // HMBOUND and IMRs will be locked just before jumping to the OS waking vector
    895     //
    896     if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) {
    897       if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) == QUARK_NC_MEMORY_MANAGER_IMRXL)) {
    898         Data32 &= ~IMR_LOCK;
    899         if (DeviceId == QUARK2_MC_DEVICE_ID) {
    900           Data32 &= ~IMR_EN;
    901         }
    902       }
    903       if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) >= QUARK_NC_MEMORY_MANAGER_IMRXRM)) {
    904         Data32 = (UINT32)IMRX_ALL_ACCESS;
    905       }
    906     }
    907 
    908     //
    909     // Save latest settings to runtime script table
    910     //
    911     S3BootScriptSavePciCfgWrite (
    912       S3BootScriptWidthUint32,
    913       PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)),
    914       1,
    915       &Data32
    916      );
    917 
    918     Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);
    919 
    920     S3BootScriptSavePciCfgWrite (
    921       S3BootScriptWidthUint32,
    922       PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)),
    923       1,
    924       &Data32
    925      );
    926     Index += 2;
    927   }
    928 
    929   Index = 0;
    930   while (QNCS3SaveExtReg[Index] != 0xFF) {
    931     //
    932     // Save IMR settings with IMR protection enabled (above script was to handle restoring all settings first - now we want to enable)
    933     //
    934     if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) {
    935       if (DeviceId == QUARK2_MC_DEVICE_ID) {
    936         if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) == QUARK_NC_MEMORY_MANAGER_IMRXL)) {
    937           Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);
    938           Data32 &= ~IMR_LOCK;
    939 
    940           //
    941           // Save latest settings to runtime script table
    942           //
    943           S3BootScriptSavePciCfgWrite (
    944             S3BootScriptWidthUint32,
    945             PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)),
    946             1,
    947             &Data32
    948           );
    949 
    950           Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);
    951 
    952           S3BootScriptSavePciCfgWrite (
    953             S3BootScriptWidthUint32,
    954             PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)),
    955             1,
    956             &Data32
    957           );
    958         }
    959       } else {
    960         if ((QNCS3SaveExtReg[Index + 1] >= (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM)) && (QNCS3SaveExtReg[Index + 1] <= (QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM)) && ((QNCS3SaveExtReg[Index + 1] & 0x03) >= QUARK_NC_MEMORY_MANAGER_IMRXRM)) {
    961           Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);
    962 
    963           //
    964           // Save latest settings to runtime script table
    965           //
    966           S3BootScriptSavePciCfgWrite (
    967             S3BootScriptWidthUint32,
    968             PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)),
    969             1,
    970             &Data32
    971           );
    972 
    973           Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);
    974 
    975           S3BootScriptSavePciCfgWrite (
    976             S3BootScriptWidthUint32,
    977             PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)),
    978             1,
    979             &Data32
    980           );
    981         }
    982       }
    983     }
    984     Index += 2;
    985   }
    986 
    987   // Check if ECC scrub enabled and need re-enabling on resume
    988   // All scrub related configuration registers are saved on suspend
    989   // as part of QNCS3SaveExtReg configuration table script.
    990   // The code below extends the S3 resume script with scrub reactivation
    991   // message (if needed only)
    992   Data32 = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG);
    993   if( 0 != (Data32 & SCRUB_CFG_ACTIVE)) {
    994 
    995       Data32 = SCRUB_RESUME_MSG();
    996 
    997       S3BootScriptSavePciCfgWrite (
    998         S3BootScriptWidthUint32,
    999         PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)),
   1000         1,
   1001         &Data32
   1002        );
   1003   }
   1004 
   1005   //
   1006   // Save I/O ports to S3 script table
   1007   //
   1008 
   1009   //
   1010   // Important to trap Sx for SMM
   1011   //
   1012   Data32 = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE);
   1013   S3BootScriptSaveIoWrite(S3BootScriptWidthUint32, (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE), 1, &Data32);
   1014 
   1015   return EFI_SUCCESS;
   1016 }
   1017 
   1018