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