| /** @file | |
| ACPISMM Driver implementation file. | |
| This is QNC Smm platform driver | |
| Copyright (c) 2013-2016 Intel Corporation. | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <AcpiSmmPlatform.h> | |
| #define PCILIB_TO_COMMON_ADDRESS(Address) \ | |
| ((UINT64) ((((UINTN) ((Address>>20) & 0xff)) << 24) + (((UINTN) ((Address>>15) & 0x1f)) << 16) + (((UINTN) ((Address>>12) & 0x07)) << 8) + ((UINTN) (Address & 0xfff )))) | |
| // | |
| // Modular variables needed by this driver | |
| // | |
| EFI_ACPI_SMM_DEV mAcpiSmm; | |
| UINT8 mPciCfgRegTable[] = { | |
| // | |
| // Logic to decode the table masks to arrive at the registers saved | |
| // Dword Registers are saved. For a given mask, the Base+offset register | |
| // will be saved as in the table below. | |
| // (example) To save register 0x24, 0x28 the mask at the Base 0x20 will be 0x06 | |
| // Base 0x00 0x20 0x40 0x60 0x80 0xA0 0xC0 0xE0 | |
| // Mask offset | |
| // 0x01 0x00 | |
| // 0x02 0x04 | |
| // 0x04 0x08 | |
| // 0x08 0x0C | |
| // 0x10 0x10 | |
| // 0x20 0x14 | |
| // 0x40 0x18 | |
| // 0x80 0x1C | |
| // | |
| // | |
| // Bus, Dev, Func, | |
| // 00-1F, 20-3F, 40-5F, 60-7F, 80-9F, A0-BF, C0-DF, E0-FF | |
| // Only Bus 0 device is supported now | |
| // | |
| // | |
| // Quark South Cluster devices | |
| // | |
| PCI_DEVICE (0, 20, 0), | |
| PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 20, 1), | |
| PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 20, 2), | |
| PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 20, 3), | |
| PCI_REG_MASK (0x18, 0x98, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00), | |
| PCI_DEVICE (0, 20, 4), | |
| PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 20, 5), | |
| PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 20, 6), | |
| PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 20, 7), | |
| PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 21, 0), | |
| PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 21, 1), | |
| PCI_REG_MASK (0x18, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 21, 2), | |
| PCI_REG_MASK (0x38, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| // | |
| // Quark North Cluster devices | |
| // | |
| PCI_DEVICE (0, 0, 0), | |
| PCI_REG_MASK (0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 23, 0), | |
| PCI_REG_MASK (0xC0, 0x8F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 23, 1), | |
| PCI_REG_MASK (0xC0, 0x8F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00), | |
| PCI_DEVICE (0, 31, 0), | |
| PCI_REG_MASK (0x00, 0x08, 0x4E, 0x03, 0x02, 0x00, 0x60, 0x10), | |
| PCI_DEVICE_END | |
| }; | |
| EFI_PLATFORM_TYPE mPlatformType; | |
| // These registers have to set in byte order | |
| const UINT8 QNCS3SaveExtReg[] = { | |
| QUARK_NC_HOST_BRIDGE_SB_PORT_ID, QNC_MSG_FSBIC_REG_HSMMC, // SMRAM settings | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXL, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXH, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXRM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR0+QUARK_NC_MEMORY_MANAGER_IMRXWM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXL, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXH, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXRM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR1+QUARK_NC_MEMORY_MANAGER_IMRXWM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXL, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXH, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXRM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR2+QUARK_NC_MEMORY_MANAGER_IMRXWM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXL, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXH, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXRM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR3+QUARK_NC_MEMORY_MANAGER_IMRXWM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXL, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXH, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXRM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR4+QUARK_NC_MEMORY_MANAGER_IMRXWM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXL, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXH, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXRM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR5+QUARK_NC_MEMORY_MANAGER_IMRXWM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXL, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXH, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXRM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR6+QUARK_NC_MEMORY_MANAGER_IMRXWM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXL, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXH, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXRM, | |
| QUARK_NC_MEMORY_MANAGER_SB_PORT_ID, QUARK_NC_MEMORY_MANAGER_IMR7+QUARK_NC_MEMORY_MANAGER_IMRXWM, | |
| QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_END_MEM_REG, // ECC Scrub settings | |
| QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_START_MEM_REG, | |
| QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_NEXT_READ_REG, | |
| QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG, | |
| 0xFF | |
| }; | |
| /** | |
| Allocate EfiACPIMemoryNVS below 4G memory address. | |
| This function allocates EfiACPIMemoryNVS below 4G memory address. | |
| @param Size Size of memory to allocate. | |
| @return Allocated address for output. | |
| **/ | |
| VOID* | |
| AllocateAcpiNvsMemoryBelow4G ( | |
| IN UINTN Size | |
| ) | |
| { | |
| UINTN Pages; | |
| EFI_PHYSICAL_ADDRESS Address; | |
| EFI_STATUS Status; | |
| VOID* Buffer; | |
| Pages = EFI_SIZE_TO_PAGES (Size); | |
| Address = 0xffffffff; | |
| Status = gBS->AllocatePages ( | |
| AllocateMaxAddress, | |
| EfiACPIMemoryNVS, | |
| Pages, | |
| &Address | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return NULL; | |
| } | |
| Buffer = (VOID *) (UINTN) Address; | |
| ZeroMem (Buffer, Size); | |
| return Buffer; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| ReservedS3Memory ( | |
| UINTN SystemMemoryLength | |
| ) | |
| /*++ | |
| Routine Description: | |
| Reserved S3 memory for InstallS3Memory | |
| Arguments: | |
| Returns: | |
| EFI_OUT_OF_RESOURCES - Insufficient resources to complete function. | |
| EFI_SUCCESS - Function has completed successfully. | |
| --*/ | |
| { | |
| VOID *GuidHob; | |
| EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *DescriptorBlock; | |
| VOID *AcpiReservedBase; | |
| UINTN TsegIndex; | |
| UINTN TsegSize; | |
| UINTN TsegBase; | |
| RESERVED_ACPI_S3_RANGE *AcpiS3Range; | |
| // | |
| // Get Hob list for SMRAM desc | |
| // | |
| GuidHob = GetFirstGuidHob (&gEfiSmmPeiSmramMemoryReserveGuid); | |
| ASSERT (GuidHob); | |
| DescriptorBlock = GET_GUID_HOB_DATA (GuidHob); | |
| ASSERT (DescriptorBlock); | |
| // | |
| // Use the hob to get SMRAM capabilities | |
| // | |
| TsegIndex = DescriptorBlock->NumberOfSmmReservedRegions - 1; | |
| ASSERT (TsegIndex <= (MAX_SMRAM_RANGES - 1)); | |
| TsegBase = (UINTN)DescriptorBlock->Descriptor[TsegIndex].PhysicalStart; | |
| TsegSize = (UINTN)DescriptorBlock->Descriptor[TsegIndex].PhysicalSize; | |
| DEBUG ((EFI_D_INFO, "SMM Base: %08X\n", TsegBase)); | |
| DEBUG ((EFI_D_INFO, "SMM Size: %08X\n", TsegSize)); | |
| // | |
| // Now find the location of the data structure that is used to store the address | |
| // of the S3 reserved memory. | |
| // | |
| AcpiS3Range = (RESERVED_ACPI_S3_RANGE*) (UINTN) (TsegBase + RESERVED_ACPI_S3_RANGE_OFFSET); | |
| // | |
| // Allocate reserved ACPI memory for S3 resume. Pointer to this region is | |
| // stored in SMRAM in the first page of TSEG. | |
| // | |
| AcpiReservedBase = AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdS3AcpiReservedMemorySize)); | |
| if (AcpiReservedBase != NULL) { | |
| AcpiS3Range->AcpiReservedMemoryBase = (UINT32)(UINTN) AcpiReservedBase; | |
| AcpiS3Range->AcpiReservedMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize); | |
| } | |
| AcpiS3Range->SystemMemoryLength = (UINT32)SystemMemoryLength; | |
| DEBUG ((EFI_D_INFO, "S3 Memory Base: %08X\n", AcpiS3Range->AcpiReservedMemoryBase)); | |
| DEBUG ((EFI_D_INFO, "S3 Memory Size: %08X\n", AcpiS3Range->AcpiReservedMemorySize)); | |
| DEBUG ((EFI_D_INFO, "S3 SysMemoryLength: %08X\n", AcpiS3Range->SystemMemoryLength)); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| EFIAPI | |
| InitAcpiSmmPlatform ( | |
| IN EFI_HANDLE ImageHandle, | |
| IN EFI_SYSTEM_TABLE *SystemTable | |
| ) | |
| /*++ | |
| Routine Description: | |
| Initializes the SMM S3 Handler Driver. | |
| Arguments: | |
| ImageHandle - The image handle of Sleep State Wake driver. | |
| SystemTable - The starndard EFI system table. | |
| Returns: | |
| EFI_OUT_OF_RESOURCES - Insufficient resources to complete function. | |
| EFI_SUCCESS - Function has completed successfully. | |
| Other - Error occured during execution. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| EFI_GLOBAL_NVS_AREA_PROTOCOL *AcpiNvsProtocol = NULL; | |
| UINTN MemoryLength; | |
| EFI_PEI_HOB_POINTERS Hob; | |
| Status = gBS->LocateProtocol ( | |
| &gEfiGlobalNvsAreaProtocolGuid, | |
| NULL, | |
| (VOID **) &AcpiNvsProtocol | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| mAcpiSmm.BootScriptSaved = 0; | |
| mPlatformType = (EFI_PLATFORM_TYPE)PcdGet16 (PcdPlatformType); | |
| // | |
| // Calculate the system memory length by memory hobs | |
| // | |
| MemoryLength = 0x100000; | |
| Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); | |
| ASSERT (Hob.Raw != NULL); | |
| while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) { | |
| if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { | |
| // | |
| // Skip the memory region below 1MB | |
| // | |
| if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) { | |
| MemoryLength += (UINTN)Hob.ResourceDescriptor->ResourceLength; | |
| } | |
| } | |
| Hob.Raw = GET_NEXT_HOB (Hob); | |
| Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw); | |
| } | |
| ReservedS3Memory(MemoryLength); | |
| // | |
| // Locate and Register to Parent driver | |
| // | |
| Status = RegisterToDispatchDriver (); | |
| ASSERT_EFI_ERROR (Status); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| RegisterToDispatchDriver ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Register to dispatch driver. | |
| Arguments: | |
| None. | |
| Returns: | |
| EFI_SUCCESS - Successfully init the device. | |
| Other - Error occured whening calling Dxe lib functions. | |
| --*/ | |
| { | |
| UINTN Length; | |
| EFI_STATUS Status; | |
| EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch; | |
| EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; | |
| EFI_SMM_SX_REGISTER_CONTEXT *EntryDispatchContext; | |
| EFI_SMM_SX_REGISTER_CONTEXT *EntryS1DispatchContext; | |
| EFI_SMM_SX_REGISTER_CONTEXT *EntryS3DispatchContext; | |
| EFI_SMM_SX_REGISTER_CONTEXT *EntryS4DispatchContext; | |
| EFI_SMM_SX_REGISTER_CONTEXT *EntryS5DispatchContext; | |
| EFI_SMM_SW_REGISTER_CONTEXT *SwContext; | |
| EFI_SMM_SW_REGISTER_CONTEXT *AcpiDisableSwContext; | |
| EFI_SMM_SW_REGISTER_CONTEXT *AcpiEnableSwContext; | |
| Status = gSmst->SmmLocateProtocol ( | |
| &gEfiSmmSxDispatch2ProtocolGuid, | |
| NULL, | |
| (VOID **) &SxDispatch | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = gSmst->SmmLocateProtocol ( | |
| &gEfiSmmSwDispatch2ProtocolGuid, | |
| NULL, | |
| (VOID **) &SwDispatch | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Length = sizeof (EFI_SMM_SX_REGISTER_CONTEXT) * 4 + sizeof (EFI_SMM_SW_REGISTER_CONTEXT) * 2; | |
| Status = gSmst->SmmAllocatePool ( | |
| EfiRuntimeServicesData, | |
| Length, | |
| (VOID **) &EntryDispatchContext | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| SetMem (EntryDispatchContext, Length, 0); | |
| EntryS1DispatchContext = EntryDispatchContext++; | |
| EntryS3DispatchContext = EntryDispatchContext++; | |
| EntryS4DispatchContext = EntryDispatchContext++; | |
| EntryS5DispatchContext = EntryDispatchContext++; | |
| SwContext = (EFI_SMM_SW_REGISTER_CONTEXT *)EntryDispatchContext; | |
| AcpiDisableSwContext = SwContext++; | |
| AcpiEnableSwContext = SwContext++; | |
| // | |
| // Register the enable handler | |
| // | |
| AcpiEnableSwContext->SwSmiInputValue = EFI_ACPI_ACPI_ENABLE; | |
| Status = SwDispatch->Register ( | |
| SwDispatch, | |
| EnableAcpiCallback, | |
| AcpiEnableSwContext, | |
| &(mAcpiSmm.DisableAcpiHandle) | |
| ); | |
| // | |
| // Register the disable handler | |
| // | |
| AcpiDisableSwContext->SwSmiInputValue = EFI_ACPI_ACPI_DISABLE; | |
| Status = SwDispatch->Register ( | |
| SwDispatch, | |
| DisableAcpiCallback, | |
| AcpiDisableSwContext, | |
| &(mAcpiSmm.EnableAcpiHandle) | |
| ); | |
| // | |
| // Register entry phase call back function for S1 | |
| // | |
| EntryS1DispatchContext->Type = SxS1; | |
| EntryS1DispatchContext->Phase = SxEntry; | |
| Status = SxDispatch->Register ( | |
| SxDispatch, | |
| SxSleepEntryCallBack, | |
| EntryS1DispatchContext, | |
| &(mAcpiSmm.S1SleepEntryHandle) | |
| ); | |
| // | |
| // Register entry phase call back function | |
| // | |
| EntryS3DispatchContext->Type = SxS3; | |
| EntryS3DispatchContext->Phase = SxEntry; | |
| Status = SxDispatch->Register ( | |
| SxDispatch, | |
| SxSleepEntryCallBack, | |
| EntryS3DispatchContext, | |
| &(mAcpiSmm.S3SleepEntryHandle) | |
| ); | |
| // | |
| // Register entry phase call back function for S4 | |
| // | |
| EntryS4DispatchContext->Type = SxS4; | |
| EntryS4DispatchContext->Phase = SxEntry; | |
| Status = SxDispatch->Register ( | |
| SxDispatch, | |
| SxSleepEntryCallBack, | |
| EntryS4DispatchContext, | |
| &(mAcpiSmm.S4SleepEntryHandle) | |
| ); | |
| // | |
| // Register callback for S5 in order to workaround the LAN shutdown issue | |
| // | |
| EntryS5DispatchContext->Type = SxS5; | |
| EntryS5DispatchContext->Phase = SxEntry; | |
| Status = SxDispatch->Register ( | |
| SxDispatch, | |
| SxSleepEntryCallBack, | |
| EntryS5DispatchContext, | |
| &(mAcpiSmm.S5SoftOffEntryHandle) | |
| ); | |
| return Status; | |
| } | |
| EFI_STATUS | |
| RestoreQncS3SwCallback ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *DispatchContext, | |
| IN OUT VOID *CommBuffer, | |
| IN OUT UINTN *CommBufferSize | |
| ) | |
| /*++ | |
| Routine Description: | |
| SMI handler to restore QncS3 code & context for S3 path | |
| This will be only triggered when BootScript got executed during resume | |
| Arguments: | |
| DispatchHandle - EFI Handle | |
| DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT | |
| Returns: | |
| Nothing | |
| --*/ | |
| { | |
| // | |
| // Restore to original address by default | |
| // | |
| RestoreLockBox(&gQncS3CodeInLockBoxGuid, NULL, NULL); | |
| RestoreLockBox(&gQncS3ContextInLockBoxGuid, NULL, NULL); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| DisableAcpiCallback ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *DispatchContext, | |
| IN OUT VOID *CommBuffer, | |
| IN OUT UINTN *CommBufferSize | |
| ) | |
| /*++ | |
| Routine Description: | |
| SMI handler to disable ACPI mode | |
| Dispatched on reads from APM port with value 0xA1 | |
| ACPI events are disabled and ACPI event status is cleared. | |
| SCI mode is then disabled. | |
| Clear all ACPI event status and disable all ACPI events | |
| Disable PM sources except power button | |
| Clear status bits | |
| Disable GPE0 sources | |
| Clear status bits | |
| Disable GPE1 sources | |
| Clear status bits | |
| Disable SCI | |
| Arguments: | |
| DispatchHandle - EFI Handle | |
| DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT | |
| Returns: | |
| Nothing | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINT16 Pm1Cnt; | |
| Status = GetAllQncPmBase (gSmst); | |
| ASSERT_EFI_ERROR (Status); | |
| Pm1Cnt = IoRead16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C); | |
| // | |
| // Disable SCI | |
| // | |
| Pm1Cnt &= ~B_QNC_PM1BLK_PM1C_SCIEN; | |
| IoWrite16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C, Pm1Cnt); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| EnableAcpiCallback ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *DispatchContext, | |
| IN OUT VOID *CommBuffer, | |
| IN OUT UINTN *CommBufferSize | |
| ) | |
| /*++ | |
| Routine Description: | |
| SMI handler to enable ACPI mode | |
| Dispatched on reads from APM port with value 0xA0 | |
| Disables the SW SMI Timer. | |
| ACPI events are disabled and ACPI event status is cleared. | |
| SCI mode is then enabled. | |
| Disable SW SMI Timer | |
| Clear all ACPI event status and disable all ACPI events | |
| Disable PM sources except power button | |
| Clear status bits | |
| Disable GPE0 sources | |
| Clear status bits | |
| Disable GPE1 sources | |
| Clear status bits | |
| Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4) | |
| Enable SCI | |
| Arguments: | |
| DispatchHandle - EFI Handle | |
| DispatchContext - Pointer to the EFI_SMM_SW_DISPATCH_CONTEXT | |
| Returns: | |
| Nothing | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINT32 SmiEn; | |
| UINT16 Pm1Cnt; | |
| UINT8 Data8; | |
| Status = GetAllQncPmBase (gSmst); | |
| ASSERT_EFI_ERROR (Status); | |
| SmiEn = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE); | |
| // | |
| // Disable SW SMI Timer | |
| // | |
| SmiEn &= ~(B_QNC_GPE0BLK_SMIE_SWT); | |
| IoWrite32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE, SmiEn); | |
| // | |
| // Guarantee day-of-month alarm is invalid (ACPI 1.0 section 4.7.2.4) | |
| // | |
| Data8 = RTC_ADDRESS_REGISTER_D; | |
| IoWrite8 (R_IOPORT_CMOS_STANDARD_INDEX, Data8); | |
| Data8 = 0x0; | |
| IoWrite8 (R_IOPORT_CMOS_STANDARD_DATA, Data8); | |
| // | |
| // Enable SCI | |
| // | |
| Pm1Cnt = IoRead16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C); | |
| Pm1Cnt |= B_QNC_PM1BLK_PM1C_SCIEN; | |
| IoWrite16 (mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1C, Pm1Cnt); | |
| // | |
| // Do platform specific stuff for ACPI enable SMI | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| SxSleepEntryCallBack ( | |
| IN EFI_HANDLE DispatchHandle, | |
| IN CONST VOID *DispatchContext, | |
| IN OUT VOID *CommBuffer, | |
| IN OUT UINTN *CommBufferSize | |
| ) | |
| /*++ | |
| Routine Description: | |
| Callback function entry for Sx sleep state. | |
| Arguments: | |
| DispatchHandle - The handle of this callback, obtained when registering. | |
| DispatchContext - The predefined context which contained sleep type and phase. | |
| Returns: | |
| EFI_SUCCESS - Operation successfully performed. | |
| EFI_INVALID_PARAMETER - Invalid parameter passed in. | |
| --*/ | |
| { | |
| EFI_STATUS Status; | |
| UINT8 Data8; | |
| UINT16 Data16; | |
| UINT32 Data32; | |
| REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeS3SuspendStart)); | |
| // | |
| // Reget QNC power mgmr regs base in case of OS changing it at runtime | |
| // | |
| Status = GetAllQncPmBase (gSmst); | |
| // | |
| // Clear RTC Alarm (if set) | |
| // | |
| Data8 = RTC_ADDRESS_REGISTER_C; | |
| IoWrite8 (R_IOPORT_CMOS_STANDARD_INDEX, Data8); | |
| Data8 = IoRead8 (R_IOPORT_CMOS_STANDARD_DATA); | |
| // | |
| // Clear all ACPI status bits | |
| // | |
| Data32 = B_QNC_GPE0BLK_GPE0S_ALL; | |
| Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0S, 1, &Data32 ); | |
| Data16 = B_QNC_PM1BLK_PM1S_ALL; | |
| Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1S, 1, &Data16 ); | |
| // | |
| // Handling S1 - setting appropriate wake bits in GPE0_EN | |
| // | |
| if ((DispatchHandle == mAcpiSmm.S1SleepEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS1)) { | |
| // | |
| // Enable bit13 (EGPE), 14 (GPIO) ,17 (PCIE) in GPE0_EN | |
| // | |
| Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); | |
| Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE); | |
| Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); | |
| // | |
| // Enable bit10 (RTC) in PM1E | |
| // | |
| Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); | |
| Data16 |= B_QNC_PM1BLK_PM1E_RTC; | |
| Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Handling S4, S5 and WOL - setting appropriate wake bits in GPE0_EN | |
| // | |
| if (((DispatchHandle == mAcpiSmm.S4SleepEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS4)) || | |
| ((DispatchHandle == mAcpiSmm.S5SoftOffEntryHandle) && (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type == SxS5)) | |
| ) { | |
| // | |
| // Enable bit13 (EGPE), 14 (GPIO) ,17 (PCIE) in GPE0_EN | |
| // Enable the WOL bits in GPE0_EN reg here for PME | |
| // | |
| Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); | |
| Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE); | |
| Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); | |
| // | |
| // Enable bit10 (RTC) in PM1E | |
| // | |
| Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); | |
| Data16 |= B_QNC_PM1BLK_PM1E_RTC; | |
| Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); | |
| } else { | |
| if ((DispatchHandle != mAcpiSmm.S3SleepEntryHandle) || (((EFI_SMM_SX_REGISTER_CONTEXT *)DispatchContext)->Type != SxS3)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = SaveRuntimeScriptTable (gSmst); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| // | |
| // Enable bit13 (EGPE), 14 (GPIO), 17 (PCIE) in GPE0_EN | |
| // Enable the WOL bits in GPE0_EN reg here for PME | |
| // | |
| Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); | |
| Data32 |= (B_QNC_GPE0BLK_GPE0E_EGPE | B_QNC_GPE0BLK_GPE0E_GPIO | B_QNC_GPE0BLK_GPE0E_PCIE); | |
| Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT32, mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_GPE0E, 1, &Data32 ); | |
| // | |
| // Enable bit10 (RTC) in PM1E | |
| // | |
| Status = gSmst->SmmIo.Io.Read( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); | |
| Data16 |= B_QNC_PM1BLK_PM1E_RTC; | |
| Status = gSmst->SmmIo.Io.Write( &gSmst->SmmIo, SMM_IO_UINT16, mAcpiSmm.QncPmBase + R_QNC_PM1BLK_PM1E, 1, &Data16 ); | |
| } | |
| // | |
| // When entering a power-managed state like S3, | |
| // PERST# must be asserted in advance of power-off. | |
| // | |
| PlatformPERSTAssert (mPlatformType); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| GetAllQncPmBase ( | |
| IN EFI_SMM_SYSTEM_TABLE2 *Smst | |
| ) | |
| /*++ | |
| Routine Description: | |
| Get QNC chipset LPC Power Management I/O Base at runtime. | |
| Arguments: | |
| Smst - The standard SMM system table. | |
| Returns: | |
| EFI_SUCCESS - Successfully init the device. | |
| Other - Error occured whening calling Dxe lib functions. | |
| --*/ | |
| { | |
| 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; | |
| 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; | |
| // | |
| // Quark does not support Changing Primary SoC IOBARs from what was | |
| // setup in SEC/PEI UEFI stages. | |
| // | |
| ASSERT (mAcpiSmm.QncPmBase == (UINT32) PcdGet16 (PcdPm1blkIoBaseAddress)); | |
| ASSERT (mAcpiSmm.QncGpe0Base == (UINT32) PcdGet16 (PcdGpe0blkIoBaseAddress)); | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| SaveRuntimeScriptTable ( | |
| IN EFI_SMM_SYSTEM_TABLE2 *Smst | |
| ) | |
| { | |
| EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; | |
| UINT32 Data32; | |
| UINT16 Data16; | |
| UINT8 Mask; | |
| UINTN Index; | |
| UINTN Offset; | |
| UINT16 DeviceId; | |
| // | |
| // Check what Soc we are running on (read Host bridge DeviceId) | |
| // | |
| DeviceId = QncGetSocDeviceId(); | |
| // | |
| // Save PCI-Host bridge settings (0, 0, 0). 0x90, 94 and 9c are changed by CSM | |
| // and vital to S3 resume. That's why we put save code here | |
| // | |
| Index = 0; | |
| while (mPciCfgRegTable[Index] != PCI_DEVICE_END) { | |
| PciAddress.Bus = mPciCfgRegTable[Index++]; | |
| PciAddress.Device = mPciCfgRegTable[Index++]; | |
| PciAddress.Function = mPciCfgRegTable[Index++]; | |
| PciAddress.Register = 0; | |
| PciAddress.ExtendedRegister = 0; | |
| Data16 = PciRead16 (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)); | |
| if (Data16 == 0xFFFF) { | |
| Index += 8; | |
| continue; | |
| } | |
| for (Offset = 0, Mask = 0x01; Offset < 256; Offset += 4, Mask <<= 1) { | |
| if (Mask == 0x00) { | |
| Mask = 0x01; | |
| } | |
| if (mPciCfgRegTable[Index + Offset / 32] & Mask) { | |
| PciAddress.Register = (UINT8) Offset; | |
| Data32 = PciRead32 (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)); | |
| // | |
| // Save latest settings to runtime script table | |
| // | |
| S3BootScriptSavePciCfgWrite ( | |
| S3BootScriptWidthUint32, | |
| PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(PciAddress.Bus, PciAddress.Device, PciAddress.Function, PciAddress.Register)), | |
| 1, | |
| &Data32 | |
| ); | |
| } | |
| } | |
| Index += 8; | |
| } | |
| // | |
| // Save message bus registers | |
| // | |
| Index = 0; | |
| while (QNCS3SaveExtReg[Index] != 0xFF) { | |
| Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); | |
| // | |
| // Save IMR settings with IMR protection disabled initially | |
| // HMBOUND and IMRs will be locked just before jumping to the OS waking vector | |
| // | |
| if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) { | |
| 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)) { | |
| Data32 &= ~IMR_LOCK; | |
| if (DeviceId == QUARK2_MC_DEVICE_ID) { | |
| Data32 &= ~IMR_EN; | |
| } | |
| } | |
| 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)) { | |
| Data32 = (UINT32)IMRX_ALL_ACCESS; | |
| } | |
| } | |
| // | |
| // Save latest settings to runtime script table | |
| // | |
| S3BootScriptSavePciCfgWrite ( | |
| S3BootScriptWidthUint32, | |
| PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)), | |
| 1, | |
| &Data32 | |
| ); | |
| Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); | |
| S3BootScriptSavePciCfgWrite ( | |
| S3BootScriptWidthUint32, | |
| PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), | |
| 1, | |
| &Data32 | |
| ); | |
| Index += 2; | |
| } | |
| Index = 0; | |
| while (QNCS3SaveExtReg[Index] != 0xFF) { | |
| // | |
| // Save IMR settings with IMR protection enabled (above script was to handle restoring all settings first - now we want to enable) | |
| // | |
| if (QNCS3SaveExtReg[Index] == QUARK_NC_MEMORY_MANAGER_SB_PORT_ID) { | |
| if (DeviceId == QUARK2_MC_DEVICE_ID) { | |
| 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)) { | |
| Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); | |
| Data32 &= ~IMR_LOCK; | |
| // | |
| // Save latest settings to runtime script table | |
| // | |
| S3BootScriptSavePciCfgWrite ( | |
| S3BootScriptWidthUint32, | |
| PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)), | |
| 1, | |
| &Data32 | |
| ); | |
| Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); | |
| S3BootScriptSavePciCfgWrite ( | |
| S3BootScriptWidthUint32, | |
| PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), | |
| 1, | |
| &Data32 | |
| ); | |
| } | |
| } else { | |
| 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)) { | |
| Data32 = QNCPortRead (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); | |
| // | |
| // Save latest settings to runtime script table | |
| // | |
| S3BootScriptSavePciCfgWrite ( | |
| S3BootScriptWidthUint32, | |
| PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MDR)), | |
| 1, | |
| &Data32 | |
| ); | |
| Data32 = MESSAGE_WRITE_DW (QNCS3SaveExtReg[Index], QNCS3SaveExtReg[Index + 1]); | |
| S3BootScriptSavePciCfgWrite ( | |
| S3BootScriptWidthUint32, | |
| PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), | |
| 1, | |
| &Data32 | |
| ); | |
| } | |
| } | |
| } | |
| Index += 2; | |
| } | |
| // Check if ECC scrub enabled and need re-enabling on resume | |
| // All scrub related configuration registers are saved on suspend | |
| // as part of QNCS3SaveExtReg configuration table script. | |
| // The code below extends the S3 resume script with scrub reactivation | |
| // message (if needed only) | |
| Data32 = QNCPortRead (QUARK_NC_RMU_SB_PORT_ID, QUARK_NC_ECC_SCRUB_CONFIG_REG); | |
| if( 0 != (Data32 & SCRUB_CFG_ACTIVE)) { | |
| Data32 = SCRUB_RESUME_MSG(); | |
| S3BootScriptSavePciCfgWrite ( | |
| S3BootScriptWidthUint32, | |
| PCILIB_TO_COMMON_ADDRESS (PCI_LIB_ADDRESS(0, 0, 0, QNC_ACCESS_PORT_MCR)), | |
| 1, | |
| &Data32 | |
| ); | |
| } | |
| // | |
| // Save I/O ports to S3 script table | |
| // | |
| // | |
| // Important to trap Sx for SMM | |
| // | |
| Data32 = IoRead32 (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE); | |
| S3BootScriptSaveIoWrite(S3BootScriptWidthUint32, (mAcpiSmm.QncGpe0Base + R_QNC_GPE0BLK_SMIE), 1, &Data32); | |
| return EFI_SUCCESS; | |
| } | |