]> git.proxmox.com Git - mirror_edk2.git/blobdiff - QuarkPlatformPkg/Platform/Pei/PlatformInit/MrcWrapper.c
QuarkPlatformPkg: Add new package for Galileo boards
[mirror_edk2.git] / QuarkPlatformPkg / Platform / Pei / PlatformInit / MrcWrapper.c
diff --git a/QuarkPlatformPkg/Platform/Pei/PlatformInit/MrcWrapper.c b/QuarkPlatformPkg/Platform/Pei/PlatformInit/MrcWrapper.c
new file mode 100644 (file)
index 0000000..eee696e
--- /dev/null
@@ -0,0 +1,1641 @@
+/** @file\r
+Framework PEIM to initialize memory on a Quark Memory Controller.\r
+\r
+Copyright (c) 2013 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
+#include "CommonHeader.h"\r
+#include "MrcWrapper.h"\r
+#include <Ioh.h>\r
+#include "Platform.h"\r
+\r
+#include <Library/PlatformHelperLib.h>\r
+\r
+//\r
+// ------------------------ TSEG Base\r
+//\r
+// ------------------------ RESERVED_CPU_S3_SAVE_OFFSET\r
+// CPU S3 data\r
+// ------------------------ RESERVED_ACPI_S3_RANGE_OFFSET\r
+// S3 Memory base structure\r
+// ------------------------ TSEG + 1 page\r
+\r
+#define RESERVED_CPU_S3_SAVE_OFFSET (RESERVED_ACPI_S3_RANGE_OFFSET - sizeof (SMM_S3_RESUME_STATE))\r
+\r
+// Strap configuration register specifying DDR setup\r
+#define QUARK_SCSS_REG_STPDDRCFG   0x00\r
+\r
+// Macro counting array elements\r
+#define COUNT(a)                 (sizeof(a)/sizeof(*a))\r
+\r
+\r
+EFI_MEMORY_TYPE_INFORMATION mDefaultQncMemoryTypeInformation[] = {\r
+  { EfiReservedMemoryType,  EDKII_RESERVED_SIZE_PAGES },     // BIOS Reserved\r
+  { EfiACPIMemoryNVS,       ACPI_NVS_SIZE_PAGES },    // S3, SMM, etc\r
+  { EfiRuntimeServicesData, RUNTIME_SERVICES_DATA_SIZE_PAGES },\r
+  { EfiRuntimeServicesCode, RUNTIME_SERVICES_CODE_SIZE_PAGES },\r
+  { EfiACPIReclaimMemory,   ACPI_RECLAIM_SIZE_PAGES },     // ACPI ASL\r
+  { EfiMaxMemoryType,       0 }\r
+};\r
+\r
+/**\r
+  Configure Uart mmio base for MRC serial log purpose\r
+\r
+  @param  MrcData  - MRC configuration data updated\r
+\r
+**/\r
+VOID\r
+MrcUartConfig(\r
+  MRC_PARAMS *MrcData\r
+  )\r
+{\r
+  UINT8    UartIdx;\r
+  UINT32   RegData32;\r
+  UINT8    IohUartBus;\r
+  UINT8    IohUartDev;\r
+\r
+  UartIdx    = PcdGet8(PcdIohUartFunctionNumber);\r
+  IohUartBus = PcdGet8(PcdIohUartBusNumber);\r
+  IohUartDev = PcdGet8(PcdIohUartDevNumber);\r
+\r
+  RegData32 = PciRead32 (PCI_LIB_ADDRESS(IohUartBus,  IohUartDev, UartIdx, PCI_BASE_ADDRESSREG_OFFSET));\r
+  MrcData->uart_mmio_base = RegData32 & 0xFFFFFFF0;\r
+}\r
+\r
+/**\r
+  Configure MRC from memory controller fuse settings.\r
+\r
+  @param  MrcData      - MRC configuration data to be updated.\r
+\r
+  @return EFI_SUCCESS    MRC Config parameters updated from platform data.\r
+**/\r
+EFI_STATUS\r
+MrcConfigureFromMcFuses (\r
+  OUT MRC_PARAMS                          *MrcData\r
+  )\r
+{\r
+  UINT32                            McFuseStat;\r
+\r
+  McFuseStat = QNCPortRead (\r
+                 QUARK_NC_MEMORY_CONTROLLER_SB_PORT_ID,\r
+                 QUARK_NC_MEMORY_CONTROLLER_REG_DFUSESTAT\r
+                 );\r
+\r
+  DEBUG ((EFI_D_INFO, "MRC McFuseStat 0x%08x\n", McFuseStat));\r
+\r
+  if ((McFuseStat & B_DFUSESTAT_ECC_DIS) != 0) {\r
+    DEBUG ((EFI_D_INFO, "MRC Fuse : fus_dun_ecc_dis.\n"));\r
+    MrcData->ecc_enables = 0;\r
+  } else {\r
+    MrcData->ecc_enables = 1;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Configure MRC from platform info hob.\r
+\r
+  @param  MrcData      - MRC configuration data to be updated.\r
+\r
+  @return EFI_SUCCESS    MRC Config parameters updated from hob.\r
+  @return EFI_NOT_FOUND  Platform Info or MRC Config parameters not found.\r
+  @return EFI_INVALID_PARAMETER  Wrong params in hob.\r
+**/\r
+EFI_STATUS\r
+MrcConfigureFromInfoHob (\r
+  OUT MRC_PARAMS  *MrcData\r
+  )\r
+{\r
+  PDAT_MRC_ITEM  *ItemData;\r
+\r
+  ItemData = (PDAT_MRC_ITEM *)PcdGetPtr (PcdMrcParameters);\r
+\r
+  MrcData->channel_enables     = ItemData->ChanMask;\r
+  MrcData->channel_width       = ItemData->ChanWidth;\r
+  MrcData->address_mode        = ItemData->AddrMode;\r
+  // Enable scrambling if requested.\r
+  MrcData->scrambling_enables  = (ItemData->Flags & PDAT_MRC_FLAG_SCRAMBLE_EN) != 0;\r
+  MrcData->ddr_type            = ItemData->DramType;\r
+  MrcData->dram_width          = ItemData->DramWidth;\r
+  MrcData->ddr_speed           = ItemData->DramSpeed;\r
+  // Enable ECC if requested.\r
+  MrcData->rank_enables        = ItemData->RankMask;\r
+  MrcData->params.DENSITY      = ItemData->DramDensity;\r
+  MrcData->params.tCL          = ItemData->tCL;\r
+  MrcData->params.tRAS         = ItemData->tRAS;\r
+  MrcData->params.tWTR         = ItemData->tWTR;\r
+  MrcData->params.tRRD         = ItemData->tRRD;\r
+  MrcData->params.tFAW         = ItemData->tFAW;\r
+\r
+  MrcData->refresh_rate        = ItemData->SrInt;\r
+  MrcData->sr_temp_range       = ItemData->SrTemp;\r
+  MrcData->ron_value           = ItemData->DramRonVal;\r
+  MrcData->rtt_nom_value       = ItemData->DramRttNomVal;\r
+  MrcData->rd_odt_value        = ItemData->SocRdOdtVal;\r
+\r
+  DEBUG ((EFI_D_INFO, "MRC dram_width %d\n",  MrcData->dram_width));\r
+  DEBUG ((EFI_D_INFO, "MRC rank_enables %d\n",MrcData->rank_enables));\r
+  DEBUG ((EFI_D_INFO, "MRC ddr_speed %d\n",   MrcData->ddr_speed));\r
+  DEBUG ((EFI_D_INFO, "MRC flags: %s\n",\r
+    (MrcData->scrambling_enables) ? L"SCRAMBLE_EN" : L""\r
+    ));\r
+\r
+  DEBUG ((EFI_D_INFO, "MRC density=%d tCL=%d tRAS=%d tWTR=%d tRRD=%d tFAW=%d\n",\r
+    MrcData->params.DENSITY,\r
+    MrcData->params.tCL,\r
+    MrcData->params.tRAS,\r
+    MrcData->params.tWTR,\r
+    MrcData->params.tRRD,\r
+    MrcData->params.tFAW\r
+    ));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Configure ECC scrub\r
+\r
+  @param MrcData - MRC configuration\r
+\r
+**/\r
+VOID\r
+EccScrubSetup(\r
+  const MRC_PARAMS *MrcData\r
+  )\r
+{\r
+  UINT32 BgnAdr = 0;\r
+  UINT32 EndAdr = MrcData->mem_size;\r
+  UINT32 BlkSize = PcdGet8(PcdEccScrubBlkSize) & SCRUB_CFG_BLOCKSIZE_MASK;\r
+  UINT32 Interval = PcdGet8(PcdEccScrubInterval) & SCRUB_CFG_INTERVAL_MASK;\r
+\r
+  if( MrcData->ecc_enables == 0 || MrcData->boot_mode == bmS3 || Interval == 0) {\r
+    // No scrub configuration needed if ECC not enabled\r
+    // On S3 resume reconfiguration is done as part of resume\r
+    // script, see SNCS3Save.c ==> SaveRuntimeScriptTable()\r
+    // Also if PCD disables scrub, then we do nothing.\r
+    return;\r
+  }\r
+\r
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_END_MEM_REG, EndAdr);\r
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_START_MEM_REG, BgnAdr);\r
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_NEXT_READ_REG, BgnAdr);\r
+  QNCPortWrite (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG,\r
+    Interval << SCRUB_CFG_INTERVAL_SHIFT |\r
+    BlkSize << SCRUB_CFG_BLOCKSIZE_SHIFT);\r
+\r
+  McD0PciCfg32 (QNC_ACCESS_PORT_MCR) = SCRUB_RESUME_MSG();\r
+}\r
+\r
+/** Post InstallS3Memory / InstallEfiMemory tasks given MrcData context.\r
+\r
+  @param[in]       MrcData  MRC configuration.\r
+  @param[in]       IsS3     TRUE if after InstallS3Memory.\r
+\r
+**/\r
+VOID\r
+PostInstallMemory (\r
+  IN MRC_PARAMS                           *MrcData,\r
+  IN BOOLEAN                              IsS3\r
+  )\r
+{\r
+  UINT32                            RmuMainDestBaseAddress;\r
+  UINT32                            *RmuMainSrcBaseAddress;\r
+  UINTN                             RmuMainSize;\r
+  EFI_STATUS                        Status;\r
+\r
+  //\r
+  // Setup ECC policy (All boot modes).\r
+  //\r
+  QNCPolicyDblEccBitErr (V_WDT_CONTROL_DBL_ECC_BIT_ERR_WARM);\r
+\r
+  //\r
+  // Find the 64KB of memory for Rmu Main at the top of available memory.\r
+  //\r
+  InfoPostInstallMemory (&RmuMainDestBaseAddress, NULL, NULL);\r
+  DEBUG ((EFI_D_INFO, "RmuMain Base Address : 0x%x\n", RmuMainDestBaseAddress));\r
+\r
+  //\r
+  // Relocate RmuMain.\r
+  //\r
+  if (IsS3) {\r
+    QNCSendOpcodeDramReady (RmuMainDestBaseAddress);\r
+  } else {\r
+    Status = PlatformFindFvFileRawDataSection (NULL, PcdGetPtr(PcdQuarkMicrocodeFile), (VOID **) &RmuMainSrcBaseAddress, &RmuMainSize);\r
+    ASSERT_EFI_ERROR (Status);\r
+    if (!EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_INFO, "Found Microcode ADDR:SIZE 0x%08x:0x%04x\n", (UINTN) RmuMainSrcBaseAddress, RmuMainSize));\r
+    }\r
+\r
+    RmuMainRelocation (RmuMainDestBaseAddress, (UINT32) RmuMainSrcBaseAddress, RmuMainSize);\r
+    QNCSendOpcodeDramReady (RmuMainDestBaseAddress);\r
+    EccScrubSetup (MrcData);\r
+  }\r
+}\r
+\r
+/**\r
+\r
+  Do memory initialisation for QNC DDR3 SDRAM Controller\r
+\r
+  @param  FfsHeader    Not used.\r
+  @param  PeiServices  General purpose services available to every PEIM.\r
+\r
+  @return EFI_SUCCESS  Memory initialisation completed successfully.\r
+          All other error conditions encountered result in an ASSERT.\r
+\r
+**/\r
+EFI_STATUS\r
+MemoryInit (\r
+  IN EFI_PEI_SERVICES          **PeiServices\r
+  )\r
+{\r
+  MRC_PARAMS                                 MrcData;\r
+  EFI_BOOT_MODE                               BootMode;\r
+  EFI_STATUS                                  Status;\r
+  EFI_PEI_READ_ONLY_VARIABLE2_PPI             *VariableServices;\r
+  EFI_STATUS_CODE_VALUE                       ErrorCodeValue;\r
+  PEI_QNC_MEMORY_INIT_PPI                     *QncMemoryInitPpi;\r
+  UINT16                                      PmswAdr;\r
+\r
+  ErrorCodeValue  = 0;\r
+\r
+  //\r
+  // It is critical that both of these data structures are initialized to 0.\r
+  // This PEIM knows the number of DIMMs in the system and works with that\r
+  // information.  The MCH PEIM that consumes these data structures does not\r
+  // know the number of DIMMs so it expects the entire structure to be\r
+  // properly initialized.  By initializing these to zero, all flags indicating\r
+  // that the SPD is present or the row should be configured are set to false.\r
+  //\r
+  ZeroMem (&MrcData, sizeof(MrcData));\r
+\r
+  //\r
+  // Get necessary PPI\r
+  //\r
+  Status = PeiServicesLocatePpi (\r
+             &gEfiPeiReadOnlyVariable2PpiGuid,           // GUID\r
+             0,                                          // INSTANCE\r
+             NULL,                                       // EFI_PEI_PPI_DESCRIPTOR\r
+             (VOID **)&VariableServices                  // PPI\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Determine boot mode\r
+  //\r
+  Status = PeiServicesGetBootMode (&BootMode);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Initialize Error type for reporting status code\r
+  //\r
+  switch (BootMode) {\r
+  case BOOT_ON_FLASH_UPDATE:\r
+    ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY + EFI_CU_MEMORY_EC_UPDATE_FAIL;\r
+    break;\r
+  case BOOT_ON_S3_RESUME:\r
+    ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY + EFI_CU_MEMORY_EC_S3_RESUME_FAIL;\r
+    break;\r
+  default:\r
+    ErrorCodeValue = EFI_COMPUTING_UNIT_MEMORY;\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Specify MRC boot mode\r
+  //\r
+  switch (BootMode) {\r
+  case BOOT_ON_S3_RESUME:\r
+  case BOOT_ON_FLASH_UPDATE:\r
+    MrcData.boot_mode = bmS3;\r
+    break;\r
+  case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:\r
+    MrcData.boot_mode = bmFast;\r
+    break;\r
+  default:\r
+    MrcData.boot_mode = bmCold;\r
+    break;\r
+  }\r
+\r
+  //\r
+  // Configure MRC input parameters.\r
+  //\r
+  Status = MrcConfigureFromMcFuses (&MrcData);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = MrcConfigureFromInfoHob (&MrcData);\r
+  ASSERT_EFI_ERROR (Status);\r
+  MrcUartConfig(&MrcData);\r
+\r
+  if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
+    //\r
+    // Always do bmCold on recovery.\r
+    //\r
+    DEBUG ((DEBUG_INFO, "MemoryInit:Force bmCold on Recovery\n"));\r
+    MrcData.boot_mode = bmCold;\r
+  } else {\r
+\r
+    //\r
+    // Load Memory configuration data saved in previous boot from variable\r
+    //\r
+    Status = LoadConfig (\r
+               PeiServices,\r
+               VariableServices,\r
+               &MrcData\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+\r
+      switch (BootMode) {\r
+      case BOOT_ON_S3_RESUME:\r
+      case BOOT_ON_FLASH_UPDATE:\r
+        REPORT_STATUS_CODE (\r
+          EFI_ERROR_CODE + EFI_ERROR_UNRECOVERED,\r
+          ErrorCodeValue\r
+        );\r
+        PeiServicesResetSystem ();\r
+        break;\r
+\r
+      default:\r
+        MrcData.boot_mode = bmCold;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Locate Memory Reference Code PPI\r
+  //\r
+  Status = PeiServicesLocatePpi (\r
+             &gQNCMemoryInitPpiGuid,        // GUID\r
+             0,                             // INSTANCE\r
+             NULL,                          // EFI_PEI_PPI_DESCRIPTOR\r
+             (VOID **)&QncMemoryInitPpi     // PPI\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  PmswAdr = (UINT16)(LpcPciCfg32 (R_QNC_LPC_GPE0BLK) & 0xFFFF) + R_QNC_GPE0BLK_PMSW;\r
+  if( IoRead32 (PmswAdr) & B_QNC_GPE0BLK_PMSW_DRAM_INIT) {\r
+    // MRC did not complete last execution, force cold boot path\r
+    MrcData.boot_mode = bmCold;\r
+  }\r
+\r
+  // Mark MRC pending\r
+  IoOr32 (PmswAdr, (UINT32)B_QNC_GPE0BLK_PMSW_DRAM_INIT);\r
+\r
+  //\r
+  // Call Memory Reference Code's Routines\r
+  //\r
+  QncMemoryInitPpi->MrcStart (&MrcData);\r
+\r
+  // Mark MRC completed\r
+  IoAnd32 (PmswAdr, ~(UINT32)B_QNC_GPE0BLK_PMSW_DRAM_INIT);\r
+\r
+\r
+  //\r
+  // Note emulation platform has to read actual memory size\r
+  // MrcData.mem_size from PcdGet32 (PcdMemorySize);\r
+\r
+  if (BootMode == BOOT_ON_S3_RESUME) {\r
+\r
+    DEBUG ((EFI_D_INFO, "Following BOOT_ON_S3_RESUME boot path.\n"));\r
+\r
+    Status = InstallS3Memory (PeiServices, VariableServices, MrcData.mem_size);\r
+    if (EFI_ERROR (Status)) {\r
+      REPORT_STATUS_CODE (\r
+        EFI_ERROR_CODE + EFI_ERROR_UNRECOVERED,\r
+        ErrorCodeValue\r
+      );\r
+      PeiServicesResetSystem ();\r
+    }\r
+    PostInstallMemory (&MrcData, TRUE);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Assign physical memory to PEI and DXE\r
+  //\r
+  DEBUG ((EFI_D_INFO, "InstallEfiMemory.\n"));\r
+\r
+  Status = InstallEfiMemory (\r
+             PeiServices,\r
+             VariableServices,\r
+             BootMode,\r
+             MrcData.mem_size\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  PostInstallMemory (&MrcData, FALSE);\r
+\r
+  //\r
+  // Save current configuration into Hob and will save into Variable later in DXE\r
+  //\r
+  DEBUG ((EFI_D_INFO, "SaveConfig.\n"));\r
+  Status = SaveConfig (\r
+             &MrcData\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  DEBUG ((EFI_D_INFO, "MemoryInit Complete.\n"));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  This function saves a config to a HOB.\r
+\r
+  @param  RowInfo         The MCH row configuration information.\r
+  @param  TimingData      Timing data to be saved.\r
+  @param  RowConfArray    Row configuration information for each row in the system.\r
+  @param  SpdData         SPD info read for each DIMM slot in the system.\r
+\r
+  @return EFI_SUCCESS:    The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SaveConfig (\r
+  IN MRC_PARAMS *MrcData\r
+  )\r
+{\r
+  //\r
+  // Build HOB data for Memory Config\r
+  // HOB data size (stored in variable) is required to be multiple of 8 bytes\r
+  //\r
+  BuildGuidDataHob (\r
+    &gEfiMemoryConfigDataGuid,\r
+    (VOID *) &MrcData->timings,\r
+    ((sizeof (MrcData->timings) + 0x7) & (~0x7))\r
+    );\r
+\r
+  DEBUG ((EFI_D_INFO, "IIO IoApicBase  = %x IoApicLimit=%x\n", IOAPIC_BASE, (IOAPIC_BASE + IOAPIC_SIZE - 1)));\r
+  DEBUG ((EFI_D_INFO, "IIO RcbaAddress = %x\n", (UINT32)PcdGet64 (PcdRcbaMmioBaseAddress)));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Load a configuration stored in a variable.\r
+\r
+  @param  TimingData          Timing data to be loaded from NVRAM.\r
+  @param  RowConfArray        Row configuration information for each row in the system.\r
+\r
+  @return EFI_SUCCESS         The function completed successfully.\r
+          Other               Could not read variable.\r
+\r
+**/\r
+EFI_STATUS\r
+LoadConfig (\r
+  IN      EFI_PEI_SERVICES                        **PeiServices,\r
+  IN      EFI_PEI_READ_ONLY_VARIABLE2_PPI         *VariableServices,\r
+  IN OUT  MRC_PARAMS                              *MrcData\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 BufferSize;\r
+  PLATFORM_VARIABLE_MEMORY_CONFIG_DATA  VarData;\r
+\r
+  BufferSize = ((sizeof (VarData.timings) + 0x7) & (~0x7));  // HOB data size (stored in variable) is required to be multiple of 8bytes\r
+\r
+  Status = VariableServices->GetVariable (\r
+                               VariableServices,\r
+                               EFI_MEMORY_CONFIG_DATA_NAME,\r
+                               &gEfiMemoryConfigDataGuid,\r
+                               NULL,\r
+                               &BufferSize,\r
+                               &VarData.timings\r
+                               );\r
+  if (!EFI_ERROR (Status)) {\r
+    CopyMem (&MrcData->timings, &VarData.timings, sizeof(MrcData->timings));\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  This function installs memory.\r
+\r
+  @param   PeiServices    PEI Services table.\r
+  @param   BootMode       The specific boot path that is being followed\r
+  @param   Mch            Pointer to the DualChannelDdrMemoryInit PPI\r
+  @param   RowConfArray   Row configuration information for each row in the system.\r
+\r
+  @return  EFI_SUCCESS            The function completed successfully.\r
+           EFI_INVALID_PARAMETER  One of the input parameters was invalid.\r
+           EFI_ABORTED            An error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+InstallEfiMemory (\r
+  IN      EFI_PEI_SERVICES                           **PeiServices,\r
+  IN      EFI_PEI_READ_ONLY_VARIABLE2_PPI            *VariableServices,\r
+  IN      EFI_BOOT_MODE                              BootMode,\r
+  IN      UINT32                                     TotalMemorySize\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS                  PeiMemoryBaseAddress;\r
+  EFI_SMRAM_HOB_DESCRIPTOR_BLOCK        *SmramHobDescriptorBlock;\r
+  EFI_STATUS                            Status;\r
+  EFI_PEI_HOB_POINTERS                  Hob;\r
+  PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES];\r
+  UINT8                                 Index;\r
+  UINT8                                 NumRanges;\r
+  UINT8                                 SmramIndex;\r
+  UINT8                                 SmramRanges;\r
+  UINT64                                PeiMemoryLength;\r
+  UINTN                                 BufferSize;\r
+  UINTN                                 PeiMemoryIndex;\r
+  UINTN                                 RequiredMemSize;\r
+  EFI_RESOURCE_ATTRIBUTE_TYPE           Attribute;\r
+  EFI_PHYSICAL_ADDRESS                  BadMemoryAddress;\r
+  EFI_SMRAM_DESCRIPTOR                  DescriptorAcpiVariable;\r
+  VOID                                  *CapsuleBuffer;\r
+  UINTN                                 CapsuleBufferLength;\r
+  PEI_CAPSULE_PPI                       *Capsule;\r
+  VOID                                  *LargeMemRangeBuf;\r
+  UINTN                                 LargeMemRangeBufLen;\r
+\r
+  //\r
+  // Test the memory from 1M->TOM\r
+  //\r
+  if (BootMode != BOOT_ON_FLASH_UPDATE) {\r
+    Status = BaseMemoryTest (\r
+              PeiServices,\r
+              0x100000,\r
+              (TotalMemorySize - 0x100000),\r
+              Quick,\r
+              &BadMemoryAddress\r
+              );\r
+  ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+\r
+  //\r
+  // Get the Memory Map\r
+  //\r
+  NumRanges = MAX_RANGES;\r
+\r
+  ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);\r
+\r
+  Status = GetMemoryMap (\r
+             PeiServices,\r
+             TotalMemorySize,\r
+             (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,\r
+             &NumRanges\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Find the highest memory range in processor native address space to give to\r
+  // PEI. Then take the top.\r
+  //\r
+  PeiMemoryBaseAddress = 0;\r
+\r
+  //\r
+  // Query the platform for the minimum memory size\r
+  //\r
+\r
+  Status = GetPlatformMemorySize (\r
+             PeiServices,\r
+             BootMode,\r
+             &PeiMemoryLength\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Get required memory size for ACPI use. This helps to put ACPI memory on the topest\r
+  //\r
+  RequiredMemSize = 0;\r
+  RetriveRequiredMemorySize (PeiServices, &RequiredMemSize);\r
+\r
+  PeiMemoryIndex = 0;\r
+\r
+  for (Index = 0; Index < NumRanges; Index++)\r
+  {\r
+    DEBUG ((EFI_D_INFO, "Found 0x%x bytes at ", MemoryMap[Index].RangeLength));\r
+    DEBUG ((EFI_D_INFO, "0x%x.\n", MemoryMap[Index].PhysicalAddress));\r
+\r
+    if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&\r
+        (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS) &&\r
+        (MemoryMap[Index].PhysicalAddress >= PeiMemoryBaseAddress) &&\r
+        (MemoryMap[Index].RangeLength >= PeiMemoryLength)) {\r
+      PeiMemoryBaseAddress = MemoryMap[Index].PhysicalAddress +\r
+                             MemoryMap[Index].RangeLength -\r
+                             PeiMemoryLength;\r
+      PeiMemoryIndex = Index;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Find the largest memory range excluding that given to PEI.\r
+  //\r
+  LargeMemRangeBuf = NULL;\r
+  LargeMemRangeBufLen = 0;\r
+  for (Index = 0; Index < NumRanges; Index++) {\r
+    if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&\r
+        (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < MAX_ADDRESS)) {\r
+          if (Index != PeiMemoryIndex) {\r
+            if (MemoryMap[Index].RangeLength > LargeMemRangeBufLen) {\r
+              LargeMemRangeBuf = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress);\r
+              LargeMemRangeBufLen = (UINTN) MemoryMap[Index].RangeLength;\r
+            }\r
+          } else {\r
+            if ((MemoryMap[Index].RangeLength - PeiMemoryLength) >= LargeMemRangeBufLen) {\r
+              LargeMemRangeBuf = (VOID *) ((UINTN) MemoryMap[Index].PhysicalAddress);\r
+              LargeMemRangeBufLen = (UINTN) (MemoryMap[Index].RangeLength - PeiMemoryLength);\r
+            }\r
+          }\r
+    }\r
+  }\r
+\r
+  Capsule             = NULL;\r
+  CapsuleBuffer       = NULL;\r
+  CapsuleBufferLength = 0;\r
+  if (BootMode == BOOT_ON_FLASH_UPDATE) {\r
+    Status = PeiServicesLocatePpi (\r
+               &gPeiCapsulePpiGuid,  // GUID\r
+               0,                    // INSTANCE\r
+               NULL,                 // EFI_PEI_PPI_DESCRIPTOR\r
+               (VOID **)&Capsule     // PPI\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    if (Status == EFI_SUCCESS) {\r
+      CapsuleBuffer = LargeMemRangeBuf;\r
+      CapsuleBufferLength = LargeMemRangeBufLen;\r
+\r
+      //\r
+      // Call the Capsule PPI Coalesce function to coalesce the capsule data.\r
+      //\r
+      Status = Capsule->Coalesce (\r
+                          PeiServices,\r
+                          &CapsuleBuffer,\r
+                          &CapsuleBufferLength\r
+                          );\r
+      //\r
+      // If it failed, then NULL out our capsule PPI pointer so that the capsule\r
+      // HOB does not get created below.\r
+      //\r
+      if (Status != EFI_SUCCESS) {\r
+        Capsule = NULL;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set up the IMR policy required for this platform\r
+  //\r
+  Status = SetPlatformImrPolicy (\r
+              PeiMemoryBaseAddress,\r
+              PeiMemoryLength,\r
+              RequiredMemSize\r
+              );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Carve out the top memory reserved for ACPI\r
+  //\r
+  Status        = PeiServicesInstallPeiMemory (PeiMemoryBaseAddress, (PeiMemoryLength - RequiredMemSize));\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  BuildResourceDescriptorHob (\r
+   EFI_RESOURCE_SYSTEM_MEMORY,                       // MemoryType,\r
+   (\r
+   EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+   EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+   EFI_RESOURCE_ATTRIBUTE_TESTED |\r
+   EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+   EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+   EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+   EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+   ),\r
+   PeiMemoryBaseAddress,                             // MemoryBegin\r
+   PeiMemoryLength                                   // MemoryLength\r
+   );\r
+\r
+  //\r
+  // Install physical memory descriptor hobs for each memory range.\r
+  //\r
+  SmramRanges = 0;\r
+  for (Index = 0; Index < NumRanges; Index++) {\r
+    Attribute = 0;\r
+    if (MemoryMap[Index].Type == DualChannelDdrMainMemory)\r
+    {\r
+      if (Index == PeiMemoryIndex) {\r
+        //\r
+        // This is a partially tested Main Memory range, give it to EFI\r
+        //\r
+        BuildResourceDescriptorHob (\r
+          EFI_RESOURCE_SYSTEM_MEMORY,\r
+          (\r
+          EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+          EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+          EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+          EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+          EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+          EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+          ),\r
+          MemoryMap[Index].PhysicalAddress,\r
+          MemoryMap[Index].RangeLength - PeiMemoryLength\r
+          );\r
+      } else {\r
+        //\r
+        // This is an untested Main Memory range, give it to EFI\r
+        //\r
+        BuildResourceDescriptorHob (\r
+          EFI_RESOURCE_SYSTEM_MEMORY,       // MemoryType,\r
+          (\r
+          EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+          EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+          EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+          EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+          EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+          EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+          ),\r
+          MemoryMap[Index].PhysicalAddress, // MemoryBegin\r
+          MemoryMap[Index].RangeLength      // MemoryLength\r
+          );\r
+      }\r
+    } else {\r
+      if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
+          (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {\r
+        SmramRanges++;\r
+      }\r
+      if ((MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable) ||\r
+          (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryNonCacheable)) {\r
+        Attribute |= EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;\r
+      }\r
+      if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable)         ||\r
+          (MemoryMap[Index].Type == DualChannelDdrGraphicsMemoryCacheable)) {\r
+        //\r
+        // TSEG and HSEG can be used with a write-back(WB) cache policy; however,\r
+        // the specification requires that the TSEG and HSEG space be cached only\r
+        // inside of the SMI handler. when using HSEG or TSEG an IA-32 processor\r
+        // does not automatically write back and invalidate its cache before entering\r
+        // SMM or before existing SMM therefore any MTRR defined for the active TSEG\r
+        // or HSEG must be set to un-cacheable(UC) outside of SMM.\r
+        //\r
+        Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;\r
+      }\r
+      if (MemoryMap[Index].Type == DualChannelDdrReservedMemory) {\r
+        Attribute |= EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |\r
+                     EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE;\r
+      }\r
+      //\r
+      // Make sure non-system memory is marked as reserved\r
+      //\r
+      BuildResourceDescriptorHob (\r
+        EFI_RESOURCE_MEMORY_RESERVED,     // MemoryType,\r
+        Attribute,                        // MemoryAttribute\r
+        MemoryMap[Index].PhysicalAddress, // MemoryBegin\r
+        MemoryMap[Index].RangeLength      // MemoryLength\r
+        );\r
+    }\r
+  }\r
+\r
+  //\r
+  // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer\r
+  // to the SMM Services Table that is required on the S3 resume path\r
+  //\r
+  ASSERT (SmramRanges > 0);\r
+  BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);\r
+  BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));\r
+\r
+  Hob.Raw = BuildGuidHob (\r
+              &gEfiSmmPeiSmramMemoryReserveGuid,\r
+              BufferSize\r
+              );\r
+  ASSERT (Hob.Raw);\r
+\r
+  SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);\r
+  SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;\r
+\r
+  SmramIndex = 0;\r
+  for (Index = 0; Index < NumRanges; Index++) {\r
+    if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
+        (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)\r
+        ) {\r
+      //\r
+      // This is an SMRAM range, create an SMRAM descriptor\r
+      //\r
+      SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress;\r
+      SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart      = MemoryMap[Index].CpuAddress;\r
+      SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize  = MemoryMap[Index].RangeLength;\r
+      if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) {\r
+        SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;\r
+      } else {\r
+        SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;\r
+      }\r
+\r
+      SmramIndex++;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Build a HOB with the location of the reserved memory range.\r
+  //\r
+  CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));\r
+  DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;\r
+  BuildGuidDataHob (\r
+    &gEfiAcpiVariableGuid,\r
+    &DescriptorAcpiVariable,\r
+    sizeof (EFI_SMRAM_DESCRIPTOR)\r
+    );\r
+\r
+  //\r
+  // If we found the capsule PPI (and we didn't have errors), then\r
+  // call the capsule PEIM to allocate memory for the capsule.\r
+  //\r
+  if (Capsule != NULL) {\r
+    Status = Capsule->CreateState (PeiServices, CapsuleBuffer, CapsuleBufferLength);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Find memory that is reserved so PEI has some to use.\r
+\r
+  @param  PeiServices      PEI Services table.\r
+  @param  VariableSevices  Variable PPI instance.\r
+\r
+  @return EFI_SUCCESS  The function completed successfully.\r
+                       Error value from LocatePpi()\r
+                       Error Value from VariableServices->GetVariable()\r
+\r
+**/\r
+EFI_STATUS\r
+InstallS3Memory (\r
+  IN      EFI_PEI_SERVICES                      **PeiServices,\r
+  IN      EFI_PEI_READ_ONLY_VARIABLE2_PPI       *VariableServices,\r
+  IN      UINT32                                TotalMemorySize\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 S3MemoryBase;\r
+  UINTN                                 S3MemorySize;\r
+  UINT8                                 SmramRanges;\r
+  UINT8                                 NumRanges;\r
+  UINT8                                 Index;\r
+  UINT8                                 SmramIndex;\r
+  UINTN                                 BufferSize;\r
+  EFI_PEI_HOB_POINTERS                  Hob;\r
+  EFI_SMRAM_HOB_DESCRIPTOR_BLOCK        *SmramHobDescriptorBlock;\r
+  PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE MemoryMap[MAX_RANGES];\r
+  RESERVED_ACPI_S3_RANGE                *S3MemoryRangeData;\r
+  EFI_SMRAM_DESCRIPTOR                  DescriptorAcpiVariable;\r
+\r
+  //\r
+  // Get the Memory Map\r
+  //\r
+  NumRanges = MAX_RANGES;\r
+\r
+  ZeroMem (MemoryMap, sizeof (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE) * NumRanges);\r
+\r
+  Status = GetMemoryMap (\r
+             PeiServices,\r
+             TotalMemorySize,\r
+             (PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE *) MemoryMap,\r
+             &NumRanges\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Install physical memory descriptor hobs for each memory range.\r
+  //\r
+  SmramRanges = 0;\r
+  for (Index = 0; Index < NumRanges; Index++) {\r
+    if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable)    ||\r
+       (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)) {\r
+      SmramRanges++;\r
+    }\r
+  }\r
+\r
+  ASSERT (SmramRanges > 0);\r
+\r
+  //\r
+  // Allocate one extra EFI_SMRAM_DESCRIPTOR to describe a page of SMRAM memory that contains a pointer\r
+  // to the SMM Services Table that is required on the S3 resume path\r
+  //\r
+  BufferSize = sizeof (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK);\r
+  if (SmramRanges > 0) {\r
+    BufferSize += ((SmramRanges - 1) * sizeof (EFI_SMRAM_DESCRIPTOR));\r
+  }\r
+\r
+  Hob.Raw = BuildGuidHob (\r
+              &gEfiSmmPeiSmramMemoryReserveGuid,\r
+              BufferSize\r
+              );\r
+  ASSERT (Hob.Raw);\r
+\r
+  SmramHobDescriptorBlock = (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) (Hob.Raw);\r
+  SmramHobDescriptorBlock->NumberOfSmmReservedRegions = SmramRanges;\r
+\r
+  SmramIndex = 0;\r
+  for (Index = 0; Index < NumRanges; Index++) {\r
+    if ((MemoryMap[Index].Type == DualChannelDdrSmramCacheable) ||\r
+        (MemoryMap[Index].Type == DualChannelDdrSmramNonCacheable)\r
+        ) {\r
+      //\r
+      // This is an SMRAM range, create an SMRAM descriptor\r
+      //\r
+      SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalStart = MemoryMap[Index].PhysicalAddress;\r
+      SmramHobDescriptorBlock->Descriptor[SmramIndex].CpuStart      = MemoryMap[Index].CpuAddress;\r
+      SmramHobDescriptorBlock->Descriptor[SmramIndex].PhysicalSize  = MemoryMap[Index].RangeLength;\r
+      if (MemoryMap[Index].Type == DualChannelDdrSmramCacheable) {\r
+        SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED | EFI_CACHEABLE;\r
+      } else {\r
+        SmramHobDescriptorBlock->Descriptor[SmramIndex].RegionState = EFI_SMRAM_CLOSED;\r
+      }\r
+\r
+      SmramIndex++;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Build a HOB with the location of the reserved memory range.\r
+  //\r
+  CopyMem(&DescriptorAcpiVariable, &SmramHobDescriptorBlock->Descriptor[SmramRanges-1], sizeof(EFI_SMRAM_DESCRIPTOR));\r
+  DescriptorAcpiVariable.CpuStart += RESERVED_CPU_S3_SAVE_OFFSET;\r
+  BuildGuidDataHob (\r
+    &gEfiAcpiVariableGuid,\r
+    &DescriptorAcpiVariable,\r
+    sizeof (EFI_SMRAM_DESCRIPTOR)\r
+    );\r
+\r
+  //\r
+  // Get the location and size of the S3 memory range in the reserved page and\r
+  // install it as PEI Memory.\r
+  //\r
+\r
+  DEBUG ((EFI_D_INFO, "TSEG Base = 0x%08x\n", SmramHobDescriptorBlock->Descriptor[SmramRanges-1].PhysicalStart));\r
+  S3MemoryRangeData = (RESERVED_ACPI_S3_RANGE*)(UINTN)\r
+    (SmramHobDescriptorBlock->Descriptor[SmramRanges-1].PhysicalStart + RESERVED_ACPI_S3_RANGE_OFFSET);\r
+\r
+  S3MemoryBase  = (UINTN) (S3MemoryRangeData->AcpiReservedMemoryBase);\r
+  DEBUG ((EFI_D_INFO, "S3MemoryBase = 0x%08x\n", S3MemoryBase));\r
+  S3MemorySize  = (UINTN) (S3MemoryRangeData->AcpiReservedMemorySize);\r
+  DEBUG ((EFI_D_INFO, "S3MemorySize = 0x%08x\n", S3MemorySize));\r
+\r
+  Status        = PeiServicesInstallPeiMemory (S3MemoryBase, S3MemorySize);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Retrieve the system memory length and build memory hob for the system\r
+  // memory above 1MB. So Memory Callback can set cache for the system memory\r
+  // correctly on S3 boot path, just like it does on Normal boot path.\r
+  //\r
+  ASSERT_EFI_ERROR ((S3MemoryRangeData->SystemMemoryLength - 0x100000) > 0);\r
+  BuildResourceDescriptorHob (\r
+            EFI_RESOURCE_SYSTEM_MEMORY,\r
+            (\r
+            EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+            EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+            EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+            EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+            EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+            EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+            ),\r
+            0x100000,\r
+            S3MemoryRangeData->SystemMemoryLength - 0x100000\r
+            );\r
+\r
+  for (Index = 0; Index < NumRanges; Index++) {\r
+    if ((MemoryMap[Index].Type == DualChannelDdrMainMemory) &&\r
+        (MemoryMap[Index].PhysicalAddress + MemoryMap[Index].RangeLength < 0x100000)) {\r
+      BuildResourceDescriptorHob (\r
+        EFI_RESOURCE_SYSTEM_MEMORY,\r
+        (\r
+        EFI_RESOURCE_ATTRIBUTE_PRESENT |\r
+        EFI_RESOURCE_ATTRIBUTE_INITIALIZED |\r
+        EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |\r
+        EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |\r
+        EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |\r
+        EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE\r
+        ),\r
+        MemoryMap[Index].PhysicalAddress,\r
+        MemoryMap[Index].RangeLength\r
+        );\r
+      DEBUG ((EFI_D_INFO, "Build resource HOB for Legacy Region on S3 patch :"));\r
+      DEBUG ((EFI_D_INFO, " Memory Base:0x%lX Length:0x%lX\n", MemoryMap[Index].PhysicalAddress, MemoryMap[Index].RangeLength));\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  This function returns the size, in bytes, required for the DXE phase.\r
+\r
+  @param  PeiServices    PEI Services table.\r
+  @param  Size           Pointer to the size, in bytes, required for the DXE phase.\r
+\r
+  @return  None\r
+\r
+**/\r
+VOID\r
+RetriveRequiredMemorySize (\r
+  IN      EFI_PEI_SERVICES                  **PeiServices,\r
+  OUT     UINTN                             *Size\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_PEI_HOB_POINTERS           Hob;\r
+  EFI_MEMORY_TYPE_INFORMATION    *MemoryData;\r
+  UINT8                          Index;\r
+  UINTN                          TempPageNum;\r
+\r
+  MemoryData  = NULL;\r
+  TempPageNum = 0;\r
+  Index       = 0;\r
+\r
+  Status      = PeiServicesGetHobList ((VOID **)&Hob.Raw);\r
+  while (!END_OF_HOB_LIST (Hob)) {\r
+    if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION &&\r
+        CompareGuid (&Hob.Guid->Name, &gEfiMemoryTypeInformationGuid)\r
+          ) {\r
+      MemoryData = (EFI_MEMORY_TYPE_INFORMATION *) (Hob.Raw + sizeof (EFI_HOB_GENERIC_HEADER) + sizeof (EFI_GUID));\r
+      break;\r
+    }\r
+\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+  }\r
+  //\r
+  // Platform PEIM should supply such a information. Generic PEIM doesn't assume any default value\r
+  //\r
+  if (!MemoryData) {\r
+    return ;\r
+  }\r
+\r
+  while (MemoryData[Index].Type != EfiMaxMemoryType) {\r
+    //\r
+    // Accumulate default memory size requirements\r
+    //\r
+    TempPageNum += MemoryData[Index].NumberOfPages;\r
+    Index++;\r
+  }\r
+\r
+  if (TempPageNum == 0) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Add additional pages used by DXE memory manager\r
+  //\r
+  (*Size) = (TempPageNum + EDKII_DXE_MEM_SIZE_PAGES) * EFI_PAGE_SIZE;\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+\r
+  This function returns the memory ranges to be enabled, along with information\r
+  describing how the range should be used.\r
+\r
+  @param  PeiServices   PEI Services Table.\r
+  @param  TimingData    Detected DDR timing parameters for installed memory.\r
+  @param  RowConfArray  Pointer to an array of EFI_DUAL_CHANNEL_DDR_ROW_CONFIG structures. The number\r
+                        of items in the array must match MaxRows returned by the McGetRowInfo() function.\r
+  @param  MemoryMap     Buffer to record details of the memory ranges tobe enabled.\r
+  @param  NumRanges     On input, this contains the maximum number of memory ranges that can be described\r
+                        in the MemoryMap buffer.\r
+\r
+  @return MemoryMap     The buffer will be filled in\r
+          NumRanges     will contain the actual number of memory ranges that are to be anabled.\r
+          EFI_SUCCESS   The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetMemoryMap (\r
+  IN     EFI_PEI_SERVICES                                    **PeiServices,\r
+  IN     UINT32                                              TotalMemorySize,\r
+  IN OUT PEI_DUAL_CHANNEL_DDR_MEMORY_MAP_RANGE               *MemoryMap,\r
+  IN OUT UINT8                                               *NumRanges\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS              MemorySize;\r
+  EFI_PHYSICAL_ADDRESS              RowLength;\r
+  EFI_STATUS                        Status;\r
+  PEI_MEMORY_RANGE_PCI_MEMORY       PciMemoryMask;\r
+  PEI_MEMORY_RANGE_OPTION_ROM       OptionRomMask;\r
+  PEI_MEMORY_RANGE_SMRAM            SmramMask;\r
+  PEI_MEMORY_RANGE_SMRAM            TsegMask;\r
+  UINT32                            BlockNum;\r
+  UINT8                             EsmramcRegister;\r
+  UINT8                             ExtendedMemoryIndex;\r
+  UINT32                            Register;\r
+\r
+  if ((*NumRanges) < MAX_RANGES) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  *NumRanges = 0;\r
+\r
+  //\r
+  // Find out which memory ranges to reserve on this platform\r
+  //\r
+  Status = ChooseRanges (\r
+             &OptionRomMask,\r
+             &SmramMask,\r
+             &PciMemoryMask\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Generate Memory ranges for the memory map.\r
+  //\r
+  EsmramcRegister = 0;\r
+  MemorySize = 0;\r
+\r
+  RowLength = TotalMemorySize;\r
+\r
+  //\r
+  // Add memory below 640KB to the memory map. Make sure memory between\r
+  // 640KB and 1MB are reserved, even if not used for SMRAM\r
+  //\r
+  MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
+  MemoryMap[*NumRanges].CpuAddress      = MemorySize;\r
+  MemoryMap[*NumRanges].RangeLength     = 0xA0000;\r
+  MemoryMap[*NumRanges].Type            = DualChannelDdrMainMemory;\r
+  (*NumRanges)++;\r
+\r
+  //\r
+  // Just mark this range reserved\r
+  //\r
+  MemoryMap[*NumRanges].PhysicalAddress = 0xA0000;\r
+  MemoryMap[*NumRanges].CpuAddress      = 0xA0000;\r
+  MemoryMap[*NumRanges].RangeLength     = 0x60000;\r
+  MemoryMap[*NumRanges].Type            = DualChannelDdrReservedMemory;\r
+  (*NumRanges)++;\r
+\r
+  RowLength -= (0x100000 - MemorySize);\r
+  MemorySize = 0x100000;\r
+\r
+  //\r
+  // Add remaining memory to the memory map\r
+  //\r
+  MemoryMap[*NumRanges].PhysicalAddress = MemorySize;\r
+  MemoryMap[*NumRanges].CpuAddress      = MemorySize;\r
+  MemoryMap[*NumRanges].RangeLength     = RowLength;\r
+  MemoryMap[*NumRanges].Type            = DualChannelDdrMainMemory;\r
+  (*NumRanges)++;\r
+  MemorySize += RowLength;\r
+\r
+  ExtendedMemoryIndex = (UINT8) (*NumRanges - 1);\r
+\r
+  // See if we need to trim TSEG out of the highest memory range\r
+  //\r
+  if (SmramMask & PEI_MR_SMRAM_TSEG_MASK) {//pcd\r
+    //\r
+    // Create the new range for TSEG and remove that range from the previous SdrDdrMainMemory range\r
+    //\r
+    TsegMask  = (SmramMask & PEI_MR_SMRAM_SIZE_MASK);\r
+\r
+    BlockNum  = 1;\r
+    while (TsegMask) {\r
+      TsegMask >>= 1;\r
+      BlockNum <<= 1;\r
+    }\r
+\r
+    BlockNum >>= 1;\r
+\r
+    if (BlockNum) {\r
+\r
+      MemoryMap[*NumRanges].RangeLength           = (BlockNum * 128 * 1024);\r
+      Register = (UINT32)((MemorySize - 1) & SMM_END_MASK);\r
+      MemorySize                                 -= MemoryMap[*NumRanges].RangeLength;\r
+      MemoryMap[*NumRanges].PhysicalAddress       = MemorySize;\r
+      MemoryMap[*NumRanges].CpuAddress            = MemorySize;\r
+      MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength;\r
+\r
+      //\r
+      // Update QuarkNcSoc HSMMCTL register\r
+      //\r
+      Register |= (UINT32)(((RShiftU64(MemorySize, 16)) & SMM_START_MASK) + (SMM_WRITE_OPEN | SMM_READ_OPEN | SMM_CODE_RD_OPEN));\r
+      QncHsmmcWrite (Register);\r
+    }\r
+\r
+    //\r
+    // Chipset only supports cacheable SMRAM\r
+    //\r
+    MemoryMap[*NumRanges].Type = DualChannelDdrSmramCacheable;\r
+\r
+    (*NumRanges)++;\r
+  }\r
+\r
+  //\r
+  // trim 64K memory from highest memory range for Rmu Main binary shadow\r
+  //\r
+  MemoryMap[*NumRanges].RangeLength           = 0x10000;\r
+  MemorySize                                 -= MemoryMap[*NumRanges].RangeLength;\r
+  MemoryMap[*NumRanges].PhysicalAddress       = MemorySize;\r
+  MemoryMap[*NumRanges].CpuAddress            = MemorySize;\r
+  MemoryMap[ExtendedMemoryIndex].RangeLength -= MemoryMap[*NumRanges].RangeLength;\r
+  MemoryMap[*NumRanges].Type = DualChannelDdrReservedMemory;\r
+  (*NumRanges)++;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+Routine Description:\r
+\r
+  Fill in bit masks to specify reserved memory ranges on the Lakeport platform\r
+\r
+Arguments:\r
+\r
+Returns:\r
+\r
+  OptionRomMask - Bit mask specifying memory regions reserved for Legacy option\r
+                  ROM use (if any)\r
+\r
+  SmramMask - Bit mask specifying memory regions reserved for SMM use (if any)\r
+\r
+**/\r
+EFI_STATUS\r
+ChooseRanges (\r
+  IN OUT   PEI_MEMORY_RANGE_OPTION_ROM           *OptionRomMask,\r
+  IN OUT   PEI_MEMORY_RANGE_SMRAM                *SmramMask,\r
+  IN OUT   PEI_MEMORY_RANGE_PCI_MEMORY           *PciMemoryMask\r
+  )\r
+{\r
+\r
+  //\r
+  // Choose regions to reserve for Option ROM use\r
+  //\r
+  *OptionRomMask = PEI_MR_OPTION_ROM_NONE;\r
+\r
+  //\r
+  // Choose regions to reserve for SMM use (AB/H SEG and TSEG). Size is in 128K blocks\r
+  //\r
+  *SmramMask = PEI_MR_SMRAM_CACHEABLE_MASK | PEI_MR_SMRAM_TSEG_MASK | ((PcdGet32(PcdTSegSize)) >> 17);\r
+\r
+  *PciMemoryMask = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+GetPlatformMemorySize (\r
+  IN       EFI_PEI_SERVICES                       **PeiServices,\r
+  IN       EFI_BOOT_MODE                          BootMode,\r
+  IN OUT   UINT64                                 *MemorySize\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_PEI_READ_ONLY_VARIABLE2_PPI       *Variable;\r
+  UINTN                                 DataSize;\r
+  EFI_MEMORY_TYPE_INFORMATION           MemoryData [EfiMaxMemoryType + 1];\r
+  UINTN                                 Index;\r
+\r
+  DataSize = sizeof (MemoryData);\r
+\r
+  if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
+\r
+    //\r
+    // // Treat recovery as if variable not found (eg 1st boot).\r
+    //\r
+    Status = EFI_NOT_FOUND;\r
+\r
+  } else {\r
+    Status = PeiServicesLocatePpi (\r
+               &gEfiPeiReadOnlyVariable2PpiGuid,\r
+               0,\r
+               NULL,\r
+               (VOID **)&Variable\r
+               );\r
+\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    DataSize = sizeof (MemoryData);\r
+    Status = Variable->GetVariable (\r
+                         Variable,\r
+                         EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,\r
+                         &gEfiMemoryTypeInformationGuid,\r
+                         NULL,\r
+                         &DataSize,\r
+                         &MemoryData\r
+                         );\r
+  }\r
+\r
+  //\r
+  // Accumulate maximum amount of memory needed\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Start with minimum memory\r
+    //\r
+    *MemorySize = PEI_MIN_MEMORY_SIZE;\r
+\r
+    for (Index = 0; Index < sizeof(mDefaultQncMemoryTypeInformation) / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) {\r
+        *MemorySize += mDefaultQncMemoryTypeInformation[Index].NumberOfPages * EFI_PAGE_SIZE;\r
+    }\r
+\r
+    //\r
+    // Build the GUID'd HOB for DXE\r
+    //\r
+    BuildGuidDataHob (\r
+                 &gEfiMemoryTypeInformationGuid,\r
+                 mDefaultQncMemoryTypeInformation,\r
+                 sizeof(mDefaultQncMemoryTypeInformation)\r
+                 );\r
+  } else {\r
+    //\r
+    // Start with at least PEI_MIN_MEMORY_SIZE pages of memory for the DXE Core and the DXE Stack\r
+    //\r
+\r
+    *MemorySize = PEI_MIN_MEMORY_SIZE;\r
+    for (Index = 0; Index < DataSize / sizeof (EFI_MEMORY_TYPE_INFORMATION); Index++) {\r
+      DEBUG ((EFI_D_INFO, "Index %d, Page: %d\n", Index, MemoryData[Index].NumberOfPages));\r
+      *MemorySize += MemoryData[Index].NumberOfPages * EFI_PAGE_SIZE;\r
+    }\r
+\r
+    //\r
+    // Build the GUID'd HOB for DXE\r
+    //\r
+    BuildGuidDataHob (\r
+                 &gEfiMemoryTypeInformationGuid,\r
+                 MemoryData,\r
+                 DataSize\r
+                 );\r
+\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+EFI_STATUS\r
+BaseMemoryTest (\r
+  IN  EFI_PEI_SERVICES                   **PeiServices,\r
+  IN  EFI_PHYSICAL_ADDRESS               BeginAddress,\r
+  IN  UINT64                             MemoryLength,\r
+  IN  PEI_MEMORY_TEST_OP                 Operation,\r
+  OUT EFI_PHYSICAL_ADDRESS               *ErrorAddress\r
+  )\r
+{\r
+  UINT32                TestPattern;\r
+  EFI_PHYSICAL_ADDRESS  TempAddress;\r
+  UINT32                SpanSize;\r
+\r
+  TestPattern = 0x5A5A5A5A;\r
+  SpanSize    = 0;\r
+\r
+  //\r
+  // Make sure we don't try and test anything above the max physical address range\r
+  //\r
+  ASSERT (BeginAddress + MemoryLength < MAX_ADDRESS);\r
+\r
+  switch (Operation) {\r
+  case Extensive:\r
+    SpanSize = 0x4;\r
+    break;\r
+\r
+  case Sparse:\r
+  case Quick:\r
+    SpanSize = 0x40000;\r
+    break;\r
+\r
+  case Ignore:\r
+    goto Done;\r
+    break;\r
+  }\r
+  //\r
+  // Write the test pattern into memory range\r
+  //\r
+  TempAddress = BeginAddress;\r
+  while (TempAddress < BeginAddress + MemoryLength) {\r
+    (*(UINT32 *) (UINTN) TempAddress) = TestPattern;\r
+    TempAddress += SpanSize;\r
+  }\r
+  //\r
+  // Read pattern from memory and compare it\r
+  //\r
+  TempAddress = BeginAddress;\r
+  while (TempAddress < BeginAddress + MemoryLength) {\r
+    if ((*(UINT32 *) (UINTN) TempAddress) != TestPattern) {\r
+      *ErrorAddress = TempAddress;\r
+      DEBUG ((EFI_D_ERROR, "Memory test failed at 0x%x.\n", TempAddress));\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    TempAddress += SpanSize;\r
+  }\r
+\r
+Done:\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  This function sets up the platform specific IMR protection for the various\r
+  memory regions.\r
+\r
+  @param  PeiMemoryBaseAddress  Base address of memory allocated for PEI.\r
+  @param  PeiMemoryLength       Length in bytes of the PEI memory (includes ACPI memory).\r
+  @param  RequiredMemSize       Size in bytes of the ACPI/Runtime memory\r
+\r
+  @return EFI_SUCCESS           The function completed successfully.\r
+          EFI_ACCESS_DENIED     Access to IMRs failed.\r
+\r
+**/\r
+EFI_STATUS\r
+SetPlatformImrPolicy (\r
+  IN      EFI_PHYSICAL_ADDRESS    PeiMemoryBaseAddress,\r
+  IN      UINT64                  PeiMemoryLength,\r
+  IN      UINTN                   RequiredMemSize\r
+  )\r
+{\r
+  UINT8         Index;\r
+  UINT32        Register;\r
+  UINT16        DeviceId;\r
+\r
+  //\r
+  // Check what Soc we are running on (read Host bridge DeviceId)\r
+  //\r
+  DeviceId = QNCMmPci16(0, MC_BUS, MC_DEV, MC_FUN, PCI_DEVICE_ID_OFFSET);\r
+\r
+  //\r
+  // If any IMR register is locked then we cannot proceed\r
+  //\r
+  for (Index = (QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL); Index <=(QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL); Index=Index+4)\r
+  {\r
+    Register = QNCPortRead (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, Index);\r
+    if (Register & IMR_LOCK) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Add IMR0 protection for the 'PeiMemory'\r
+  //\r
+  QncImrWrite (\r
+            QUARK_NC_MEMORY_MANAGER_IMR0,\r
+            (UINT32)(((RShiftU64(PeiMemoryBaseAddress, 8)) & IMRL_MASK) | IMR_EN),\r
+            (UINT32)((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength-RequiredMemSize + EFI_PAGES_TO_SIZE(EDKII_DXE_MEM_SIZE_PAGES-1) - 1), 8)) & IMRL_MASK),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+        );\r
+\r
+  //\r
+  // Add IMR2 protection for shadowed RMU binary.\r
+  //\r
+  QncImrWrite (\r
+            QUARK_NC_MEMORY_MANAGER_IMR2,\r
+            (UINT32)(((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength), 8)) & IMRH_MASK) | IMR_EN),\r
+            (UINT32)((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength+PcdGet32(PcdFlashQNCMicrocodeSize)-1), 8)) & IMRH_MASK),\r
+            (UINT32)(CPU_SNOOP + RMU + CPU0_NON_SMM),\r
+            (UINT32)(CPU_SNOOP + RMU + CPU0_NON_SMM)\r
+        );\r
+\r
+  //\r
+  // Add IMR3 protection for the default SMRAM.\r
+  //\r
+  QncImrWrite (\r
+            QUARK_NC_MEMORY_MANAGER_IMR3,\r
+            (UINT32)(((RShiftU64((SMM_DEFAULT_SMBASE), 8)) & IMRL_MASK) | IMR_EN),\r
+            (UINT32)((RShiftU64((SMM_DEFAULT_SMBASE+SMM_DEFAULT_SMBASE_SIZE_BYTES-1), 8)) & IMRH_MASK),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+        );\r
+\r
+  //\r
+  // Add IMR5 protection for the legacy S3 and AP Startup Vector region (below 1MB).\r
+  //\r
+  QncImrWrite (\r
+            QUARK_NC_MEMORY_MANAGER_IMR5,\r
+            (UINT32)(((RShiftU64(AP_STARTUP_VECTOR, 8)) & IMRL_MASK) | IMR_EN),\r
+            (UINT32)((RShiftU64((AP_STARTUP_VECTOR + EFI_PAGE_SIZE - 1), 8)) & IMRH_MASK),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+        );\r
+\r
+  //\r
+  // Add IMR6 protection for the ACPI Reclaim/ACPI/Runtime Services.\r
+  //\r
+  QncImrWrite (\r
+            QUARK_NC_MEMORY_MANAGER_IMR6,\r
+            (UINT32)(((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength-RequiredMemSize+EFI_PAGES_TO_SIZE(EDKII_DXE_MEM_SIZE_PAGES-1)), 8)) & IMRL_MASK) | IMR_EN),\r
+            (UINT32)((RShiftU64((PeiMemoryBaseAddress+PeiMemoryLength-EFI_PAGE_SIZE-1), 8)) & IMRH_MASK),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+        );\r
+\r
+  //\r
+  // Enable IMR4 protection of eSRAM.\r
+  //\r
+  QncImrWrite (\r
+            QUARK_NC_MEMORY_MANAGER_IMR4,\r
+            (UINT32)(((RShiftU64((UINTN)PcdGet32 (PcdEsramStage1Base), 8)) & IMRL_MASK) | IMR_EN),\r
+            (UINT32)((RShiftU64(((UINTN)PcdGet32 (PcdEsramStage1Base) + (UINTN)PcdGet32 (PcdESramMemorySize) - 1), 8)) & IMRH_MASK),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM),\r
+            (UINT32)(CPU_SNOOP + CPU0_NON_SMM)\r
+        );\r
+\r
+  //\r
+  // Enable Interrupt on IMR/SMM Violation\r
+  //\r
+  QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BIMRVCTL, (UINT32)(EnableIMRInt));\r
+  if (DeviceId == QUARK2_MC_DEVICE_ID) {\r
+    QNCPortWrite (QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_BSMMVCTL, (UINT32)(EnableSMMInt));\r
+  }\r
+\r
+  //\r
+  // Disable IMR7 memory protection (eSRAM + DDR3 memory) since our policies\r
+  // are now setup.\r
+  //\r
+  QncImrWrite (\r
+            QUARK_NC_MEMORY_MANAGER_IMR7,\r
+            (UINT32)(IMRL_RESET & ~IMR_EN),\r
+            (UINT32)IMRH_RESET,\r
+            (UINT32)IMRX_ALL_ACCESS,\r
+            (UINT32)IMRX_ALL_ACCESS\r
+        );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/** Return info derived from Installing Memory by MemoryInit.\r
+\r
+  @param[out]      RmuMainBaseAddressPtr   Return RmuMainBaseAddress to this location.\r
+  @param[out]      SmramDescriptorPtr  Return start of Smram descriptor list to this location.\r
+  @param[out]      NumSmramRegionsPtr  Return numbers of Smram regions to this location.\r
+\r
+  @return Address of RMU shadow region at the top of available memory.\r
+  @return List of Smram descriptors for each Smram region.\r
+  @return Numbers of Smram regions.\r
+**/\r
+VOID\r
+EFIAPI\r
+InfoPostInstallMemory (\r
+  OUT     UINT32                    *RmuMainBaseAddressPtr OPTIONAL,\r
+  OUT     EFI_SMRAM_DESCRIPTOR      **SmramDescriptorPtr OPTIONAL,\r
+  OUT     UINTN                     *NumSmramRegionsPtr OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_PEI_HOB_POINTERS                  Hob;\r
+  UINT64                                CalcLength;\r
+  EFI_SMRAM_HOB_DESCRIPTOR_BLOCK        *SmramHobDescriptorBlock;\r
+\r
+  if ((RmuMainBaseAddressPtr == NULL) && (SmramDescriptorPtr == NULL) && (NumSmramRegionsPtr == NULL)) {\r
+    return;\r
+  }\r
+\r
+  SmramHobDescriptorBlock = NULL;\r
+  if (SmramDescriptorPtr != NULL) {\r
+    *SmramDescriptorPtr = NULL;\r
+  }\r
+  if (NumSmramRegionsPtr != NULL) {\r
+    *NumSmramRegionsPtr = 0;\r
+  }\r
+\r
+  //\r
+  // Calculate RMU shadow region base address.\r
+  // Set to 1 MB. Since 1MB cacheability will always be set\r
+  // until override by CSM.\r
+  //\r
+  CalcLength = 0x100000;\r
+\r
+  Status = PeiServicesGetHobList ((VOID **) &Hob.Raw);\r
+  ASSERT_EFI_ERROR (Status);\r
+  while (!END_OF_HOB_LIST (Hob)) {\r
+    if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\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
+          CalcLength += (UINT64) (Hob.ResourceDescriptor->ResourceLength);\r
+        }\r
+      }\r
+    } else if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) {\r
+      if (CompareGuid (&(Hob.Guid->Name), &gEfiSmmPeiSmramMemoryReserveGuid)) {\r
+        SmramHobDescriptorBlock = (VOID*) (Hob.Raw + sizeof (EFI_HOB_GUID_TYPE));\r
+        if (SmramDescriptorPtr != NULL) {\r
+          *SmramDescriptorPtr = SmramHobDescriptorBlock->Descriptor;\r
+        }\r
+        if (NumSmramRegionsPtr != NULL) {\r
+          *NumSmramRegionsPtr = SmramHobDescriptorBlock->NumberOfSmmReservedRegions;\r
+        }\r
+      }\r
+    }\r
+    Hob.Raw = GET_NEXT_HOB (Hob);\r
+  }\r
+\r
+  if (RmuMainBaseAddressPtr != NULL) {\r
+    *RmuMainBaseAddressPtr = (UINT32) CalcLength;\r
+  }\r
+}\r