/** @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 #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; }