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