]> git.proxmox.com Git - mirror_edk2.git/blob - QuarkPlatformPkg/Acpi/DxeSmm/AcpiSmm/AcpiSmmPlatform.c
f7f7ca3196e6e1912c73e06e4e26f301b4d85ae8
[mirror_edk2.git] / QuarkPlatformPkg / Acpi / DxeSmm / AcpiSmm / AcpiSmmPlatform.c
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 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*
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
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 (&gEfiSmmPeiSmramMemoryReserveGuid);
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
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
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
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
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
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
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
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
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