]> git.proxmox.com Git - mirror_edk2.git/blobdiff - QuarkPlatformPkg/Acpi/DxeSmm/AcpiSmm/AcpiSmmPlatform.c
QuarkPlatformPkg: Add new package for Galileo boards
[mirror_edk2.git] / QuarkPlatformPkg / Acpi / DxeSmm / AcpiSmm / AcpiSmmPlatform.c
diff --git a/QuarkPlatformPkg/Acpi/DxeSmm/AcpiSmm/AcpiSmmPlatform.c b/QuarkPlatformPkg/Acpi/DxeSmm/AcpiSmm/AcpiSmmPlatform.c
new file mode 100644 (file)
index 0000000..321cf62
--- /dev/null
@@ -0,0 +1,1017 @@
+/** @file\r
+ACPISMM Driver implementation file.\r
+\r
+This is QNC Smm platform driver\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+**/\r
+\r
+#include <AcpiSmmPlatform.h>\r
+\r
+#define PCILIB_TO_COMMON_ADDRESS(Address) \\r
+        ((UINT64) ((((UINTN) ((Address>>20) & 0xff)) << 24) + (((UINTN) ((Address>>15) & 0x1f)) << 16) + (((UINTN) ((Address>>12) & 0x07)) << 8) + ((UINTN) (Address & 0xfff ))))\r
+\r
+//\r
+// Modular variables needed by this driver\r
+//\r
+EFI_ACPI_SMM_DEV                 mAcpiSmm;\r
+\r
+UINT8  mPciCfgRegTable[] = {\r
+  //\r
+  // Logic to decode the table masks to arrive at the registers saved\r
+  // Dword Registers are saved. For a given mask, the Base+offset register\r
+  // will be saved as in the table below.\r
+  // (example) To save register 0x24, 0x28 the mask at the Base 0x20 will be 0x06\r
+  //     Base      0x00   0x20   0x40  0x60  0x80  0xA0  0xC0  0xE0\r
+  // Mask  offset\r
+  // 0x01   0x00\r
+  // 0x02   0x04\r
+  // 0x04   0x08\r
+  // 0x08   0x0C\r
+  // 0x10   0x10\r
+  // 0x20   0x14\r
+  // 0x40   0x18\r
+  // 0x80   0x1C\r
+  //\r
+\r
+  //\r
+  // Bus,   Dev,  Func,\r
+  // 00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF\r
+  // Only Bus 0 device is supported now\r
+  //\r
+\r
+  //\r
+  // Quark South Cluster devices\r
+  //\r
+  PCI_DEVICE   (0, 20, 0),\r
+  PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 20, 1),\r
+  PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 20, 2),\r
+  PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 20, 3),\r
+  PCI_REG_MASK (0x18, 0x98, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00),\r
+\r
+  PCI_DEVICE   (0, 20, 4),\r
+  PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 20, 5),\r
+  PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 20, 6),\r
+  PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 20, 7),\r
+  PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 21, 0),\r
+  PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 21, 1),\r
+  PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 21, 2),\r
+  PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  //\r
+  // Quark North Cluster devices\r
+  //\r
+  PCI_DEVICE   (0, 0, 0),\r
+  PCI_REG_MASK (0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 23, 0),\r
+  PCI_REG_MASK (0xC0, 0x8F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 23, 1),\r
+  PCI_REG_MASK (0xC0, 0x8F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00),\r
+\r
+  PCI_DEVICE   (0, 31, 0),\r
+  PCI_REG_MASK (0x00, 0x08, 0x4E, 0x03, 0x02, 0x00, 0x60, 0x10),\r
+\r
+  PCI_DEVICE_END\r
+};\r
+\r
+EFI_PLATFORM_TYPE                         mPlatformType;\r
+\r
+  // These registers have to set in byte order\r
+const UINT8  QNCS3SaveExtReg[] = {\r
+    QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, // SMRAM settings\r
+\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXH,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXWM,\r
+\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXL,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXH,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXRM,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXWM,\r
+\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXL,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXH,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXRM,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXWM,\r
+\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXL,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXH,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXRM,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXWM,\r
+\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXL,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXH,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXRM,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXWM,\r
+\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXL,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXH,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXRM,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXWM,\r
+\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXL,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXH,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXRM,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXWM,\r
+\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXH,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXRM,\r
+    QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM,\r
+\r
+    QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_END_MEM_REG, // ECC Scrub settings\r
+    QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_START_MEM_REG,\r
+    QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_NEXT_READ_REG,\r
+    QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG,\r
+\r
+    0xFF\r
+    };\r
+\r
+/**\r
+  Allocate EfiACPIMemoryNVS below 4G memory address.\r
+\r
+  This function allocates EfiACPIMemoryNVS below 4G memory address.\r
+\r
+  @param Size   Size of memory to allocate.\r
+\r
+  @return       Allocated address for output.\r
+\r
+**/\r
+VOID*\r
+AllocateAcpiNvsMemoryBelow4G (\r
+  IN UINTN  Size\r
+  )\r
+{\r
+  UINTN                 Pages;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  EFI_STATUS            Status;\r
+  VOID*                 Buffer;\r
+\r
+  Pages = EFI_SIZE_TO_PAGES (Size);\r
+  Address = 0xffffffff;\r
+\r
+  Status  = gBS->AllocatePages (\r
+                   AllocateMaxAddress,\r
+                   EfiACPIMemoryNVS,\r
+                   Pages,\r
+                   &Address\r
+                   );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  Buffer = (VOID *) (UINTN) Address;\r
+  ZeroMem (Buffer, Size);\r
+\r
+  return Buffer;\r
+}\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+ReservedS3Memory (\r
+  UINTN  SystemMemoryLength\r
+\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Reserved S3 memory for InstallS3Memory\r
+\r
+Arguments:\r
+\r
+\r
+Returns:\r
+\r
+  EFI_OUT_OF_RESOURCES  -  Insufficient resources to complete function.\r
+  EFI_SUCCESS           -  Function has completed successfully.\r
+\r
+--*/\r
+{\r
+\r
+  VOID                                      *GuidHob;\r
+  EFI_SMRAM_HOB_DESCRIPTOR_BLOCK            *DescriptorBlock;\r
+  VOID                                      *AcpiReservedBase;\r
+\r
+  UINTN                                     TsegIndex;\r
+  UINTN                                     TsegSize;\r
+  UINTN                                     TsegBase;\r
+  RESERVED_ACPI_S3_RANGE                    *AcpiS3Range;\r
+  //\r
+  // Get Hob list for SMRAM desc\r
+  //\r
+  GuidHob    = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid);\r
+  ASSERT (GuidHob);\r
+  DescriptorBlock = GET_GUID_HOB_DATA (GuidHob);\r
+  ASSERT (DescriptorBlock);\r
+\r
+  //\r
+  // Use the hob to get SMRAM capabilities\r
+  //\r
+  TsegIndex = DescriptorBlock->NumberOfSmmReservedRegions - 1;\r
+  ASSERT (TsegIndex <= (MAX_SMRAM_RANGES - 1));\r
+  TsegBase  = (UINTN)DescriptorBlock->Descriptor[TsegIndex].PhysicalStart;\r
+  TsegSize  = (UINTN)DescriptorBlock->Descriptor[TsegIndex].PhysicalSize;\r
+\r
+  DEBUG ((EFI_D_INFO, "SMM  Base: %08X\n", TsegBase));\r
+  DEBUG ((EFI_D_INFO, "SMM  Size: %08X\n", TsegSize));\r
+\r
+  //\r
+  // Now find the location of the data structure that is used to store the address\r
+  // of the S3 reserved memory.\r
+  //\r
+  AcpiS3Range = (RESERVED_ACPI_S3_RANGE*) (UINTN) (TsegBase + RESERVED_ACPI_S3_RANGE_OFFSET);\r
+\r
+  //\r
+  // Allocate reserved ACPI memory for S3 resume.  Pointer to this region is\r
+  // stored in SMRAM in the first page of TSEG.\r
+  //\r
+  AcpiReservedBase = AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdS3AcpiReservedMemorySize));\r
+  if (AcpiReservedBase != NULL) {\r
+    AcpiS3Range->AcpiReservedMemoryBase = (UINT32)(UINTN) AcpiReservedBase;\r
+    AcpiS3Range->AcpiReservedMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize);\r
+  }\r
+  AcpiS3Range->SystemMemoryLength = (UINT32)SystemMemoryLength;\r
+\r
+  DEBUG ((EFI_D_INFO, "S3 Memory  Base:    %08X\n", AcpiS3Range->AcpiReservedMemoryBase));\r
+  DEBUG ((EFI_D_INFO, "S3 Memory  Size:    %08X\n", AcpiS3Range->AcpiReservedMemorySize));\r
+  DEBUG ((EFI_D_INFO, "S3 SysMemoryLength: %08X\n", AcpiS3Range->SystemMemoryLength));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+InitAcpiSmmPlatform (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Initializes the SMM S3 Handler Driver.\r
+\r
+Arguments:\r
+\r
+  ImageHandle  -  The image handle of Sleep State Wake driver.\r
+  SystemTable  -  The starndard EFI system table.\r
+\r
+Returns:\r
+\r
+  EFI_OUT_OF_RESOURCES  -  Insufficient resources to complete function.\r
+  EFI_SUCCESS           -  Function has completed successfully.\r
+  Other                 -  Error occured during execution.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_GLOBAL_NVS_AREA_PROTOCOL    *AcpiNvsProtocol = NULL;\r
+  UINTN                           MemoryLength;\r
+  EFI_PEI_HOB_POINTERS            Hob;\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiGlobalNvsAreaProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &AcpiNvsProtocol\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  mAcpiSmm.BootScriptSaved  = 0;\r
+\r
+  mPlatformType = (EFI_PLATFORM_TYPE)PcdGet16 (PcdPlatformType);\r
+\r
+  //\r
+  // Calculate the system memory length by memory hobs\r
+  //\r
+  MemoryLength  = 0x100000;\r
+  Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);\r
+  ASSERT (Hob.Raw != NULL);\r
+  while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) {\r
+    if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {\r
+      //\r
+      // Skip the memory region below 1MB\r
+      //\r
+      if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {\r
+        MemoryLength += (UINTN)Hob.ResourceDescriptor->ResourceLength;\r
+      }\r
+    }\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+    Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);\r
+  }\r
+\r
+  ReservedS3Memory(MemoryLength);\r
+\r
+  //\r
+  // Locate and Register to Parent driver\r
+  //\r
+  Status = RegisterToDispatchDriver ();\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+RegisterToDispatchDriver (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Register to dispatch driver.\r
+\r
+Arguments:\r
+\r
+  None.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS  -  Successfully init the device.\r
+  Other        -  Error occured whening calling Dxe lib functions.\r
+\r
+--*/\r
+{\r
+  UINTN                         Length;\r
+  EFI_STATUS                    Status;\r
+  EFI_SMM_SX_DISPATCH2_PROTOCOL  *SxDispatch;\r
+  EFI_SMM_SW_DISPATCH2_PROTOCOL  *SwDispatch;\r
+  EFI_SMM_SX_REGISTER_CONTEXT   *EntryDispatchContext;\r
+  EFI_SMM_SX_REGISTER_CONTEXT   *EntryS1DispatchContext;\r
+  EFI_SMM_SX_REGISTER_CONTEXT   *EntryS3DispatchContext;\r
+  EFI_SMM_SX_REGISTER_CONTEXT   *EntryS4DispatchContext;\r
+  EFI_SMM_SX_REGISTER_CONTEXT   *EntryS5DispatchContext;\r
+  EFI_SMM_SW_REGISTER_CONTEXT   *SwContext;\r
+  EFI_SMM_SW_REGISTER_CONTEXT   *AcpiDisableSwContext;\r
+  EFI_SMM_SW_REGISTER_CONTEXT   *AcpiEnableSwContext;\r
+\r
+  Status = gSmst->SmmLocateProtocol (\r
+                  &gEfiSmmSxDispatch2ProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &SxDispatch\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gSmst->SmmLocateProtocol (\r
+                  &gEfiSmmSwDispatch2ProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &SwDispatch\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Length = sizeof (EFI_SMM_SX_REGISTER_CONTEXT) * 4 + sizeof (EFI_SMM_SW_REGISTER_CONTEXT) * 2;\r
+  Status = gSmst->SmmAllocatePool (\r
+                      EfiRuntimeServicesData,\r
+                      Length,\r
+                      (VOID **) &EntryDispatchContext\r
+                      );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SetMem (EntryDispatchContext, Length, 0);\r
+\r
+  EntryS1DispatchContext  = EntryDispatchContext++;\r
+  EntryS3DispatchContext  = EntryDispatchContext++;\r
+  EntryS4DispatchContext  = EntryDispatchContext++;\r
+  EntryS5DispatchContext  = EntryDispatchContext++;\r
+\r
+  SwContext = (EFI_SMM_SW_REGISTER_CONTEXT *)EntryDispatchContext;\r
+  AcpiDisableSwContext = SwContext++;\r
+  AcpiEnableSwContext  = SwContext++;\r
+\r
+  //\r
+  // Register the enable handler\r
+  //\r
+  AcpiEnableSwContext->SwSmiInputValue = EFI_ACPI_ACPI_ENABLE;\r
+  Status = SwDispatch->Register (\r
+                        SwDispatch,\r
+                        EnableAcpiCallback,\r
+                        AcpiEnableSwContext,\r
+                        &(mAcpiSmm.DisableAcpiHandle)\r
+                        );\r
+\r
+  //\r
+  // Register the disable handler\r
+  //\r
+  AcpiDisableSwContext->SwSmiInputValue = EFI_ACPI_ACPI_DISABLE;\r
+  Status = SwDispatch->Register (\r
+                        SwDispatch,\r
+                        DisableAcpiCallback,\r
+                        AcpiDisableSwContext,\r
+                        &(mAcpiSmm.EnableAcpiHandle)\r
+                        );\r
+\r
+\r
+  //\r
+  // Register entry phase call back function for S1\r
+  //\r
+  EntryS1DispatchContext->Type  = SxS1;\r
+  EntryS1DispatchContext->Phase = SxEntry;\r
+  Status = SxDispatch->Register (\r
+                        SxDispatch,\r
+                        SxSleepEntryCallBack,\r
+                        EntryS1DispatchContext,\r
+                        &(mAcpiSmm.S1SleepEntryHandle)\r
+                        );\r
+\r
+  //\r
+  // Register entry phase call back function\r
+  //\r
+  EntryS3DispatchContext->Type  = SxS3;\r
+  EntryS3DispatchContext->Phase = SxEntry;\r
+  Status = SxDispatch->Register (\r
+                        SxDispatch,\r
+                        SxSleepEntryCallBack,\r
+                        EntryS3DispatchContext,\r
+                        &(mAcpiSmm.S3SleepEntryHandle)\r
+                        );\r
+\r
+  //\r
+  // Register entry phase call back function for S4\r
+  //\r
+  EntryS4DispatchContext->Type  = SxS4;\r
+  EntryS4DispatchContext->Phase = SxEntry;\r
+  Status = SxDispatch->Register (\r
+                        SxDispatch,\r
+                        SxSleepEntryCallBack,\r
+                        EntryS4DispatchContext,\r
+                        &(mAcpiSmm.S4SleepEntryHandle)\r
+                        );\r
+\r
+  //\r
+  // Register callback for S5 in order to workaround the LAN shutdown issue\r
+  //\r
+  EntryS5DispatchContext->Type  = SxS5;\r
+  EntryS5DispatchContext->Phase = SxEntry;\r
+  Status = SxDispatch->Register (\r
+                        SxDispatch,\r
+                        SxSleepEntryCallBack,\r
+                        EntryS5DispatchContext,\r
+                        &(mAcpiSmm.S5SoftOffEntryHandle)\r
+                        );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+RestoreQncS3SwCallback (\r
+  IN  EFI_HANDLE                    DispatchHandle,\r
+  IN  CONST VOID                    *DispatchContext,\r
+  IN  OUT VOID                      *CommBuffer,\r
+  IN  OUT UINTN                     *CommBufferSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  SMI handler to retore QncS3 code & context for S3 path\r
+  This will be only triggered when BootScript got executed during resume\r
+\r
+Arguments:\r
+  DispatchHandle  - EFI Handle\r
+  DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT\r
+\r
+Returns:\r
+  Nothing\r
+\r
+--*/\r
+{\r
+  //\r
+  // Restore to original address by default\r
+  //\r
+  RestoreLockBox(&gQncS3CodeInLockBoxGuid, NULL, NULL);\r
+  RestoreLockBox(&gQncS3ContextInLockBoxGuid, NULL, NULL);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+DisableAcpiCallback (\r
+  IN  EFI_HANDLE                    DispatchHandle,\r
+  IN  CONST VOID                    *DispatchContext,\r
+  IN  OUT VOID                      *CommBuffer,\r
+  IN  OUT UINTN                     *CommBufferSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  SMI handler to disable ACPI mode\r
+\r
+  Dispatched on reads from APM port with value 0xA1\r
+\r
+  ACPI events are disabled and ACPI event status is cleared.\r
+  SCI mode is then disabled.\r
+   Clear all ACPI event status and disable all ACPI events\r
+   Disable PM sources except power button\r
+   Clear status bits\r
+   Disable GPE0 sources\r
+   Clear status bits\r
+   Disable GPE1 sources\r
+   Clear status bits\r
+   Disable SCI\r
+\r
+Arguments:\r
+  DispatchHandle  - EFI Handle\r
+  DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT\r
+\r
+Returns:\r
+  Nothing\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT16      Pm1Cnt;\r
+\r
+  Status = GetAllQncPmBase (gSmst);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Pm1Cnt = IoRead16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C);\r
+\r
+  //\r
+  // Disable SCI\r
+  //\r
+  Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SCIEN;\r
+\r
+  IoWrite16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C, Pm1Cnt);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+EnableAcpiCallback (\r
+  IN  EFI_HANDLE                    DispatchHandle,\r
+  IN  CONST VOID                    *DispatchContext,\r
+  IN  OUT VOID                      *CommBuffer,\r
+  IN  OUT UINTN                     *CommBufferSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  SMI handler to enable ACPI mode\r
+\r
+  Dispatched on reads from APM port with value 0xA0\r
+\r
+  Disables the SW SMI Timer.\r
+  ACPI events are disabled and ACPI event status is cleared.\r
+  SCI mode is then enabled.\r
+\r
+   Disable SW SMI Timer\r
+\r
+   Clear all ACPI event status and disable all ACPI events\r
+   Disable PM sources except power button\r
+   Clear status bits\r
+\r
+   Disable GPE0 sources\r
+   Clear status bits\r
+\r
+   Disable GPE1 sources\r
+   Clear status bits\r
+\r
+   Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4)\r
+\r
+   Enable SCI\r
+\r
+Arguments:\r
+  DispatchHandle  - EFI Handle\r
+  DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT\r
+\r
+Returns:\r
+  Nothing\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      SmiEn;\r
+  UINT16      Pm1Cnt;\r
+  UINT8       Data8;\r
+\r
+  Status  = GetAllQncPmBase (gSmst);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SmiEn = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE);\r
+\r
+  //\r
+  // Disable SW SMI Timer\r
+  //\r
+  SmiEn &= ~(B_QNC_GPE0BLK_SMIE_SWT);\r
+  IoWrite32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE, SmiEn);\r
+\r
+  //\r
+  // Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4)\r
+  //\r
+  Data8 = RTC_ADDRESS_REGISTER_D;\r
+  IoWrite8 (R_IOPORT_CMOS_STANDARD_INDEX, Data8);\r
+  Data8 = 0x0;\r
+  IoWrite8 (R_IOPORT_CMOS_STANDARD_DATA, Data8);\r
+\r
+  //\r
+  // Enable SCI\r
+  //\r
+  Pm1Cnt = IoRead16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C);\r
+  Pm1Cnt |= B_QNC_PM1BLK_PM1C_SCIEN;\r
+  IoWrite16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C, Pm1Cnt);\r
+\r
+  //\r
+  // Do platform specific stuff for ACPI enable SMI\r
+  //\r
+\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+SxSleepEntryCallBack (\r
+  IN  EFI_HANDLE                    DispatchHandle,\r
+  IN  CONST VOID                    *DispatchContext,\r
+  IN  OUT VOID                      *CommBuffer,\r
+  IN  OUT UINTN                     *CommBufferSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Callback function entry for Sx sleep state.\r
+\r
+Arguments:\r
+\r
+  DispatchHandle   -  The handle of this callback, obtained when registering.\r
+  DispatchContext  -  The predefined context which contained sleep type and phase.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS            -  Operation successfully performed.\r
+  EFI_INVALID_PARAMETER  -  Invalid parameter passed in.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       Data8;\r
+  UINT16      Data16;\r
+  UINT32      Data32;\r
+\r
+  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeS3SuspendStart));\r
+\r
+  //\r
+  // Reget QNC power mgmr regs base in case of OS changing it at runtime\r
+  //\r
+  Status  = GetAllQncPmBase (gSmst);\r
+\r
+  //\r
+  // Clear RTC Alarm (if set)\r
+  //\r
+  Data8 = RTC_ADDRESS_REGISTER_C;\r
+  IoWrite8 (R_IOPORT_CMOS_STANDARD_INDEX, Data8);\r
+  Data8 = IoRead8 (R_IOPORT_CMOS_STANDARD_DATA);\r
+\r
+  //\r
+  // Clear all ACPI status bits\r
+  //\r
+  Data32 = B_QNC_GPE0BLK_GPE0S_ALL;\r
+  Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0S, 1, &Data32 );\r
+  Data16 = B_QNC_PM1BLK_PM1S_ALL;\r
+  Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1S, 1, &Data16 );\r
+\r
+  //\r
+  // Handling S1 - setting appropriate wake bits in GPE0_EN\r
+  //\r
+  if ((DispatchHandle == mAcpiSmm.S1SleepEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS1)) {\r
+    //\r
+    // Enable bit13 (EGPE), 14 (GPIO) ,17 (PCIE) in GPE0_EN\r
+    //\r
+    Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );\r
+    Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE);\r
+    Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );\r
+\r
+    //\r
+    // Enable bit10 (RTC) in PM1E\r
+    //\r
+    Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );\r
+    Data16 |= B_QNC_PM1BLK_PM1E_RTC;\r
+    Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Handling S4, S5 and WOL - setting appropriate wake bits in GPE0_EN\r
+  //\r
+  if (((DispatchHandle == mAcpiSmm.S4SleepEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS4)) ||\r
+      ((DispatchHandle == mAcpiSmm.S5SoftOffEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS5))\r
+     ) {\r
+    //\r
+    // Enable bit13 (EGPE), 14 (GPIO) ,17 (PCIE) in GPE0_EN\r
+    // Enable the WOL bits in GPE0_EN reg here for PME\r
+    //\r
+    Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );\r
+    Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE);\r
+    Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );\r
+\r
+    //\r
+    // Enable bit10 (RTC) in PM1E\r
+    //\r
+    Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );\r
+    Data16 |= B_QNC_PM1BLK_PM1E_RTC;\r
+    Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );\r
+\r
+  } else {\r
+\r
+    if ((DispatchHandle != mAcpiSmm.S3SleepEntryHandle) || (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type != SxS3)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    Status  = SaveRuntimeScriptTable (gSmst);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Enable bit13 (EGPE), 14 (GPIO), 17 (PCIE) in GPE0_EN\r
+    // Enable the WOL bits in GPE0_EN reg here for PME\r
+    //\r
+    Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );\r
+    Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE);\r
+    Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 );\r
+\r
+    //\r
+    // Enable bit10 (RTC) in PM1E\r
+    //\r
+    Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );\r
+    Data16 |= B_QNC_PM1BLK_PM1E_RTC;\r
+    Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 );\r
+  }\r
+\r
+  //\r
+  // When entering a power-managed state like S3,\r
+  // PERST# must be asserted in advance of power-off.\r
+  //\r
+  PlatformPERSTAssert (mPlatformType);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GetAllQncPmBase (\r
+  IN EFI_SMM_SYSTEM_TABLE2       *Smst\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Get QNC chipset LPC Power Management I/O Base at runtime.\r
+\r
+Arguments:\r
+\r
+  Smst  -  The standard SMM system table.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS  -  Successfully init the device.\r
+  Other        -  Error occured whening calling Dxe lib functions.\r
+\r
+--*/\r
+{\r
+  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;\r
+  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;\r
+\r
+  //\r
+  // Quark does not support Changing Primary SoC IOBARs from what was\r
+  // setup in SEC/PEI UEFI stages.\r
+  //\r
+  ASSERT (mAcpiSmm.QncPmBase == (UINT32) PcdGet16 (PcdPm1blkIoBaseAddress));\r
+  ASSERT (mAcpiSmm.QncGpe0Base == (UINT32) PcdGet16 (PcdGpe0blkIoBaseAddress));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+SaveRuntimeScriptTable (\r
+  IN EFI_SMM_SYSTEM_TABLE2       *Smst\r
+  )\r
+{\r
+  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS  PciAddress;\r
+  UINT32                Data32;\r
+  UINT16                Data16;\r
+  UINT8                 Mask;\r
+  UINTN                 Index;\r
+  UINTN                 Offset;\r
+  UINT16                DeviceId;\r
+\r
+  //\r
+  // Check what Soc we are running on (read Host bridge DeviceId)\r
+  //\r
+  DeviceId = QncGetSocDeviceId();\r
+\r
+  //\r
+  // Save PCI-Host bridge settings (0, 0, 0). 0x90, 94 and 9c are changed by CSM\r
+  // and vital to S3 resume. That's why we put save code here\r
+  //\r
+  Index = 0;\r
+  while (mPciCfgRegTable[Index] != PCI_DEVICE_END) {\r
+\r
+    PciAddress.Bus              = mPciCfgRegTable[Index++];\r
+    PciAddress.Device           = mPciCfgRegTable[Index++];\r
+    PciAddress.Function         = mPciCfgRegTable[Index++];\r
+    PciAddress.Register         = 0;\r
+    PciAddress.ExtendedRegister = 0;\r
+\r
+    Data16 = PciRead16 (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register));\r
+    if (Data16 == 0xFFFF) {\r
+      Index += 8;\r
+      continue;\r
+    }\r
+\r
+    for (Offset = 0, Mask = 0x01; Offset < 256; Offset += 4, Mask <<= 1) {\r
+\r
+      if (Mask == 0x00) {\r
+        Mask = 0x01;\r
+      }\r
+\r
+      if (mPciCfgRegTable[Index + Offset / 32] & Mask) {\r
+\r
+        PciAddress.Register = (UINT8) Offset;\r
+        Data32 = PciRead32 (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register));\r
+\r
+\r
+        //\r
+        // Save latest settings to runtime script table\r
+        //\r
+        S3BootScriptSavePciCfgWrite (\r
+             S3BootScriptWidthUint32,\r
+             PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)),\r
+             1,\r
+             &Data32\r
+             );\r
+      }\r
+    }\r
+\r
+    Index += 8;\r
+\r
+  }\r
+\r
+  //\r
+  // Save message bus registers\r
+  //\r
+  Index = 0;\r
+  while (QNCS3SaveExtReg[Index] != 0xFF) {\r
+    Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);\r
+\r
+    //\r
+    // Save IMR settings with IMR protection disabled initially\r
+    // HMBOUND and IMRs will be locked just before jumping to the OS waking vector\r
+    //\r
+    if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) {\r
+      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)) {\r
+        Data32 &= ~IMR_LOCK;\r
+        if (DeviceId == QUARK2_MC_DEVICE_ID) {\r
+          Data32 &= ~IMR_EN;\r
+        }\r
+      }\r
+      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)) {\r
+        Data32 = (UINT32)IMRX_ALL_ACCESS;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Save latest settings to runtime script table\r
+    //\r
+    S3BootScriptSavePciCfgWrite (\r
+      S3BootScriptWidthUint32,\r
+      PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)),\r
+      1,\r
+      &Data32\r
+     );\r
+\r
+    Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);\r
+\r
+    S3BootScriptSavePciCfgWrite (\r
+      S3BootScriptWidthUint32,\r
+      PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)),\r
+      1,\r
+      &Data32\r
+     );\r
+    Index += 2;\r
+  }\r
+\r
+  Index = 0;\r
+  while (QNCS3SaveExtReg[Index] != 0xFF) {\r
+    //\r
+    // Save IMR settings with IMR protection enabled (above script was to handle restoring all settings first - now we want to enable)\r
+    //\r
+    if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) {\r
+      if (DeviceId == QUARK2_MC_DEVICE_ID) {\r
+        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)) {\r
+          Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);\r
+          Data32 &= ~IMR_LOCK;\r
+\r
+          //\r
+          // Save latest settings to runtime script table\r
+          //\r
+          S3BootScriptSavePciCfgWrite (\r
+            S3BootScriptWidthUint32,\r
+            PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)),\r
+            1,\r
+            &Data32\r
+          );\r
+\r
+          Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);\r
+\r
+          S3BootScriptSavePciCfgWrite (\r
+            S3BootScriptWidthUint32,\r
+            PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)),\r
+            1,\r
+            &Data32\r
+          );\r
+        }\r
+      } else {\r
+        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)) {\r
+          Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);\r
+\r
+          //\r
+          // Save latest settings to runtime script table\r
+          //\r
+          S3BootScriptSavePciCfgWrite (\r
+            S3BootScriptWidthUint32,\r
+            PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)),\r
+            1,\r
+            &Data32\r
+          );\r
+\r
+          Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]);\r
+\r
+          S3BootScriptSavePciCfgWrite (\r
+            S3BootScriptWidthUint32,\r
+            PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)),\r
+            1,\r
+            &Data32\r
+          );\r
+        }\r
+      }\r
+    }\r
+    Index += 2;\r
+  }\r
+\r
+  // Check if ECC scrub enabled and need re-enabling on resume\r
+  // All scrub related configuration registers are saved on suspend\r
+  // as part of QNCS3SaveExtReg configuration table script.\r
+  // The code below extends the S3 resume script with scrub reactivation\r
+  // message (if needed only)\r
+  Data32 = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG);\r
+  if( 0 != (Data32 & SCRUB_CFG_ACTIVE)) {\r
+\r
+      Data32 = SCRUB_RESUME_MSG();\r
+\r
+      S3BootScriptSavePciCfgWrite (\r
+        S3BootScriptWidthUint32,\r
+        PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)),\r
+        1,\r
+        &Data32\r
+       );\r
+  }\r
+\r
+  //\r
+  // Save I/O ports to S3 script table\r
+  //\r
+\r
+  //\r
+  // Important to trap Sx for SMM\r
+  //\r
+  Data32 = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE);\r
+  S3BootScriptSaveIoWrite(S3BootScriptWidthUint32, (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE), 1, &Data32);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r