AcpiSmmPlatform.c 32 KB

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