diff options
Diffstat (limited to 'ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm')
18 files changed, 7937 insertions, 0 deletions
diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.cif b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.cif new file mode 100644 index 0000000..51c2e34 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.cif @@ -0,0 +1,24 @@ +<component> + name = "PchSmiDispatcher" + category = ModulePart + LocalRoot = "ReferenceCode\Chipset\LynxPoint\PchSmiDispatcher\Smm" + RefName = "PchSmiDispatcher" +[files] +"PchSmiDispatcher.sdl" +"PchSmiDispatcher.mak" +"PchSmm.h" +"PchSmmCore.c" +"PchSmmHelpers.h" +"PchSmmHelpers.c" +"PchxSmmHelpers.h" +"PchxSmmHelpers.c" +"PchSmmUsb.c" +"PchSmmGpi.c" +"PchSmmPowerButton.c" +"PchSmmSw.c" +"PchSmmSx.c" +"PchSmmIchn.c" +"PchSmmPeriodicTimer.c" +"PchSmiDispatcher.dxs" +"PchSmiDispatcher.inf" +<endComponent> diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.dxs b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.dxs new file mode 100644 index 0000000..e0f4908 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.dxs @@ -0,0 +1,43 @@ +/** @file + Dispatch dependency expression file for the PchSmmDispatcher driver. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement + +**/ + + +// +// Common for R8 and R9 codebase +// +#include "AutoGen.h" +#include "DxeDepex.h" + +// +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase; +// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase. +// +#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB) +#include "EfiDepex.h" + +#include EFI_PROTOCOL_DEFINITION (SmmBase) +#include EFI_PROTOCOL_CONSUMER(PciRootBridgeIo) +#endif + +DEPENDENCY_START + EFI_SMM_BASE_PROTOCOL_GUID AND + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID +DEPENDENCY_END diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.inf b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.inf new file mode 100644 index 0000000..a251b73 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.inf @@ -0,0 +1,104 @@ +## @file +# Component description file for the Pch SMI Dispatch Handlers module +# +#@copyright +# Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +# This file contains a 'Sample Driver' and is licensed as such +# under the terms of your license agreement with Intel or your +# vendor. This file may be modified by the user, subject to +# the additional terms of the license agreement +# + +[defines] +BASE_NAME = PchSmiDispatcher +FILE_GUID = B0D6ED53-B844-43f5-BD2F-61095264E77E +COMPONENT_TYPE = BS_DRIVER + +[sources.common] + PchSmm.h + PchSmmCore.c + PchSmmHelpers.h + PchSmmHelpers.c + PchxSmmHelpers.h + PchxSmmHelpers.c + PchSmmUsb.c + PchSmmGpi.c + PchSmmPowerButton.c + PchSmmSw.c + PchSmmSx.c + PchSmmIchn.c + PchSmmPeriodicTimer.c +# +# Edk II Glue Driver Entry Point +# + EdkIIGlueSmmDriverEntryPoint.c + +[libraries.common] + EdkIIGlueBaseLib + EdkIIGlueBaseIoLibIntrinsic + EdkIIGlueBaseMemoryLib + EdkIIGlueDxeMemoryAllocationLib + EdkIIGlueSmmRuntimeDxeReportStatusCodeLib + EdkIIGlueUefiBootServicesTableLib + EdkIIGlueUefiRuntimeServicesTableLib + EdkIIGlueDxeServicesTableLib + EdkIIGlueUefiDevicePathLib + EdkIIGlueDxeDebugLibReportStatusCode + EdkIIGlueBasePciLibPciExpress + EdkFrameworkProtocolLib + EdkProtocolLib + $(PROJECT_PCH_FAMILY)ProtocolLib + PchPlatformLib + EdkIIGlueSmmFirmwarePerformanceLib + +[libraries.ia32,libraries.x64] + +[includes.common] + . + $(EDK_SOURCE)/Foundation/Efi + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT) + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include/Library + $(EDK_SOURCE)/Foundation/Include + $(EDK_SOURCE)/Foundation/Efi/Include + $(EDK_SOURCE)/Foundation/Framework/Include + $(EDK_SOURCE)/Foundation/Cpu/Pentium/Include +# +# EDK II Glue Library utilizes some standard headers from EDK +# + $(EFI_SOURCE) + $(EDK_SOURCE)/Foundation + $(EDK_SOURCE)/Foundation/Framework + $(EDK_SOURCE)/Foundation/Include/IndustryStandard + $(EDK_SOURCE)/Foundation/Core/Dxe + $(EDK_SOURCE)/Foundation/Include/Pei + $(EDK_SOURCE)/Foundation/Library/Dxe/Include + $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include + +[nmake.common] + IMAGE_ENTRY_POINT = _ModuleEntryPoint + DPX_SOURCE = PchSmiDispatcher.dxs +# +# Module Entry Point +# + C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_MODULE_ENTRY_POINT__=InitializePchSmmDispatcher + C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_BASE_LIB__ \ + -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + -D __EDKII_GLUE_BASE_MEMORY_LIB__ \ + -D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \ + -D __EDKII_GLUE_SMM_RUNTIME_DXE_REPORT_STATUS_CODE_LIB__ \ + -D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ + -D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \ + -D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \ + -D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \ + -D __EDKII_GLUE_UEFI_DEVICE_PATH_LIB__ \ + -D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ + diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.mak b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.mak new file mode 100644 index 0000000..d4308f8 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.mak @@ -0,0 +1,115 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#************************************************************************* +# $Header: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchSmiDispatcher/PchSmiDispatcher.mak 3 6/24/13 6:08a Scottyang $ +# +# $Revision: 3 $ +# +# $Date: 6/24/13 6:08a $ +#************************************************************************* +# Revision History +# ---------------- +# $Log: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchSmiDispatcher/PchSmiDispatcher.mak $ +# +# 3 6/24/13 6:08a Scottyang +# [TAG] EIP127297 +# [Category] Improvement +# [Description] Update PCH RC 1.6.0. +# [Files] SB.sd, SBDxe.c, ..\ReferenceCode\Chipset\LynxPoint\*.* +# +# 2 2/24/12 2:14a Victortu +# Updated to support 4.6.5.3_IntelEDK_1117_Patch7_00. +# +# 1 2/08/12 8:54a Yurenlai +# Intel Lynx Point/SB eChipset initially releases. +# +#************************************************************************* + +#--------------------------------------------------------------------------- +# Create PchSmiDispatcher Driver +#--------------------------------------------------------------------------- +EDK : PchSmiDispatcher +PchSmiDispatcher : $(BUILD_DIR)\PchSmiDispatcher.mak PchSmiDispatcherBin + + +$(BUILD_DIR)\PchSmiDispatcher.mak : $(PchSmiDispatcher_DIR)\$(@B).cif $(PchSmiDispatcher_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(PchSmiDispatcher_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +PchSmiDispatcher_INCLUDES=\ + $(INTEL_PCH_INCLUDES)\ + $(EdkIIGlueLib_INCLUDES)\ + +PchSmiDispatcher_DEFINES = $(MY_DEFINES)\ + /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=InitializePchSmmDispatcher"\ + /D __EDKII_GLUE_BASE_LIB__ \ + /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + /D __EDKII_GLUE_BASE_MEMORY_LIB__ \ + /D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \ + /D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \ + /D __EDKII_GLUE_SMM_RUNTIME_DXE_REPORT_STATUS_CODE_LIB__ \ + /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \ + /D __EDKII_GLUE_UEFI_DEVICE_PATH_LIB__ \ + /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \ + /D __EDKII_GLUE_UEFI_RUNTIME_SERVICES_TABLE_LIB__ \ + /D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ + +PchSmiDispatcher_LIB_LINKS =\ +!IF "$(x64_BUILD)"=="1" + $(EdkIIGlueBaseLibX64_LIB)\ +!ELSE + $(EdkIIGlueBaseLibIA32_LIB)\ +!ENDIF + $(EdkIIGlueBaseLib_LIB)\ + $(EdkIIGlueBaseIoLibIntrinsic_LIB)\ + $(EdkIIGlueBaseMemoryLib_LIB)\ + $(EdkIIGlueDxeMemoryAllocationLib_LIB)\ + $(EdkIIGlueDxeDebugLibReportStatusCode_LIB)\ + $(EdkIIGlueSmmRuntimeDxeReportStatusCodeLib_LIB)\ + $(EdkIIGlueUefiBootServicesTableLib_LIB)\ + $(EdkIIGlueUefiDevicePathLib_LIB)\ + $(EdkIIGlueBasePciLibPciExpress_LIB)\ + $(EDKFRAMEWORKPROTOCOLLIB)\ + $(EDKPROTOCOLLIB)\ + $(INTEL_PCH_PROTOCOL_LIB)\ + $(PchPlatformSmmLib_LIB)\ + $(EdkIIGlueSmmFirmwarePerformanceLib_LIB)\ + $(EdkIIGlueUefiRuntimeServicesTableLib_LIB)\ + $(EdkIIGlueDxeServicesTableLib_LIB)\ + +PchSmiDispatcherBin: $(COMPILERSTUB) $(PchSmiDispatcher_LIB_LINKS) + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\ + /f $(BUILD_DIR)\PchSmiDispatcher.mak all \ + "MY_INCLUDES=$(PchSmiDispatcher_INCLUDES)" \ + "MY_DEFINES=$(PchSmiDispatcher_DEFINES)" \ + GUID=B0D6ED53-B844-43f5-BD2F-61095264E77E\ + ENTRY_POINT=_ModuleEntryPoint \ + TYPE=BS_DRIVER\ + EDKIIModule=SMMDRIVER\ + DEPEX1=$(PchSmiDispatcher_DIR)\PchSmiDispatcher.dxs\ + DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX \ + COMPRESS=1 +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.sdl b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.sdl new file mode 100644 index 0000000..93c2ae0 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmiDispatcher.sdl @@ -0,0 +1,102 @@ +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* + +#************************************************************************* +# $Header: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchSmiDispatcher/PchSmiDispatcher.sdl 3 12/30/13 5:10a Barretlin $ +# +# $Revision: 3 $ +# +# $Date: 12/30/13 5:10a $ +#************************************************************************* +# Revision History +# ---------------- +# $Log: /Alaska/BIN/Chipset/Intel/SouthBridge/LynxPoint/Intel Pch SB Refcode/PchSmiDispatcher/PchSmiDispatcher.sdl $ +# +# 3 12/30/13 5:10a Barretlin +# [TAG] EIP145008 +# [Category] Improvement +# [Description] Force Power button event phase always as entry to avoid +# some power button issue +# [Files] PchSmiDispatcher.sdl PchSmmPowerButton.c +# +# 2 4/25/12 9:22a Victortu +# [TAG] None +# [Category] Improvement +# [Description] Reprogram SMM ChildDispatcher drivers. +# [Files] SmiHandlerGeneric.c; SmiHandlerPorting.c; +# SmiHandlerGeneric2.c; SmmChildDispatch2Main.c; SmmChildDispatcher2.mak; +# SmmChildDispatcher2.sdl; SmmChildDispatch.h; SmmChildDispatchMain.c; +# SmmChildDispatchProtocol.c; SmmChildDispatcher.dxs; +# PchSmiDispatcher.sdl +# +# 1 2/08/12 8:54a Yurenlai +# Intel Lynx Point/SB eChipset initially releases. +# +#************************************************************************* +TOKEN + Name = "PchSmiDispatcher_SUPPORT" + Value = "1" + Help = "Main switch to enable PchSmiDispatcher support in Project" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + TargetH = Yes + Master = Yes +End + +TOKEN + Name = "INTEL_RC_SMI_DISPATCHER_SUPPORT" + Value = "1" + TokenType = Boolean + TargetH = Yes + Lock = Yes +End + +TOKEN + Name = "FORCE_PWB_PHASE_AS_ENTRY" + Value = "1" + Help = "Force Power button event phase always as entry to avoid some power button issue. EIP145008" + TokenType = Boolean + TargetH = Yes +End + +PATH + Name = "PchSmiDispatcher_DIR" + Help = "PchSmiDispatcher file source directory" +End + +MODULE + Help = "Includes PchSmiDispatcher.mak to Project" + File = "PchSmiDispatcher.mak" +End + +ELINK + Name = "$(BUILD_DIR)\PchSmiDispatcher.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + +#************************************************************************* +#************************************************************************* +#** ** +#** (C)Copyright 1985-2011, American Megatrends, Inc. ** +#** ** +#** All Rights Reserved. ** +#** ** +#** 5555 Oakbrook Parkway, Suite 200, Norcross, GA 30093 ** +#** ** +#** Phone: (770)-246-8600 ** +#** ** +#************************************************************************* +#************************************************************************* diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmm.h b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmm.h new file mode 100644 index 0000000..864615b --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmm.h @@ -0,0 +1,727 @@ +/** @file + Prototypes and defines for the PCH SMM Dispatcher. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#ifndef PCH_SMM_H +#define PCH_SMM_H + +// +// External include files do NOT need to be explicitly specified in real EDKII +// environment +// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) + +#include "EdkIIGlueDxe.h" + +// +// Driver Consumed Protocol Prototypes +// +// +// Used during initialization +// +#include EFI_PROTOCOL_DEPENDENCY (PciRootBridgeIo) +#include EFI_PROTOCOL_CONSUMER (LoadedImage) +// +// Used during SMI dispatch +// +#include EFI_PROTOCOL_DEPENDENCY (SmmBase) +#include EFI_PROTOCOL_CONSUMER (SmmControl) +// +// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SUPPORTED PROTOCOLS +// +#include EFI_PROTOCOL_PRODUCER (SmmUsbDispatch) +#include EFI_PROTOCOL_PRODUCER (SmmSxDispatch) +#include EFI_PROTOCOL_PRODUCER (SmmSwDispatch) +#include EFI_PROTOCOL_PRODUCER (SmmGpiDispatch) +#include EFI_PROTOCOL_PRODUCER (SmmIchnDispatch) +#include EFI_PROTOCOL_PRODUCER (SmmIchnDispatchEx) +#include EFI_PROTOCOL_PRODUCER (SmmPowerButtonDispatch) +#include EFI_PROTOCOL_PRODUCER (SmmPeriodicTimerDispatch) +#include "PchAccess.h" +#include "PchPlatformLib.h" +#endif +/// +/// Define an enumeration for all the supported protocols +/// +typedef enum { + UsbType, + SxType, + SwType, + GpiType, + IchnType, + IchnExType, + PowerButtonType, + PeriodicTimerType, + PchSmmProtocolTypeMax +} PCH_SMM_PROTOCOL_TYPE; + +/// +/// SPECIFYING A REGISTER +/// We want a general way of referring to addresses. For this case, we'll only +/// need addresses in the ACPI table (and the TCO entries within the ACPI table). +/// However, it's interesting to consider what it would take to support other types +/// of addresses. To address Will's concern, I think it prudent to accommodate it +/// early on in the design. +/// +/// Addresses we need to consider: +/// +/// Type: Required: +/// I/O Yes +/// ACPI (special case of I/O) Only if we want to +/// TCO (special case of ACPI) Only if we want to +/// GPIO (special case of I/O) Only if we want to +/// Memory (or Memory Mapped I/O) Only if we want to +/// PCIE Yes, for BiosWp +/// +typedef enum { + /// + /// IO_ADDR_TYPE, /// unimplemented + /// + ACPI_ADDR_TYPE, + GPIO_ADDR_TYPE, + /// + /// MEMORY_ADDR_TYPE, /// unimplemented + /// + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCIE_ADDR_TYPE, + NUM_ADDR_TYPES, ///< count of items in this enum + PCH_SMM_ADDR_TYPE_NULL = -1 ///< sentinel to indicate NULL or to signal end of arrays +} ADDR_TYPE; + +// +// Assumption: 32-bits -- enum's evaluate to integer +// Assumption: This code will only run on IA-32. Justification: IA-64 doesn't have SMIs. +// We don't have to worry about 64-bit addresses. +// Typedef the size of addresses in case the numbers I'm using are wrong or in case +// this changes. This is a good idea because PCI_ADDR will change, for example, when +// we add support for PciExpress. +// +typedef UINT16 IO_ADDR; +typedef IO_ADDR GPIO_ADDR; +typedef IO_ADDR ACPI_ADDR; ///< can omit +typedef IO_ADDR TCO_ADDR; ///< can omit +typedef UINTN MEM_ADDR; +typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS; +typedef union { + UINT32 Raw; + struct { + UINT8 Reg; + UINT8 Fnc; + UINT8 Dev; + UINT8 Bus; + } Fields; +} PCIE_ADDR; + +typedef struct { + ADDR_TYPE Type; + union { + /// + /// used to initialize during declaration/definition + /// + UINT32 raw; + + /// + /// used to access useful data + /// + IO_ADDR io; + ACPI_ADDR acpi; + TCO_ADDR tco; + GPIO_ADDR gpio; + MEM_ADDR mem; + MEMORY_MAPPED_IO_ADDRESS Mmio; + PCIE_ADDR pcie; + + } Data; + +} PCH_SMM_ADDRESS; + +/// +/// SPECIFYING BITS WITHIN A REGISTER +/// Here's a struct that helps us specify a source or enable bit. +/// +typedef struct { + PCH_SMM_ADDRESS Reg; + UINT8 SizeInBytes; ///< of the register + UINT8 Bit; +} PCH_SMM_BIT_DESC; + +// +// Sometimes, we'll have bit descriptions that are unused. It'd be great to have a +// way to easily identify them: +// +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type == PCH_SMM_ADDR_TYPE_NULL) ///< "returns" true when BitDesc is NULL +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = PCH_SMM_ADDR_TYPE_NULL) ///< will "return" an integer w/ value of 0 +#define NULL_BIT_DESC_INITIALIZER \ + { \ + { \ + PCH_SMM_ADDR_TYPE_NULL, \ + { \ + 0 \ + } \ + }, \ + 0, 0 \ + } +// +// I'd like a type to specify the callback's Sts & En bits because they'll +// be commonly used together: +// +#define NUM_EN_BITS 2 +#define NUM_STS_BITS 1 + +// +// Flags +// +typedef UINT8 PCH_SMM_SOURCE_FLAGS; + +// +// Flags required today +// +#define PCH_SMM_NO_FLAGS 0 +#define PCH_SMM_SCI_EN_DEPENDENT 1 + +// +// Flags that might be required tomorrow +// +/// +/// #define PCH_SMM_CLEAR_WITH_ONE 2 /// may need to support bits that clear by writing 0 +/// #define PCH_SMM_MULTIBIT_FIELD 3 /// may need to support status/enable fields 2 bits wide +/// +typedef struct { + PCH_SMM_SOURCE_FLAGS Flags; + PCH_SMM_BIT_DESC En[NUM_EN_BITS]; + PCH_SMM_BIT_DESC Sts[NUM_STS_BITS]; +} PCH_SMM_SOURCE_DESC; +// +// 31 bytes, I think +// +#define NULL_SOURCE_DESC_INITIALIZER \ + { \ + PCH_SMM_NO_FLAGS, \ + { \ + NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \ + }, \ + { \ + NULL_BIT_DESC_INITIALIZER \ + } \ + } + +/// +/// CHILD CONTEXTS +/// To keep consistent w/ the architecture, we'll need to provide the context +/// to the child when we call its callback function. After talking with Will, +/// we agreed that we'll need functions to "dig" the context out of the hardware +/// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare those +/// contexts to prevent unnecessary dispatches. I'd like a general type for these +/// "GetContext" functions, so I'll need a union of all the protocol contexts for +/// our internal use: +/// +typedef union { + // + // (in no particular order) + // + EFI_SMM_ICHN_DISPATCH_CONTEXT Ichn; + EFI_SMM_ICHN_DISPATCH_EX_CONTEXT IchnEx; + EFI_SMM_SX_DISPATCH_CONTEXT Sx; + EFI_SMM_PERIODIC_TIMER_DISPATCH_CONTEXT PeriodicTimer; + EFI_SMM_SW_DISPATCH_CONTEXT Sw; + EFI_SMM_POWER_BUTTON_DISPATCH_CONTEXT PowerButton; + EFI_SMM_USB_DISPATCH_CONTEXT Usb; + EFI_SMM_GPI_DISPATCH_CONTEXT Gpi; +} PCH_SMM_CONTEXT; +// +// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes +// +typedef struct _DATABASE_RECORD DATABASE_RECORD; + +/// +/// Assumption: the GET_CONTEXT function will be as small and simple as possible. +/// Assumption: We don't need to pass in an enumeration for the protocol because each +/// GET_CONTEXT function is written for only one protocol. +/// We also need a function to compare contexts to see if the child should be dispatched +/// +typedef +VOID +(EFIAPI *GET_CONTEXT) ( + IN DATABASE_RECORD * Record, + OUT PCH_SMM_CONTEXT * Context + ); + +typedef +BOOLEAN +(EFIAPI *CMP_CONTEXT) ( + IN PCH_SMM_CONTEXT * Context1, + IN PCH_SMM_CONTEXT * Context2 + ); + +/// +/// Finally, every protocol will require a "Get Context" and "Compare Context" call, so +/// we may as well wrap that up in a table, too. +/// +typedef struct { + GET_CONTEXT GetContext; + CMP_CONTEXT CmpContext; +} CONTEXT_FUNCTIONS; + +extern CONTEXT_FUNCTIONS ContextFunctions[PchSmmProtocolTypeMax]; + +/// +/// MAPPING CONTEXT TO BIT DESCRIPTIONS +/// I'd like to have a general approach to mapping contexts to bit descriptions. +/// Sometimes, we'll find that we can use table lookups or constant assignments; +/// other times, we'll find that we'll need to use a function to perform the mapping. +/// If we define a macro to mask that process, we'll never have to change the code. +/// I don't know if this is desirable or not -- if it isn't, then we can get rid +/// of the macros and just use function calls or variable assignments. Doesn't matter +/// to me. +/// Mapping complex contexts requires a function +/// + +/** + Maps a USB context to a source description. + + @param[in] Context The context we need to map. Type must be USB. + @param[out] SrcDesc The source description that corresponds to the given context. + + @retval None +**/ +VOID +MapUsbToSrcDesc ( + IN PCH_SMM_CONTEXT *Context, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Figure out which timer the child is requesting and + send back the source description + + @param[in] DispatchContext The pointer to the Dispatch Context instances + @param[out] SrcDesc The pointer to the source description + + @retval None +**/ +VOID +MapPeriodicTimerToSrcDesc ( + IN PCH_SMM_CONTEXT *DispatchContext, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ); + +// +// Mapping simple contexts can be done by assignment or lookup table +// +extern const PCH_SMM_SOURCE_DESC SW_SOURCE_DESC; +extern const PCH_SMM_SOURCE_DESC SX_SOURCE_DESC; +extern const PCH_SMM_SOURCE_DESC POWER_BUTTON_SOURCE_DESC; + +// +// With the changes we've made to the protocols, we can now use table +// lookups for the following protocols: +// +#define NUM_SUPPORTED_GPIS 16 +extern const PCH_SMM_SOURCE_DESC LPTH_GPI_SOURCE_DESC[NUM_SUPPORTED_GPIS]; +extern const PCH_SMM_SOURCE_DESC LPTLP_GPI_SOURCE_DESC[NUM_SUPPORTED_GPIS]; + +extern PCH_SMM_SOURCE_DESC ICHN_H_SOURCE_DESCS[NUM_ICHN_TYPES]; +extern PCH_SMM_SOURCE_DESC ICHN_LP_SOURCE_DESCS[NUM_ICHN_TYPES]; +extern PCH_SMM_SOURCE_DESC ICHN_EX_SOURCE_DESCS[IchnExTypeMAX - IchnExPciExpress]; + +/// +/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF. +/// +#define MAXIMUM_SWI_VALUE 0xFF + +/// +/// GENERALIZING THE CALLBACK +/// All SmmXxxDispatch callbacks have the same form: +/// +/// VOID Callback( EFI_HANDLE, EFI_SMM_Xxx_DISPATCH_CONTEXT ) +/// We need a typedef that'll allow us to call any callback +/// +typedef +VOID +(EFIAPI *PCH_SMM_CALLBACK) ( + IN EFI_HANDLE Handle, + IN PCH_SMM_CONTEXT * Context + ); + +/// +/// Open: Need to make sure this kind of type cast will actually work. +/// May need an intermediate form w/ two VOID* arguments. I'll figure +/// that out when I start compiling. +/// +typedef +VOID +(EFIAPI *PCH_SMM_CLEAR_SOURCE) ( + PCH_SMM_SOURCE_DESC * SrcDesc + ); + +/// +/// "DATABASE" RECORD +/// Linked list data structures +/// +#define DATABASE_RECORD_SIGNATURE EFI_SIGNATURE_32 ('D', 'B', 'R', 'C') + +struct _DATABASE_RECORD { + UINT32 Signature; + LIST_ENTRY Link; + + /// + /// Status and Enable bit description + /// + PCH_SMM_SOURCE_DESC SrcDesc; + + /// + /// Callback function + /// + PCH_SMM_CALLBACK Callback; + PCH_SMM_CONTEXT ChildContext; + + /// + /// Special handling hooks -- init them to NULL if unused/unneeded + /// + PCH_SMM_CLEAR_SOURCE ClearSource; ///< needed for SWSMI timer + + /// + /// Functions required to make callback code general + /// + CONTEXT_FUNCTIONS ContextFunctions; + + /// + /// The protocol that this record dispatches + /// + PCH_SMM_PROTOCOL_TYPE ProtocolType; + +}; + +#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE) + +/// +/// HOOKING INTO THE ARCHITECTURE +/// +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_GENERIC_REGISTER) ( + IN VOID **This, + IN VOID *DispatchFunction, + IN VOID *DispatchContext, + OUT EFI_HANDLE * DispatchHandle + ); +typedef +EFI_STATUS +(EFIAPI *PCH_SMM_GENERIC_UNREGISTER) ( + IN VOID **This, + IN EFI_HANDLE DispatchHandle + ); + +/// +/// Define a memory "stamp" equivalent in size and function to most of the protocols +/// +typedef struct { + PCH_SMM_GENERIC_REGISTER Register; + PCH_SMM_GENERIC_UNREGISTER Unregister; + UINTN Extra1; + UINTN Extra2; ///< may not need this one +} PCH_SMM_GENERIC_PROTOCOL; + +/** + Register a child SMI dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source. + @param[in] DispatchContext Pointer to the dispatch function's context. + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver, will be the address of linked + list link in the call back record. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record + @retval EFI_INVALID_PARAMETER The input parameter is invalid + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. +**/ +EFI_STATUS +PchSmmCoreRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN PCH_SMM_CALLBACK DispatchFunction, + IN PCH_SMM_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ); + +/** + Unregister a child SMI source dispatch function with a parent SMM driver. + + @param[in] This Pointer to the EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +PchSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ); + +typedef union { + PCH_SMM_GENERIC_PROTOCOL Generic; + + EFI_SMM_USB_DISPATCH_PROTOCOL Usb; + EFI_SMM_SX_DISPATCH_PROTOCOL Sx; + EFI_SMM_SW_DISPATCH_PROTOCOL Sw; + EFI_SMM_GPI_DISPATCH_PROTOCOL Gpi; + EFI_SMM_ICHN_DISPATCH_PROTOCOL Ichn; + EFI_SMM_ICHN_DISPATCH_EX_PROTOCOL IchnEx; + EFI_SMM_POWER_BUTTON_DISPATCH_PROTOCOL PowerButton; + EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL PeriodicTimer; +} PCH_SMM_PROTOCOL; + +/// +/// Define a structure to help us identify the generic protocol +/// +#define PROTOCOL_SIGNATURE EFI_SIGNATURE_32 ('P', 'R', 'O', 'T') + +typedef struct { + UINTN Signature; + + PCH_SMM_PROTOCOL_TYPE Type; + PCH_SMM_PROTOCOL Protocols; +} PCH_SMM_QUALIFIED_PROTOCOL; + +#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \ + CR ( \ + _generic, \ + PCH_SMM_QUALIFIED_PROTOCOL, \ + Protocols, \ + PROTOCOL_SIGNATURE \ + ) + +/// +/// Create private data for the protocols that we'll publish +/// +typedef struct { + LIST_ENTRY CallbackDataBase; + EFI_HANDLE InstallMultProtHandle; + PCH_SMM_QUALIFIED_PROTOCOL Protocols[PchSmmProtocolTypeMax]; +} PRIVATE_DATA; + +extern PRIVATE_DATA mPrivateData; +extern EFI_SMM_SYSTEM_TABLE *mSmst; +extern UINT32 mAcpiBaseAddr; +extern UINT32 mGpioBaseAddr; +extern EFI_SMM_BASE_PROTOCOL *mSmmBase; + +/** + Get the Software Smi value + + @param[in] Record No use + @param[out] Context The context that includes Software Smi value to be filled + + @retval None +**/ +VOID +EFIAPI +SwGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether software SMI value of two contexts match + + @param[in] Context1 Context 1 that includes software SMI value 1 + @param[in] Context2 Context 2 that includes software SMI value 2 + + @retval FALSE Software SMI value match + @retval TRUE Software SMI value don't match +**/ +BOOLEAN +EFIAPI +SwCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + Get the Sleep type + + @param[in] Record No use + @param[out] Context The context that includes SLP_TYP bits to be filled + + @retval None +**/ +VOID +EFIAPI +SxGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether sleep type of two contexts match + + @param[in] Context1 Context 1 that includes sleep type 1 + @param[in] Context2 Context 2 that includes sleep type 2 + + @retval FALSE Sleep types match + @retval TRUE Sleep types don't match +**/ +BOOLEAN +EFIAPI +SxCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + Update the elapsed time from the Interval data of DATABASE_RECORD + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] HwContext The Context to be updated. + + @retval None +**/ +VOID +EFIAPI +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether Periodic Timer of two contexts match + + @param[in] Context1 Context 1 that includes Periodic Timer 1 + @param[in] Context2 Context 2 that includes Periodic Timer 2 + + @retval FALSE Periodic Timer match + @retval TRUE Periodic Timer don't match +**/ +BOOLEAN +EFIAPI +PeriodicTimerCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + Get the power button status. + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] Context Calling context from the hardware, will be updated with the current power button status. + + @retval None +**/ +VOID +EFIAPI +PowerButtonGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ); + +/** + Check whether Power Button status of two contexts match + + @param[in] Context1 Context 1 that includes Power Button status 1 + @param[in] Context2 Context 2 that includes Power Button status 2 + + @retval FALSE Power Button status match + @retval TRUE Power Button status don't match +**/ +BOOLEAN +EFIAPI +PowerButtonCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ); + +/** + This function is responsible for calculating and enabling any timers that are required + to dispatch messages to children. The SrcDesc argument isn't acutally used. + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. + + @retval None. +**/ +VOID +EFIAPI +PchSmmPeriodicTimerClearSource ( + IN PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + This services returns the next SMI tick period that is supported by the chipset. + The order returned is from longest to shortest interval period. + + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL instance. + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI interval period that is supported by the child. + + @retval EFI_SUCCESS The service returned successfully. + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid. +**/ +EFI_STATUS +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ); + +/** + When we get an SMI that indicates that we are transitioning to a sleep state, + we need to actually transition to that state. We do this by disabling the + "SMI on sleep enable" feature, which generates an SMI when the operating system + tries to put the system to sleep, and then physically putting the system to sleep. + + @param[in] None + + @retval None. +**/ +VOID +PchSmmSxGoToSleep ( + VOID + ); + +/** + Clear the SMI status bit after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +EFIAPI +PchSmmIchnClearSource ( + IN PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Fix the base address of the source regs and status regs. + Since Base should get from register filled by platform modules already. + + @param[in] None. + + @retval None. +**/ +VOID +PchSmmIchnFixSourceBase ( + VOID + ); + +#endif diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmCore.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmCore.c new file mode 100644 index 0000000..89100d5 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmCore.c @@ -0,0 +1,891 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PchSmm.h" +#include "PchSmmHelpers.h" +// AMI_OVERRIDE, GPIO_ROUT >>> +#include "Token.h" +// AMI_OVERRIDE, GPIO_ROUT <<< + +/// +/// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// MODULE / GLOBAL DATA +/// +/// Module variables used by the both the main dispatcher and the source dispatchers +/// Declared in PchSmmSources.h +/// +EFI_SMM_SYSTEM_TABLE *mSmst; +UINT32 mAcpiBaseAddr; +UINT32 mGpioBaseAddr; +EFI_SMM_BASE_PROTOCOL *mSmmBase; +// +// The reserved mmio address can only be used in Sx handler +// it's not reserved in ACPI. +// +EFI_PHYSICAL_ADDRESS mResvMmioBaseAddr; + +PRIVATE_DATA mPrivateData = { ///< for the structure + { + NULL + }, ///< CallbackDataBase linked list head + NULL, ///< EFI handle returned when calling InstallMultipleProtocolInterfaces + { ///< protocol arrays + /// + /// elements within the array + /// + { + PROTOCOL_SIGNATURE, + UsbType, + { + (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister + } + }, + { + PROTOCOL_SIGNATURE, + SxType, + { + (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister + } + }, + { + PROTOCOL_SIGNATURE, + SwType, + { + (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister, + (UINTN) MAXIMUM_SWI_VALUE + } + }, + { + PROTOCOL_SIGNATURE, + GpiType, + { + (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister, + (UINTN) NUM_SUPPORTED_GPIS + } + }, + { + PROTOCOL_SIGNATURE, + IchnType, + { + (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister + } + }, + { + PROTOCOL_SIGNATURE, + IchnExType, + { + (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister + } + }, + { + PROTOCOL_SIGNATURE, + PowerButtonType, + { + (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister + } + }, + { + PROTOCOL_SIGNATURE, + PeriodicTimerType, + { + (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister, + (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister, + (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval + } + }, + } +}; + +CONTEXT_FUNCTIONS mContextFunctions[PchSmmProtocolTypeMax] = { + { + NULL, + NULL + }, + { + SxGetContext, + SxCmpContext + }, + { + SwGetContext, + SwCmpContext + }, + { + NULL, + NULL + }, + { + NULL, + NULL + }, + { + NULL, + NULL + }, + { + PowerButtonGetContext, + PowerButtonCmpContext + }, + { + PeriodicTimerGetContext, + PeriodicTimerCmpContext + }, +}; + +/// +/// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// PROTOTYPES +/// +/// Functions use only in this file +/// +EFI_STATUS +EFIAPI +PchSmmCoreDispatcher ( + IN EFI_HANDLE SmmImageHandle, + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ); + +/// +/// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/// FUNCTIONS +/// +/// Driver entry point +/// + +/** + Initializes the PCH SMM Dispatcher + + @param[in] ImageHandle Pointer to the loaded image protocol for this driver + @param[in] SystemTable Pointer to the EFI System Table + + @retval EFI_SUCCESS PchSmmDispatcher Initialization completed. +**/ +EFI_STATUS +EFIAPI +InitializePchSmmDispatcher ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + /// + /// Locate SMM Base Protocol + /// + Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &mSmmBase); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return Status; + } + /// + /// Initialize our module variables + /// + Status = mSmmBase->GetSmstLocation (mSmmBase, &mSmst); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return Status; + } + + PERF_START_EX (ImageHandle, L"SmmModule", NULL, AsmReadTsc(), 8); + + /// + /// Access ACPI Base Addresses Register + /// + mAcpiBaseAddr = (UINT32) (MmioRead16 ( + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_ACPI_BASE) + ) & B_PCH_LPC_ACPI_BASE_BAR); + ASSERT (mAcpiBaseAddr != 0); + + /// + /// Access GPIO Base Addresses Register + /// + mGpioBaseAddr = (UINT32) (MmioRead16 ( + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_GPIO_BASE) + ) & B_PCH_LPC_GPIO_BASE_BAR); + ASSERT (mGpioBaseAddr != 0); + + /// + /// Fix the ICHN_SOURCE_DESCS base, in order to obtain independence with platform. + /// + PchSmmIchnFixSourceBase (); + + PchSmmPublishDispatchProtocols (); + + /// + /// Register a callback function to handle subsequent SMIs. This callback + /// will be called by SmmCoreDispatcher. + /// +//AMI_OVERRIDE Support SMM2>> + mSmmBase->RegisterCallback (mSmmBase, ImageHandle, PchSmmCoreDispatcher, TRUE, FALSE); +//AMI_OVERRIDE Support SMM2<< + + /// + /// Initialize Callback DataBase + /// + InitializeListHead (&mPrivateData.CallbackDataBase); + + /// + /// Enable SMIs on the PCH now that we have a callback + /// + PchSmmInitHardware (); + + mResvMmioBaseAddr = 0x0ffffffff; +#ifndef AMI_OVERRIDE_FOR_PCH + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateMaxAddressSearchTopDown, + EfiGcdMemoryTypeMemoryMappedIo, + 16, // 2^16: 64K Alignment + 0x10000, // 64K Length + &mResvMmioBaseAddr, + ImageHandle, + NULL + ); +#else + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateMaxAddressSearchBottomUp, + EfiGcdMemoryTypeMemoryMappedIo, + 16, // 2^16: 64K Alignment + 0x10000, // 64K Length + &mResvMmioBaseAddr, + ImageHandle, + NULL + ); +#endif + ASSERT_EFI_ERROR (Status); + DEBUG((EFI_D_INFO,"mResvMmioBaseAddr %x\n", mResvMmioBaseAddr)); + + return EFI_SUCCESS; +} + +/** + Check the Fed SwSmiInputValue to see if there is a duplicated one in the database + + @param[in] FedSwSmiInputValue Fed SwSmiInputValue + + @retval EFI_SUCCESS There is no duplicated SwSmiInputValue + @retval EFI_INVALID_PARAMETER There is a duplicated SwSmiInputValue +**/ +EFI_STATUS +SmiInputValueDuplicateCheck ( + UINTN FedSwSmiInputValue + ) +{ + + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + + if (RecordInDb->ProtocolType == SwType) { + if (RecordInDb->ChildContext.Sw.SwSmiInputValue == FedSwSmiInputValue) { + return EFI_INVALID_PARAMETER; + } + } + + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } + + return EFI_SUCCESS; +} + +/** + Register a child SMI dispatch function with a parent SMM driver. + + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL instance. + @param[in] DispatchFunction Pointer to dispatch function to be invoked for this SMI source. + @param[in] DispatchContext Pointer to the dispatch function's context. + @param[out] DispatchHandle Handle of dispatch function, for when interfacing + with the parent SMM driver, will be the address of linked + list link in the call back record. + + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record + @retval EFI_INVALID_PARAMETER The input parameter is invalid + @retval EFI_SUCCESS The dispatch function has been successfully + registered and the SMI source has been enabled. +**/ +EFI_STATUS +PchSmmCoreRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN PCH_SMM_CALLBACK DispatchFunction, + IN PCH_SMM_CONTEXT *DispatchContext, + OUT EFI_HANDLE *DispatchHandle + ) +{ + EFI_STATUS Status; + DATABASE_RECORD *Record; + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; + PCH_SMM_SOURCE_DESC NullSourceDesc = NULL_SOURCE_DESC_INITIALIZER; + PCH_SERIES PchSeries; + UINTN Index; + + PchSeries = GetPchSeries(); + Index = 0; + /// + /// Create database record and add to database + /// + if (mSmst == NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + Status = mSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof (DATABASE_RECORD), (VOID **) &Record); + if (EFI_ERROR (Status)) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + /// + /// Gather information about the registration request + /// + Record->Callback = DispatchFunction; + Record->ChildContext = *DispatchContext; + + Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This); + + Record->ProtocolType = Qualified->Type; + + Record->ContextFunctions = mContextFunctions[Qualified->Type]; + /// + /// Perform linked list housekeeping + /// + Record->Signature = DATABASE_RECORD_SIGNATURE; + + switch (Qualified->Type) { + /// + /// By the end of this switch statement, we'll know the + /// source description the child is registering for + /// + case UsbType: + /// + /// Check the validity of Context Type + /// + if ((Record->ChildContext.Usb.Type < UsbLegacy) || (Record->ChildContext.Usb.Type > UsbWake)) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + MapUsbToSrcDesc (DispatchContext, &(Record->SrcDesc)); + Record->ClearSource = NULL; + /// + /// use default clear source function + /// + break; + + case SxType: + /// + /// Check the validity of Context Type and Phase + /// + if ((Record->ChildContext.Sx.Type < SxS0) || + (Record->ChildContext.Sx.Type >= EfiMaximumSleepType) || + (Record->ChildContext.Sx.Phase < SxEntry) || + (Record->ChildContext.Sx.Phase >= EfiMaximumPhase) + ) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + CopyMem ((VOID *) &(Record->SrcDesc), (VOID *) (&SX_SOURCE_DESC), sizeof (PCH_SMM_SOURCE_DESC)); + Record->ClearSource = NULL; + /// + /// use default clear source function + /// + break; + + case SwType: + /// + /// Check the validity of Context Value + /// + if (Record->ChildContext.Sw.SwSmiInputValue > MAXIMUM_SWI_VALUE) { + goto Error; + } + + if (EFI_ERROR (SmiInputValueDuplicateCheck (Record->ChildContext.Sw.SwSmiInputValue))) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + CopyMem ((VOID *) &(Record->SrcDesc), (VOID *) (&SW_SOURCE_DESC), sizeof (PCH_SMM_SOURCE_DESC)); + Record->ClearSource = NULL; + /// + /// use default clear source function + /// + break; + + case GpiType: + Index = Record->ChildContext.Gpi.GpiNum; + if (PchSeries == PchH) { + Index -= V_PCH_LPTH_ALT_GP_SMI_GPIBASE; + if (Index >= S_PCH_LPTH_ALT_GP_SMI_GPISIZE) { + goto Error; + } + } else if (PchSeries == PchLp) { + Index -= V_PCH_LPTLP_ALT_GP_SMI_GPIBASE; + if (Index >= S_PCH_LPTLP_ALT_GP_SMI_GPISIZE) { + goto Error; + } + } else { + goto Error; + } + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + if (PchSeries == PchH) { + CopyMem ( + (VOID *) &(Record->SrcDesc), + (VOID *) &(LPTH_GPI_SOURCE_DESC[Index]), + sizeof (PCH_SMM_SOURCE_DESC) + ); + } else if (PchSeries == PchLp) { + CopyMem ( + (VOID *) &(Record->SrcDesc), + (VOID *) &(LPTLP_GPI_SOURCE_DESC[Index]), + sizeof (PCH_SMM_SOURCE_DESC) + ); + } + Record->ClearSource = NULL; + /// + /// use default clear source function + /// + break; + + case IchnType: + /// + /// Check the validity of Context Type + /// + if (Record->ChildContext.Ichn.Type >= NUM_ICHN_TYPES) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + if (PchSeries == PchLp) { + CopyMem ( + (VOID *) &(Record->SrcDesc), + (VOID *) &(ICHN_LP_SOURCE_DESCS[Record->ChildContext.Ichn.Type]), + sizeof (PCH_SMM_SOURCE_DESC) + ); + } else if (PchSeries == PchH) { + CopyMem ( + (VOID *) &(Record->SrcDesc), + (VOID *) &(ICHN_H_SOURCE_DESCS[Record->ChildContext.Ichn.Type]), + sizeof (PCH_SMM_SOURCE_DESC) + ); + } + Record->ClearSource = PchSmmIchnClearSource; + break; + + case IchnExType: + /// + /// Check the validity of Context Type + /// + if ((Record->ChildContext.IchnEx.Type < IchnExPciExpress) || (Record->ChildContext.IchnEx.Type >= IchnExTypeMAX)) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + CopyMem ( + (VOID *) &(Record->SrcDesc), + (VOID *) &(ICHN_EX_SOURCE_DESCS[Record->ChildContext.IchnEx.Type - IchnExPciExpress]), + sizeof (PCH_SMM_SOURCE_DESC) + ); + Record->ClearSource = NULL; + break; + + case PowerButtonType: + /// + /// Check the validity of Context Phase + /// + if ((Record->ChildContext.PowerButton.Phase < PowerButtonEntry) || + (Record->ChildContext.PowerButton.Phase > PowerButtonExit) + ) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + CopyMem ((VOID *) &(Record->SrcDesc), (VOID *) &POWER_BUTTON_SOURCE_DESC, sizeof (PCH_SMM_SOURCE_DESC)); + Record->ClearSource = NULL; + /// + /// use default clear source function + /// + break; + + case PeriodicTimerType: + /// + /// Check the validity of timer value + /// + if (DispatchContext->PeriodicTimer.SmiTickInterval <= 0) { + goto Error; + } + + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); + MapPeriodicTimerToSrcDesc (DispatchContext, &(Record->SrcDesc)); + Record->ClearSource = PchSmmPeriodicTimerClearSource; + break; + + default: + return EFI_INVALID_PARAMETER; + break; + } + + if (CompareSources (&Record->SrcDesc, &NullSourceDesc)) { + goto Error; + } + + if (Record->ClearSource == NULL) { + /// + /// Clear the SMI associated w/ the source using the default function + /// + PchSmmClearSource (&Record->SrcDesc); + } else { + /// + /// This source requires special handling to clear + /// + Record->ClearSource (&Record->SrcDesc); + } + + PchSmmEnableSource (&Record->SrcDesc); + +// AMI_OVERRIDE, GPIO_ROUT >>> +// Added GPIO_ROUT (B0:D31:F0 Reg#B8h) initialization for GPI SMI register. +{ + UINT32 GpioRout; + UINT32 GpioSmiRout; + + if (Qualified->Type == GpiType) { + if (PchSeries == PchH) { + GpioRout = (UINT32) (MmioRead32 ( \ + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_PCH, \ + PCI_DEVICE_NUMBER_PCH_LPC, \ + PCI_FUNCTION_NUMBER_PCH_LPC, \ + R_PCH_LPC_GPI_ROUT)\ + )); + + GpioRout &= ~(3 << (Record->ChildContext.Gpi.GpiNum * 2)); + GpioRout |= (1 << (Record->ChildContext.Gpi.GpiNum * 2)); + + MmioWrite32 ( \ + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_PCH, \ + PCI_DEVICE_NUMBER_PCH_LPC, \ + PCI_FUNCTION_NUMBER_PCH_LPC,\ + R_PCH_LPC_GPI_ROUT), \ + GpioRout\ + ); + }else if(PchSeries == PchLp){ + if( Record->ChildContext.Gpi.GpiNum >= 32 && Record->ChildContext.Gpi.GpiNum < 48){ + GpioRout = IoRead32(GPIO_BASE_ADDRESS + R_PCH_LP_LPC_GPI_ROUT1); + GpioSmiRout = IoRead32(GPIO_BASE_ADDRESS + R_PCH_LPTLP_ALT_GP_SMI_EN); + + GpioRout |= (1 << (Record->ChildContext.Gpi.GpiNum - 32)); + GpioSmiRout |= (1 << (Record->ChildContext.Gpi.GpiNum - 32)); + + IoWrite32((GPIO_BASE_ADDRESS + R_PCH_LP_LPC_GPI_ROUT1),GpioRout); + IoWrite32((GPIO_BASE_ADDRESS + R_PCH_LPTLP_ALT_GP_SMI_EN),GpioSmiRout); + } + } + } +} +// AMI_OVERRIDE, GPIO_ROUT <<< + + /// + /// Child's handle will be the address linked list link in the record + /// + *DispatchHandle = (EFI_HANDLE) (&Record->Link); + + return EFI_SUCCESS; + +Error: + Status = mSmst->SmmFreePool (Record); + /// + /// DEBUG((EFI_D_ERROR,"Free pool status %d\n", Status )); + /// + return EFI_INVALID_PARAMETER; +} + +/** + Unregister a child SMI source dispatch function with a parent SMM driver. + + @param[in] This Pointer to the EFI_SMM_IO_TRAP_DISPATCH_PROTOCOL instance. + @param[in] DispatchHandle Handle of dispatch function to deregister. + + @retval EFI_SUCCESS The dispatch function has been successfully + unregistered and the SMI source has been disabled + if there are no other registered child dispatch + functions for this SMI source. + @retval EFI_INVALID_PARAMETER Handle is invalid. +**/ +EFI_STATUS +PchSmmCoreUnRegister ( + IN PCH_SMM_GENERIC_PROTOCOL *This, + IN EFI_HANDLE *DispatchHandle + ) +{ + /// + /// BOOLEAN SafeToDisable; + /// + DATABASE_RECORD *RecordToDelete; + + /// + /// DATABASE_RECORD *RecordInDb; + /// EFI_LIST_NODE *LinkInDb; + /// + if (DispatchHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle); + + /// + /// Take the entry out of the linked list + /// + if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *) EFI_BAD_POINTER) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&RecordToDelete->Link); + + /// + /// See if we can disable the source, reserved for future use since this might + /// not be the only criteria to disable + /// + /// SafeToDisable = TRUE; + /// LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + /// while(!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + /// RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + /// if (CompareEnables (&RecordToDelete->SrcDesc, &RecordInDb->SrcDesc)) { + /// SafeToDisable = FALSE; + /// break; + /// } + /// LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + /// } + /// if (SafeToDisable) { + /// PchSmmDisableSource( &Record->SrcDesc ); + /// } + /// + return EFI_SUCCESS; +} + +/** + The callback function to handle subsequent SMIs. This callback will be called by SmmCoreDispatcher. + + @param[in] SmmImageHandle Not used + @param[in, out] CommunicationBuffer Not used + @param[in, out] SourceSize Not used + + @retval EFI_SUCCESS Function successfully completed +**/ +EFI_STATUS +EFIAPI +PchSmmCoreDispatcher ( + IN EFI_HANDLE SmmImageHandle, + IN OUT VOID *CommunicationBuffer, + IN OUT UINTN *SourceSize + ) +{ + /// + /// Used to prevent infinite loops + /// + UINTN EscapeCount; + + BOOLEAN ContextsMatch; + BOOLEAN EosSet; + BOOLEAN SxChildWasDispatched; + + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + DATABASE_RECORD *RecordToExhaust; + LIST_ENTRY *LinkToExhaust; + + PCH_SMM_CONTEXT Context; + + EFI_STATUS Status; + + PCH_SMM_SOURCE_DESC ActiveSource = NULL_SOURCE_DESC_INITIALIZER; + + EscapeCount = 100; + ContextsMatch = FALSE; + EosSet = FALSE; + SxChildWasDispatched = FALSE; + Status = EFI_SUCCESS; + + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) { + /// + /// We have children registered w/ us -- continue + /// + while ((!EosSet) && (EscapeCount > 0)) { + EscapeCount--; + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + + /// + /// look for the first active source + /// + if (!SourceIsActive (&RecordInDb->SrcDesc)) { + /// + /// Didn't find the source yet, keep looking + /// + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + + /// + /// if it's the last one, try to clear EOS + /// + if (IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + EosSet = PchSmmSetAndCheckEos (); + } + } else { + /// + /// We found a source. If this is a sleep type, we have to go to + /// appropriate sleep state anyway.No matter there is sleep child or not + /// + if (RecordInDb->ProtocolType == SxType) { + SxChildWasDispatched = TRUE; + } + /// + /// "cache" the source description and don't query I/O anymore + /// + CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb->SrcDesc), sizeof (PCH_SMM_SOURCE_DESC)); + LinkToExhaust = LinkInDb; + + /// + /// exhaust the rest of the queue looking for the same source + /// + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) { + RecordToExhaust = DATABASE_RECORD_FROM_LINK (LinkToExhaust); + /// + /// RecordToExhaust->Link might be removed (unregistered) by Callback function, and then the + /// system will hang in ASSERT() while calling GetNextNode(). + /// To prevent the issue, we need to get next record in DB here (before Callback function). + /// + LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase, &RecordToExhaust->Link); + + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) { + /// + /// These source descriptions are equal, so this callback should be + /// dispatched. + /// + if (RecordToExhaust->ContextFunctions.GetContext != NULL) { + /// + /// This child requires that we get a calling context from + /// hardware and compare that context to the one supplied + /// by the child. + /// + ASSERT (RecordToExhaust->ContextFunctions.CmpContext != NULL); + + /// + /// Make sure contexts match before dispatching event to child + /// + RecordToExhaust->ContextFunctions.GetContext (RecordToExhaust, &Context); + ContextsMatch = RecordToExhaust->ContextFunctions.CmpContext (&Context, &RecordToExhaust->ChildContext); + + } else { + /// + /// This child doesn't require any more calling context beyond what + /// it supplied in registration. Simply pass back what it gave us. + /// + ASSERT (RecordToExhaust->Callback != NULL); + Context = RecordToExhaust->ChildContext; + ContextsMatch = TRUE; + } + + if (ContextsMatch) { + + ASSERT (RecordToExhaust->Callback != NULL); + PERF_START_EX (NULL, L"SmmFunction", NULL, AsmReadTsc(), RecordToExhaust->ProtocolType); + RecordToExhaust->Callback ((EFI_HANDLE) & RecordToExhaust->Link, &Context); + PERF_END_EX (NULL, L"SmmFunction", NULL, AsmReadTsc(), RecordToExhaust->ProtocolType); + if (RecordToExhaust->ProtocolType == SxType) { + SxChildWasDispatched = TRUE; + } + } + } + } + + if (RecordInDb->ClearSource == NULL) { + /// + /// Clear the SMI associated w/ the source using the default function + /// + PchSmmClearSource (&ActiveSource); + } else { + /// + /// This source requires special handling to clear + /// + RecordInDb->ClearSource (&ActiveSource); + } + /// + /// Also, try to clear EOS + /// + EosSet = PchSmmSetAndCheckEos (); + /// + /// Queue is empty, reset the search + /// + break; + } + } + } + } + /// + /// If you arrive here, there are two possible reasons: + /// (1) you've got problems with clearing the SMI status bits in the + /// ACPI table. If you don't properly clear the SMI bits, then you won't be able to set the + /// EOS bit. If this happens too many times, the loop exits. + /// (2) there was a SMM communicate for callback messages that was received prior + /// to this driver. + /// If there is an asynchronous SMI that occurs while processing the Callback, let + /// all of the drivers (including this one) have an opportunity to scan for the SMI + /// and handle it. + /// If not, we don't want to exit and have the foreground app. clear EOS without letting + /// these other sources get serviced. + /// + /// This assert is not valid with CSM legacy solution because it generates software SMI + /// to test for legacy USB support presence. + /// This may not be illegal, so we cannot assert at this time. + /// + /// ASSERT (EscapeCount > 0); + /// + if (SxChildWasDispatched) { + /// + /// A child of the SmmSxDispatch protocol was dispatched during this call; + /// put the system to sleep. + /// + PchSmmSxGoToSleep (); + } + + return Status; + +} diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmGpi.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmGpi.c new file mode 100644 index 0000000..e9b16f9 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmGpi.c @@ -0,0 +1,101 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#include "PchSmmHelpers.h" + +#define LPTH_GPI_INIT_ELEMENT(num) { \ + PCH_SMM_NO_FLAGS, \ + { \ + { \ + { \ + ACPI_ADDR_TYPE, R_PCH_LPTH_ALT_GP_SMI_EN \ + }, \ + S_PCH_LPTH_ALT_GP_SMI_EN, num, \ + }, \ + NULL_BIT_DESC_INITIALIZER \ + }, \ + { \ + { \ + { \ + ACPI_ADDR_TYPE, R_PCH_LPTH_ALT_GP_SMI_STS \ + }, \ + S_PCH_LPTH_ALT_GP_SMI_STS, (num), \ + }, \ + } \ + } + +#define LPTLP_GPI_INIT_ELEMENT(num) { \ + PCH_SMM_NO_FLAGS, \ + { \ + { \ + { \ + GPIO_ADDR_TYPE, R_PCH_LPTLP_ALT_GP_SMI_EN \ + }, \ + S_PCH_LPTLP_ALT_GP_SMI_EN, num, \ + }, \ + NULL_BIT_DESC_INITIALIZER \ + }, \ + { \ + { \ + { \ + GPIO_ADDR_TYPE, R_PCH_LPTLP_ALT_GP_SMI_STS \ + }, \ + S_PCH_LPTLP_ALT_GP_SMI_STS, (num), \ + }, \ + } \ + } + +const PCH_SMM_SOURCE_DESC LPTH_GPI_SOURCE_DESC[NUM_SUPPORTED_GPIS] = { + LPTH_GPI_INIT_ELEMENT(0), + LPTH_GPI_INIT_ELEMENT(1), + LPTH_GPI_INIT_ELEMENT(2), + LPTH_GPI_INIT_ELEMENT(3), + LPTH_GPI_INIT_ELEMENT(4), + LPTH_GPI_INIT_ELEMENT(5), + LPTH_GPI_INIT_ELEMENT(6), + LPTH_GPI_INIT_ELEMENT(7), + LPTH_GPI_INIT_ELEMENT(8), + LPTH_GPI_INIT_ELEMENT(9), + LPTH_GPI_INIT_ELEMENT(10), + LPTH_GPI_INIT_ELEMENT(11), + LPTH_GPI_INIT_ELEMENT(12), + LPTH_GPI_INIT_ELEMENT(13), + LPTH_GPI_INIT_ELEMENT(14), + LPTH_GPI_INIT_ELEMENT(15), +}; + +const PCH_SMM_SOURCE_DESC LPTLP_GPI_SOURCE_DESC[NUM_SUPPORTED_GPIS] = { + LPTLP_GPI_INIT_ELEMENT(0), + LPTLP_GPI_INIT_ELEMENT(1), + LPTLP_GPI_INIT_ELEMENT(2), + LPTLP_GPI_INIT_ELEMENT(3), + LPTLP_GPI_INIT_ELEMENT(4), + LPTLP_GPI_INIT_ELEMENT(5), + LPTLP_GPI_INIT_ELEMENT(6), + LPTLP_GPI_INIT_ELEMENT(7), + LPTLP_GPI_INIT_ELEMENT(8), + LPTLP_GPI_INIT_ELEMENT(9), + LPTLP_GPI_INIT_ELEMENT(10), + LPTLP_GPI_INIT_ELEMENT(11), + LPTLP_GPI_INIT_ELEMENT(12), + LPTLP_GPI_INIT_ELEMENT(13), + LPTLP_GPI_INIT_ELEMENT(14), + LPTLP_GPI_INIT_ELEMENT(15), +}; diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmHelpers.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmHelpers.c new file mode 100644 index 0000000..062f518 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmHelpers.c @@ -0,0 +1,317 @@ +/** @file + Helper functions for PCH SMM dispatcher. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PchSmmHelpers.h" + +/// +/// #define BIT_ZERO 0x00000001 +/// +const UINT32 BIT_ZERO = 0x00000001; + +/// +/// SUPPORT / HELPER FUNCTIONS (PCH version-independent) +/// + +/** + Compare 2 SMM source descriptors' enable settings. + + @param[in] Src1 Pointer to the PCH SMI source description table 1 + @param[in] Src2 Pointer to the PCH SMI source description table 2 + + @retval TRUE The enable settings of the 2 SMM source descriptors are identical. + @retval FALSE The enable settings of the 2 SMM source descriptors are not identical. +**/ +BOOLEAN +CompareEnables ( + const IN PCH_SMM_SOURCE_DESC *Src1, + const IN PCH_SMM_SOURCE_DESC *Src2 + ) +{ + BOOLEAN IsEqual; + UINTN loopvar; + + IsEqual = TRUE; + for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) { + /// + /// It's okay to compare a NULL bit description to a non-NULL bit description. + /// They are unequal and these tests will generate the correct result. + /// + if (Src1->En[loopvar].Bit != Src2->En[loopvar].Bit || + Src1->En[loopvar].Reg.Type != Src2->En[loopvar].Reg.Type || + Src1->En[loopvar].Reg.Data.raw != Src2->En[loopvar].Reg.Data.raw + ) { + IsEqual = FALSE; + break; + /// + /// out of for loop + /// + } + } + + return IsEqual; +} + +/** + Compare 2 SMM source descriptors' statuses. + + @param[in] Src1 Pointer to the PCH SMI source description table 1 + @param[in] Src2 Pointer to the PCH SMI source description table 2 + + @retval TRUE The statuses of the 2 SMM source descriptors are identical. + @retval FALSE The statuses of the 2 SMM source descriptors are not identical. +**/ +BOOLEAN +CompareStatuses ( + const IN PCH_SMM_SOURCE_DESC *Src1, + const IN PCH_SMM_SOURCE_DESC *Src2 + ) +{ + BOOLEAN IsEqual; + UINTN loopvar; + + IsEqual = TRUE; + + for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) { + /// + /// It's okay to compare a NULL bit description to a non-NULL bit description. + /// They are unequal and these tests will generate the correct result. + /// + if (Src1->Sts[loopvar].Bit != Src2->Sts[loopvar].Bit || + Src1->Sts[loopvar].Reg.Type != Src2->Sts[loopvar].Reg.Type || + Src1->Sts[loopvar].Reg.Data.raw != Src2->Sts[loopvar].Reg.Data.raw + ) { + IsEqual = FALSE; + break; + /// + /// out of for loop + /// + } + } + + return IsEqual; +} + +/** + Compare 2 SMM source descriptors, based on Enable settings and Status settings of them. + + @param[in] Src1 Pointer to the PCH SMI source description table 1 + @param[in] Src2 Pointer to the PCH SMI source description table 2 + + @retval TRUE The 2 SMM source descriptors are identical. + @retval FALSE The 2 SMM source descriptors are not identical. +**/ +BOOLEAN +CompareSources ( + const IN PCH_SMM_SOURCE_DESC *Src1, + const IN PCH_SMM_SOURCE_DESC *Src2 + ) +{ + return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses (Src1, Src2)); +} + +/** + Check if an SMM source is active. + + @param[in] Src Pointer to the PCH SMI source description table + + @retval TRUE It is active. + @retval FALSE It is inactive. +**/ +BOOLEAN +SourceIsActive ( + const IN PCH_SMM_SOURCE_DESC *Src + ) +{ + BOOLEAN IsActive; + UINTN loopvar; + + BOOLEAN SciEn; + + IsActive = TRUE; + + SciEn = PchSmmGetSciEn (); + + if ((Src->Flags & PCH_SMM_SCI_EN_DEPENDENT) && (SciEn)) { + /// + /// This source is dependent on SciEn, and SciEn == 1. An ACPI OS is present, + /// so we shouldn't do anything w/ this source until SciEn == 0. + /// + IsActive = FALSE; + + } else { + /// + /// Read each bit desc from hardware and make sure it's a one + /// + for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) { + + if (!IS_BIT_DESC_NULL (Src->En[loopvar])) { + + if (ReadBitDesc (&Src->En[loopvar]) == 0) { + IsActive = FALSE; + break; + /// + /// out of for loop + /// + } + + } + } + + if (IsActive) { + /// + /// Read each bit desc from hardware and make sure it's a one + /// + for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) { + + if (!IS_BIT_DESC_NULL (Src->Sts[loopvar])) { + + if (ReadBitDesc (&Src->Sts[loopvar]) == 0) { + IsActive = FALSE; + break; + /// + /// out of for loop + /// + } + + } + } + } + } + + return IsActive; +} + +/** + Enable the SMI source event by set the SMI enable bit, this function would also clear SMI + status bit to make initial state is correct + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +PchSmmEnableSource ( + const PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINTN loopvar; + + /// + /// Set enables to 1 by writing a 1 + /// + for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) { + if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) { + WriteBitDesc (&SrcDesc->En[loopvar], 1, FALSE); + } + } + /// + /// Clear statuses to 0 by writing a 1 + /// + for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) { + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) { + WriteBitDesc (&SrcDesc->Sts[loopvar], 1, TRUE); + } + } +} + +/** + Disable the SMI source event by clear the SMI enable bit + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +PchSmmDisableSource ( + const PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINTN loopvar; + + for (loopvar = 0; loopvar < NUM_EN_BITS; loopvar++) { + if (!IS_BIT_DESC_NULL (SrcDesc->En[loopvar])) { + WriteBitDesc (&SrcDesc->En[loopvar], 0, FALSE); + } + } +} + +/** + Clear the SMI status bit by set the source bit of SMI status register + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +PchSmmClearSource ( + const PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINTN loopvar; + + for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) { + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) { + WriteBitDesc (&SrcDesc->Sts[loopvar], 1, TRUE); + } + } +} + +/** + Sets the source to a 1 and then waits for it to clear. + Be very careful when calling this function -- it will not + ASSERT. An acceptable case to call the function is when + waiting for the NEWCENTURY_STS bit to clear (which takes + 3 RTCCLKs). + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +PchSmmClearSourceAndBlock ( + const PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + UINTN loopvar; + BOOLEAN IsSet; + + for (loopvar = 0; loopvar < NUM_STS_BITS; loopvar++) { + + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[loopvar])) { + /// + /// Write the bit + /// + WriteBitDesc (&SrcDesc->Sts[loopvar], 1, TRUE); + + /// + /// Don't return until the bit actually clears. + /// + IsSet = TRUE; + while (IsSet) { + IsSet = ReadBitDesc (&SrcDesc->Sts[loopvar]); + /// + /// IsSet will eventually clear -- or else we'll have + /// an infinite loop. + /// + } + } + } +} diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmHelpers.h b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmHelpers.h new file mode 100644 index 0000000..24ef5f8 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmHelpers.h @@ -0,0 +1,155 @@ +/** @file + Helper functions for PCH SMM + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#ifndef PCH_SMM_HELPERS_H +#define PCH_SMM_HELPERS_H + +#include "PchSmm.h" +#include "PchxSmmHelpers.h" + +// +// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// SUPPORT / HELPER FUNCTIONS (PCH version-independent) +// + +/** + Publish SMI Dispatch protocols. + + @param[in] None + + @retval None +**/ +VOID +PchSmmPublishDispatchProtocols ( + VOID + ); + +/** + Compare 2 SMM source descriptors' enable settings. + + @param[in] Src1 Pointer to the PCH SMI source description table 1 + @param[in] Src2 Pointer to the PCH SMI source description table 2 + + @retval TRUE The enable settings of the 2 SMM source descriptors are identical. + @retval FALSE The enable settings of the 2 SMM source descriptors are not identical. +**/ +BOOLEAN +CompareEnables ( + const IN PCH_SMM_SOURCE_DESC *Src1, + const IN PCH_SMM_SOURCE_DESC *Src2 + ); + +/** + Compare 2 SMM source descriptors' statuses. + + @param[in] Src1 Pointer to the PCH SMI source description table 1 + @param[in] Src2 Pointer to the PCH SMI source description table 2 + + @retval TRUE The statuses of the 2 SMM source descriptors are identical. + @retval FALSE The statuses of the 2 SMM source descriptors are not identical. +**/ +BOOLEAN +CompareStatuses ( + const IN PCH_SMM_SOURCE_DESC *Src1, + const IN PCH_SMM_SOURCE_DESC *Src2 + ); + +/** + Compare 2 SMM source descriptors, based on Enable settings and Status settings of them. + + @param[in] Src1 Pointer to the PCH SMI source description table 1 + @param[in] Src2 Pointer to the PCH SMI source description table 2 + + @retval TRUE The 2 SMM source descriptors are identical. + @retval FALSE The 2 SMM source descriptors are not identical. +**/ +BOOLEAN +CompareSources ( + const IN PCH_SMM_SOURCE_DESC *Src1, + const IN PCH_SMM_SOURCE_DESC *Src2 + ); + +/** + Check if an SMM source is active. + + @param[in] Src Pointer to the PCH SMI source description table + + @retval TRUE It is active. + @retval FALSE It is inactive. +**/ +BOOLEAN +SourceIsActive ( + const IN PCH_SMM_SOURCE_DESC *Src + ); + +/** + Enable the SMI source event by set the SMI enable bit, this function would also clear SMI + status bit to make initial state is correct + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +PchSmmEnableSource ( + const PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Disable the SMI source event by clear the SMI enable bit + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +PchSmmDisableSource ( + const PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Clear the SMI status bit by set the source bit of SMI status register + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +PchSmmClearSource ( + const PCH_SMM_SOURCE_DESC *SrcDesc + ); + +/** + Sets the source to a 1 and then waits for it to clear. + Be very careful when calling this function -- it will not + ASSERT. An acceptable case to call the function is when + waiting for the NEWCENTURY_STS bit to clear (which takes + 3 RTCCLKs). + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +PchSmmClearSourceAndBlock ( + const PCH_SMM_SOURCE_DESC *SrcDesc + ); + +#endif diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmIchn.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmIchn.c new file mode 100644 index 0000000..5ecb7d3 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmIchn.c @@ -0,0 +1,2425 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Ichn dispatch protocol. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#include "PchSmmHelpers.h" + +#define PCH_RCRB_BASE_NEED_FIX 0 + +PCH_SMM_SOURCE_DESC ICHN_H_SOURCE_DESCS[NUM_ICHN_TYPES] = { + /// + /// IchnMch + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_DMISMI + } + } + }, + /// + /// IchnPme + /// + { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0a_EN + }, + S_PCH_ACPI_GPE0a_EN, + N_PCH_ACPI_GPE0a_EN_PME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0a_STS + }, + S_PCH_ACPI_GPE0a_STS, + N_PCH_ACPI_GPE0a_STS_PME + } + } + }, + /// + /// IchnRtcAlarm + /// + { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_PM1_EN + }, + S_PCH_ACPI_PM1_EN, + N_PCH_ACPI_PM1_EN_RTC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_PM1_STS + }, + S_PCH_ACPI_PM1_STS, + N_PCH_ACPI_PM1_STS_RTC + } + } + }, + /// + /// IchnRingIndicate + /// + { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0a_EN + }, + S_PCH_ACPI_GPE0a_EN, + N_PCH_ACPI_GPE0a_EN_RI + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0a_STS + }, + S_PCH_ACPI_GPE0a_STS, + N_PCH_ACPI_GPE0a_STS_RI + } + } + }, + /// + /// IchnAc97Wake + /// ICH8M has removed AC97 but IchnAc97Wake is the enumed index reserved in framework SmmIchnDispatch protocol, + /// we just fill in invalid initializer and not use it. + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnSerialIrq + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_SERIRQ + } + } + }, + /// + /// IchnY2KRollover + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_NEWCENTURY + } + } + }, + /// + /// IchnTcoTimeout + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_TIMEOUT + } + } + }, + /// + /// IchnOsTco + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_SW_TCO_SMI + } + } + }, + /// + /// IchnNmi + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_CNT) + }, + S_PCH_TCO1_CNT, + N_PCH_TCO_CNT_NMI2SMI_EN + } + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_NMI2SMI + } + } + }, + /// + /// IchnIntruderDetect + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO2_CNT) + }, + S_PCH_TCO2_CNT, + N_PCH_TCO2_CNT_INTRD_SEL + } + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO2_STS) + }, + S_PCH_TCO2_STS, + N_PCH_TCO2_STS_INTRD_DET + } + } + }, + /// + /// IchnBiosWp + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_LPC << 16) | + (PCI_FUNCTION_NUMBER_PCH_LPC << 8) | + R_PCH_LPC_BIOS_CNTL + ) + }, + S_PCH_LPC_BIOS_CNTL, + N_PCH_LPC_BIOS_CNTL_BLE + } + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_BIOSWR + } + } + }, + /// + /// IchnMcSmi + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_MCSMI + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_MCSMI + } + } + }, + /// + /// IchnPmeB0 + /// + { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0a_EN + }, + S_PCH_ACPI_GPE0a_EN, + N_PCH_ACPI_GPE0a_EN_PME_B0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0a_STS + }, + S_PCH_ACPI_GPE0a_STS, + N_PCH_ACPI_GPE0a_STS_PME_B0 + } + } + }, + /// + /// IchnThrmSts (THRM# signal no longer existed in PCH) + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnSmBus + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_SMBUS + } + } + }, + /// + /// IchnIntelUsb2 + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_INTEL_USB2 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_INTEL_USB2 + } + } + }, + /// + /// IchnMonSmi7 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnMonSmi6 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnMonSmi5 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnMonSmi4 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap13 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap12, KBC_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 12 + } + } + }, + /// + /// IchnDevTrap11 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap10 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap9, PIRQDH_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 9 + } + } + }, + /// + /// IchnDevTrap8, PIRQCG_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 8 + } + } + }, + /// + /// IchnDevTrap7, PIRQBF_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 7 + } + } + }, + /// + /// IchnDevTrap6, PIRQAE_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 6 + } + } + }, + /// + /// IchnDevTrap5 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap3 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap2 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap1 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap0, IDE_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 0 + } + } + }, + /// + /// PCH I/O Trap register 3 monitor, + /// The "PCH_RCRB_BASE_NEED_FIX" should be fixed since the RCRB base should get from the RCBA register filled by platform module. + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_IO_TRAP_3 + }, + 8, + 0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_TRSR + }, + 1, + 3 + } + } + }, + /// + /// PCH I/O Trap register 2 monitor + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_IO_TRAP_2 + }, + 8, + 0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_TRSR + }, + 1, + 2 + } + } + }, + /// + /// PCH I/O Trap register 1 monitor + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_IO_TRAP_1 + }, + 8, + 0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_TRSR + }, + 1, + 1 + } + } + }, + /// + /// PCH I/O Trap register 0 monitor + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_IO_TRAP_0 + }, + 8, + 0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_TRSR + }, + 1, + 0 + } + } + } +}; + +PCH_SMM_SOURCE_DESC ICHN_LP_SOURCE_DESCS[NUM_ICHN_TYPES] = { + /// + /// IchnMch + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_DMISMI + } + } + }, + /// + /// IchnPme + /// + { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0_EN_127_96 + }, + S_PCH_ACPI_GPE0_EN_127_96, + N_PCH_ACPI_GPE0_EN_127_96_PME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0_STS_127_96 + }, + S_PCH_ACPI_GPE0_STS_127_96, + N_PCH_ACPI_GPE0_STS_127_96_PME + } + } + }, + /// + /// IchnRtcAlarm + /// + { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_PM1_EN + }, + S_PCH_ACPI_PM1_EN, + N_PCH_ACPI_PM1_EN_RTC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_PM1_STS + }, + S_PCH_ACPI_PM1_STS, + N_PCH_ACPI_PM1_STS_RTC + } + } + }, + /// + /// IchnRingIndicate + /// + { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0_EN_127_96 + }, + S_PCH_ACPI_GPE0_EN_127_96, + N_PCH_ACPI_GPE0_EN_127_96_RI + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0_STS_127_96 + }, + S_PCH_ACPI_GPE0_STS_127_96, + N_PCH_ACPI_GPE0_STS_127_96_RI + } + } + }, + /// + /// IchnAc97Wake + /// ICH8M has removed AC97 but IchnAc97Wake is the enumed index reserved in framework SmmIchnDispatch protocol, + /// we just fill in invalid initializer and not use it. + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnSerialIrq + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_SERIRQ + } + } + }, + /// + /// IchnY2KRollover + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_NEWCENTURY + } + } + }, + /// + /// IchnTcoTimeout + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_TIMEOUT + } + } + }, + /// + /// IchnOsTco + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_SW_TCO_SMI + } + } + }, + /// + /// IchnNmi + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_CNT) + }, + S_PCH_TCO1_CNT, + N_PCH_TCO_CNT_NMI2SMI_EN + } + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_NMI2SMI + } + } + }, + /// + /// IchnIntruderDetect + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO2_CNT) + }, + S_PCH_TCO2_CNT, + N_PCH_TCO2_CNT_INTRD_SEL + } + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO2_STS) + }, + S_PCH_TCO2_STS, + N_PCH_TCO2_STS_INTRD_DET + } + } + }, + /// + /// IchnBiosWp + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_TCO + }, + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_LPC << 16) | + (PCI_FUNCTION_NUMBER_PCH_LPC << 8) | + R_PCH_LPC_BIOS_CNTL + ) + }, + S_PCH_LPC_BIOS_CNTL, + N_PCH_LPC_BIOS_CNTL_BLE + } + }, + { + { + { + ACPI_ADDR_TYPE, + (PCH_TCO_BASE + R_PCH_TCO1_STS) + }, + S_PCH_TCO1_STS, + N_PCH_TCO1_STS_BIOSWR + } + } + }, + /// + /// IchnMcSmi + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_MCSMI + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_MCSMI + } + } + }, + /// + /// IchnPmeB0 + /// + { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0_EN_127_96 + }, + S_PCH_ACPI_GPE0_EN_127_96, + N_PCH_ACPI_GPE0_EN_127_96_PME_B0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_GPE0_STS_127_96 + }, + S_PCH_ACPI_GPE0_STS_127_96, + N_PCH_ACPI_GPE0_STS_127_96_PME_B0 + } + } + }, + /// + /// IchnThrmSts (THRM# signal no longer existed in PCH) + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnSmBus + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_SMBUS + } + } + }, + /// + /// IchnIntelUsb2 + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_INTEL_USB2 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_INTEL_USB2 + } + } + }, + /// + /// IchnMonSmi7 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnMonSmi6 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnMonSmi5 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnMonSmi4 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap13 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap12, KBC_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 12 + } + } + }, + /// + /// IchnDevTrap11 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap10 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap9, PIRQDH_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 9 + } + } + }, + /// + /// IchnDevTrap8, PIRQCG_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 8 + } + } + }, + /// + /// IchnDevTrap7, PIRQBF_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 7 + } + } + }, + /// + /// IchnDevTrap6, PIRQAE_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 6 + } + } + }, + /// + /// IchnDevTrap5 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap3 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap2 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap1 + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + NULL_BIT_DESC_INITIALIZER + } + }, + /// + /// IchnDevTrap0, IDE_ACT_STS + /// + { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_DEVACT_STS + }, + S_PCH_DEVACT_STS, + 0 + } + } + }, + /// + /// PCH I/O Trap register 3 monitor, + /// The "PCH_RCRB_BASE_NEED_FIX" should be fixed since the RCRB base should get from the RCBA register filled by platform module. + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_IO_TRAP_3 + }, + 8, + 0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_TRSR + }, + 1, + 3 + } + } + }, + /// + /// PCH I/O Trap register 2 monitor + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_IO_TRAP_2 + }, + 8, + 0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_TRSR + }, + 1, + 2 + } + } + }, + /// + /// PCH I/O Trap register 1 monitor + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_IO_TRAP_1 + }, + 8, + 0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_TRSR + }, + 1, + 1 + } + } + }, + /// + /// PCH I/O Trap register 0 monitor + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_IO_TRAP_0 + }, + 8, + 0 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + MEMORY_MAPPED_IO_ADDRESS_TYPE, + PCH_RCRB_BASE_NEED_FIX + R_PCH_RCRB_TRSR + }, + 1, + 0 + } + } + } +}; + +PCH_SMM_SOURCE_DESC ICHN_EX_SOURCE_DESCS[IchnExTypeMAX - IchnExPciExpress] = { + /// + /// IchnExPciExpress + /// + NULL_SOURCE_DESC_INITIALIZER, + /// + /// IchnExMonitor + /// + NULL_SOURCE_DESC_INITIALIZER, + /// + /// IchnExSpi + /// + NULL_SOURCE_DESC_INITIALIZER, + /// + /// IchnExQRT + /// + NULL_SOURCE_DESC_INITIALIZER, + /// + /// IchnExGpioUnlock + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_GPIO_UNLOCK + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_GPIO_UNLOCK + } + } + }, + /// + /// IchnExTmrOverflow + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_PM1_EN + }, + S_PCH_ACPI_PM1_EN, + N_PCH_ACPI_PM1_EN_TMROF + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_PM1_STS + }, + S_PCH_ACPI_PM1_STS, + N_PCH_ACPI_PM1_STS_TMROF + } + } + }, + /// + /// IchnExPcie0Hotplug + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPPDM + } + } + }, + /// + /// IchnExPcie1Hotplug + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_2 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_2 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPPDM + } + } + }, + /// + /// IchnExPcie2Hotplug + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_3 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_3 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPPDM + } + } + }, + /// + /// IchnExPcie3Hotplug + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_4 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_4 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPPDM + } + } + }, + /// + /// IchnExPcie4Hotplug + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_5 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_5 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPPDM + } + } + }, + /// + /// IchnExPcie5Hotplug + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_6 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_6 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPPDM + } + } + }, + /// + /// IchnExPcie6Hotplug + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_7 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_7 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPPDM + } + } + }, + /// + /// IchnExPcie7Hotplug + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_8 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_8 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPPDM + } + } + }, + /// + /// IchnExPcie0LinkActive + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_1 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPLAS + } + } + }, + /// + /// IchnExPcie1LinkActive + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_2 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_2 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPLAS + } + } + }, + /// + /// IchnExPcie2LinkActive + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_3 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_3 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPLAS + } + } + }, + /// + /// IchnExPcie3LinkActive + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_4 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_4 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPLAS + } + } + }, + /// + /// IchnExPcie4LinkActive + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_5 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_5 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPLAS + } + } + }, + /// + /// IchnExPcie5LinkActive + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_6 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_6 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPLAS + } + } + }, + /// + /// IchnExPcie6LinkActive + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_7 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_7 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPLAS + } + } + }, + /// + /// IchnExPcie7LinkActive + /// + { + PCH_SMM_NO_FLAGS, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_8 << 8) | + R_PCH_PCIE_MPC + ) + }, + S_PCH_PCIE_MPC, + N_PCH_PCIE_MPC_HPME + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + PCIE_ADDR_TYPE, + ( + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | + (PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORTS << 16) | + (PCI_FUNCTION_NUMBER_PCH_PCIE_ROOT_PORT_8 << 8) | + R_PCH_PCIE_SMSCS + ) + }, + S_PCH_PCIE_SMSCS, + N_PCH_PCIE_SMSCS_HPLAS + } + } + } +}; + +/// +/// TCO_STS bit that needs to be cleared +/// +PCH_SMM_SOURCE_DESC TCO_STS = { + PCH_SMM_NO_FLAGS, + { + NULL_BIT_DESC_INITIALIZER, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_TCO + } + } +}; + +/** + Clear the SMI status bit after the SMI handling is done + + @param[in] SrcDesc Pointer to the PCH SMI source description table + + @retval None +**/ +VOID +EFIAPI +PchSmmIchnClearSource ( + PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + if (( + (SrcDesc->Sts[0].Reg.Data.acpi == PCH_TCO_BASE + R_PCH_TCO1_STS) && + (SrcDesc->Sts[0].Bit == N_PCH_TCO1_STS_NEWCENTURY) + ) || + ( + (SrcDesc->Sts[0].Reg.Data.acpi == PCH_TCO_BASE + R_PCH_TCO2_STS) && + (SrcDesc->Sts[0].Bit == N_PCH_TCO2_STS_INTRD_DET) + ) + ) { + /// + /// This is the Y2K rollover bit and requires special handling + /// + PchSmmClearSourceAndBlock (SrcDesc); + } else { + PchSmmClearSource (SrcDesc); + } + /// + /// Any TCO-based status bits require special handling. + /// SMI_STS.TCO_STS must be cleared in addition to the status bit in the TCO registers + /// + PchSmmClearSource (&TCO_STS); +} + +/** + Fix the base address of the source regs and status regs. + Since Base should get from register filled by platform modules already. + + @param[in] None. + + @retval None. +**/ +VOID +PchSmmIchnFixSourceBase ( + VOID + ) +{ + PCH_SERIES PchSeries; + + PchSeries = GetPchSeries(); + /// + /// We need to fix the IoTrap item's RCRB base, + /// + if (PchSeries == PchLp) { + ICHN_LP_SOURCE_DESCS[IchnIoTrap3].En[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_IO_TRAP_3); + ICHN_LP_SOURCE_DESCS[IchnIoTrap3].Sts[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_TRSR); + ICHN_LP_SOURCE_DESCS[IchnIoTrap2].En[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_IO_TRAP_2); + ICHN_LP_SOURCE_DESCS[IchnIoTrap2].Sts[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_TRSR); + ICHN_LP_SOURCE_DESCS[IchnIoTrap1].En[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_IO_TRAP_1); + ICHN_LP_SOURCE_DESCS[IchnIoTrap1].Sts[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_TRSR); + ICHN_LP_SOURCE_DESCS[IchnIoTrap0].En[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_IO_TRAP_0); + ICHN_LP_SOURCE_DESCS[IchnIoTrap0].Sts[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_TRSR); + } else if (PchSeries == PchH) { + ICHN_H_SOURCE_DESCS[IchnIoTrap3].En[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_IO_TRAP_3); + ICHN_H_SOURCE_DESCS[IchnIoTrap3].Sts[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_TRSR); + ICHN_H_SOURCE_DESCS[IchnIoTrap2].En[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_IO_TRAP_2); + ICHN_H_SOURCE_DESCS[IchnIoTrap2].Sts[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_TRSR); + ICHN_H_SOURCE_DESCS[IchnIoTrap1].En[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_IO_TRAP_1); + ICHN_H_SOURCE_DESCS[IchnIoTrap1].Sts[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_TRSR); + ICHN_H_SOURCE_DESCS[IchnIoTrap0].En[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_IO_TRAP_0); + ICHN_H_SOURCE_DESCS[IchnIoTrap0].Sts[0].Reg.Data.mem = (MEM_ADDR) (PCH_RCRB_BASE + R_PCH_RCRB_TRSR); + } +} diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c new file mode 100644 index 0000000..ee554f7 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c @@ -0,0 +1,519 @@ +/** @file + File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PchSmmHelpers.h" + +typedef enum { + PERIODIC_TIMER= 0, + SWSMI_TIMER, + NUM_TIMERS +} SUPPORTED_TIMER; + +typedef struct _TIMER_INTERVAL { + UINT64 Interval; + UINT8 AssociatedTimer; +} TIMER_INTERVAL; + +#define NUM_INTERVALS 8 + +// +// Time constants, in 100 nano-second units +// +#define TIME_64s 640000000 ///< 64 s +#define TIME_32s 320000000 ///< 32 s +#define TIME_16s 160000000 ///< 16 s +#define TIME_8s 80000000 ///< 8 s +#define TIME_64ms 640000 ///< 64 ms +#define TIME_32ms 320000 ///< 32 ms +#define TIME_16ms 160000 ///< 16 ms +#define TIME_1_5ms 15000 ///< 1.5 ms + +typedef enum { + INDEX_TIME_64s = 0, + INDEX_TIME_32s, + INDEX_TIME_16s, + INDEX_TIME_8s, + INDEX_TIME_64ms, + INDEX_TIME_32ms, + INDEX_TIME_16ms, + INDEX_TIME_1_5ms, + INDEX_TIME_MAX +} TIMER_INTERVAL_INDEX; + +static TIMER_INTERVAL mSmmPeriodicTimerIntervals[NUM_INTERVALS] = { + { + TIME_64s, + PERIODIC_TIMER + }, + { + TIME_32s, + PERIODIC_TIMER + }, + { + TIME_16s, + PERIODIC_TIMER + }, + { + TIME_8s, + PERIODIC_TIMER + }, + { + TIME_64ms, + SWSMI_TIMER + }, + { + TIME_32ms, + SWSMI_TIMER + }, + { + TIME_16ms, + SWSMI_TIMER + }, + { + TIME_1_5ms, + SWSMI_TIMER + }, +}; + +typedef struct _TIMER_INFO { + UINTN NumChildren; ///< number of children using this timer + UINT64 MinReqInterval; ///< minimum interval required by children + UINTN CurrentSetting; ///< interval this timer is set at right now (index into interval table) +} TIMER_INFO; + +TIMER_INFO mTimers[NUM_TIMERS]; + +PCH_SMM_SOURCE_DESC mTIMER_SOURCE_DESCS[NUM_TIMERS] = { + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_PERIODIC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_PERIODIC + } + } + }, + { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_SWSMI_TMR + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_SWSMI_TMR + } + } + } +}; + +VOID +PchSmmPeriodicTimerProgramTimers ( + VOID + ); + +/** + Convert the dispatch context to the timer interval, this function will assert if then either: + (1) The context contains an invalid interval + (2) The timer interval table is corrupt + + @param[in] DispatchContext The pointer to the Dispatch Context + + @retval TIMER_INTERVAL The timer interval of input dispatch context +**/ +TIMER_INTERVAL * +ContextToTimerInterval ( + IN PCH_SMM_CONTEXT *DispatchContext + ) +{ + UINTN loopvar; + + /// + /// Determine which timer this child is using + /// + for (loopvar = 0; loopvar < NUM_INTERVALS; loopvar++) { + if (((DispatchContext->PeriodicTimer.SmiTickInterval == 0) && + (DispatchContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) || + (DispatchContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)) { + return &mSmmPeriodicTimerIntervals[loopvar]; + } + } + /// + /// If this assertion fires, then either: + /// (1) the context contains an invalid interval + /// (2) the timer interval table is corrupt + /// + ASSERT (FALSE); + + return NULL; +} + +/** + Figure out which timer the child is requesting and + send back the source description + + @param[in] DispatchContext The pointer to the Dispatch Context instances + @param[out] SrcDesc The pointer to the source description + + @retval None +**/ +VOID +MapPeriodicTimerToSrcDesc ( + IN PCH_SMM_CONTEXT *DispatchContext, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + TIMER_INTERVAL *TimerInterval; + + /// + /// Figure out which timer the child is requesting and + /// send back the source description + /// + TimerInterval = ContextToTimerInterval (DispatchContext); + if (TimerInterval == NULL) { + return; + } + + CopyMem ( + (VOID *) SrcDesc, + (VOID *) (&mTIMER_SOURCE_DESCS[TimerInterval->AssociatedTimer]), + sizeof (PCH_SMM_SOURCE_DESC) + ); + + /// + /// Program the value of the interval into hardware + /// + PchSmmPeriodicTimerProgramTimers (); +} + +/** + Update the elapsed time from the Interval data of DATABASE_RECORD + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] HwContext The Context to be updated. + + @retval None +**/ +VOID +EFIAPI +PeriodicTimerGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *HwContext + ) +{ + TIMER_INTERVAL *TimerInterval; + + ASSERT (Record->ProtocolType == PeriodicTimerType); + + TimerInterval = ContextToTimerInterval (&Record->ChildContext); + if (TimerInterval == NULL) { + return; + } + /// + /// Ignore the hardware context. It's not required for this protocol. + /// Instead, just increment the child's context. + /// Update the elapsed time w/ the data from our tables + /// + Record->ChildContext.PeriodicTimer.ElapsedTime += TimerInterval->Interval; + *HwContext = Record->ChildContext; +} + +/** + Check whether Periodic Timer of two contexts match + + @param[in] Context1 Context 1 that includes Periodic Timer 1 + @param[in] Context2 Context 2 that includes Periodic Timer 2 + + @retval FALSE Periodic Timer match + @retval TRUE Periodic Timer don't match +**/ +BOOLEAN +EFIAPI +PeriodicTimerCmpContext ( + IN PCH_SMM_CONTEXT *HwContext, + IN PCH_SMM_CONTEXT *ChildContext + ) +{ + + if (ChildContext->PeriodicTimer.ElapsedTime >= ChildContext->PeriodicTimer.Period) { + /// + /// This child should be dispatched + /// Need reset ElapsedTime, or SMI handler will be invoked during SmiTickInterval instead of Period. + /// + ChildContext->PeriodicTimer.ElapsedTime = 0; + return TRUE; + } else { + return FALSE; + } +} + +/** + Program Smm Periodic Timer + + @param[in] None + + @retval None +**/ +VOID +PchSmmPeriodicTimerProgramTimers ( + VOID + ) +{ + UINT16 GenPmCon1; + UINT8 GenPmCon3; + SUPPORTED_TIMER Timer; + DATABASE_RECORD *RecordInDb; + LIST_ENTRY *LinkInDb; + UINTN PciD31F0RegBase; + TIMER_INTERVAL *TimerInterval; + + PciD31F0RegBase = MmPciAddress ( + 0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + 0 + ); + /// + /// Find the minimum required interval for each timer + /// + for (Timer = 0; Timer < NUM_TIMERS; Timer++) { + mTimers[Timer].MinReqInterval = ~ (UINT64) 0x0; + mTimers[Timer].NumChildren = 0; + } + + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase); + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb); + if (RecordInDb->ProtocolType == PeriodicTimerType) { + /// + /// This child is registerd with the PeriodicTimer protocol + /// + TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext); + if (TimerInterval == NULL) { + return; + } + + Timer = TimerInterval->AssociatedTimer; + if (Timer < 0 || Timer >= NUM_TIMERS) { + ASSERT (FALSE); + EFI_DEADLOOP (); + } + + if (mTimers[Timer].MinReqInterval > RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval) { + mTimers[Timer].MinReqInterval = RecordInDb->ChildContext.PeriodicTimer.SmiTickInterval; + } + + mTimers[Timer].NumChildren++; + } + + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, &RecordInDb->Link); + } + /// + /// Program the hardware + /// + if (mTimers[PERIODIC_TIMER].NumChildren > 0) { + GenPmCon1 = MmioRead16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1); + + GenPmCon1 &= ~B_PCH_LPC_GEN_PMCON_PER_SMI_SEL; + switch (mTimers[PERIODIC_TIMER].MinReqInterval) { + case TIME_64s: + GenPmCon1 |= V_PCH_LPC_GEN_PMCON_PER_SMI_64S; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s; + break; + + case TIME_32s: + GenPmCon1 |= V_PCH_LPC_GEN_PMCON_PER_SMI_32S; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s; + break; + + case TIME_16s: + GenPmCon1 |= V_PCH_LPC_GEN_PMCON_PER_SMI_16S; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s; + break; + + case TIME_8s: + GenPmCon1 |= V_PCH_LPC_GEN_PMCON_PER_SMI_8S; + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s; + break; + + default: + ASSERT (FALSE); + break; + } + + MmioWrite16 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_1, GenPmCon1); + + /// + /// Restart the timer here, just need to clear the SMI + /// + PchSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]); + } else { + PchSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]); + } + + if (mTimers[SWSMI_TIMER].NumChildren > 0) { + /// + /// ICH9, ICH10 and PCH share the same bit positions for SW SMI Rate settings + /// + GenPmCon3 = MmioRead8 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_3); + GenPmCon3 &= ~B_PCH_LPC_GEN_PMCON_SWSMI_RTSL; + switch (mTimers[SWSMI_TIMER].MinReqInterval) { + case TIME_64ms: + GenPmCon3 |= V_PCH_LPC_GEN_PMCON_SWSMI_RTSL_64MS; + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_64ms; + break; + + case TIME_32ms: + GenPmCon3 |= V_PCH_LPC_GEN_PMCON_SWSMI_RTSL_32MS; + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_32ms; + break; + + case TIME_16ms: + GenPmCon3 |= V_PCH_LPC_GEN_PMCON_SWSMI_RTSL_16MS; + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_16ms; + break; + + case TIME_1_5ms: + GenPmCon3 |= V_PCH_LPC_GEN_PMCON_SWSMI_RTSL_1_5MS; + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_1_5ms; + break; + + default: + ASSERT (FALSE); + break; + } + /// + /// SWSMI_RATE_SEL BIT (D31:F0:A4h[7:6]) bits are in RTC well + /// + MmioWrite8 (PciD31F0RegBase + R_PCH_LPC_GEN_PMCON_3, GenPmCon3); + + /// + /// Restart the timer here, need to disable, clear, then enable to restart this timer + /// + PchSmmDisableSource (&mTIMER_SOURCE_DESCS[SWSMI_TIMER]); + PchSmmClearSource (&mTIMER_SOURCE_DESCS[SWSMI_TIMER]); + PchSmmEnableSource (&mTIMER_SOURCE_DESCS[SWSMI_TIMER]); + } else { + PchSmmDisableSource (&mTIMER_SOURCE_DESCS[SWSMI_TIMER]); + } +} + +/** + This services returns the next SMI tick period that is supported by the chipset. + The order returned is from longest to shortest interval period. + + @param[in] This Pointer to the EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL instance. + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI interval period that is supported by the child. + + @retval EFI_SUCCESS The service returned successfully. + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is invalid. +**/ +EFI_STATUS +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( + IN EFI_SMM_PERIODIC_TIMER_DISPATCH_PROTOCOL *This, + IN OUT UINT64 **SmiTickInterval + ) +{ + TIMER_INTERVAL *IntervalPointer; + + ASSERT (SmiTickInterval != NULL); + + IntervalPointer = (TIMER_INTERVAL *) *SmiTickInterval; + + if (IntervalPointer == NULL) { + /// + /// The first time child requesting an interval + /// + IntervalPointer = &mSmmPeriodicTimerIntervals[0]; + } else if (IntervalPointer == &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) { + /// + /// At end of the list + /// + IntervalPointer = NULL; + } else { + if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) && + (IntervalPointer < &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) + ) { + /// + /// Get the next interval in the list + /// + IntervalPointer++; + } else { + /// + /// Input is out of range + /// + return EFI_INVALID_PARAMETER; + } + } + + if (IntervalPointer != NULL) { + *SmiTickInterval = &IntervalPointer->Interval; + } else { + *SmiTickInterval = NULL; + } + + return EFI_SUCCESS; +} + +/** + This function is responsible for calculating and enabling any timers that are required + to dispatch messages to children. The SrcDesc argument isn't acutally used. + + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC instance. + + @retval None. +**/ +VOID +EFIAPI +PchSmmPeriodicTimerClearSource ( + IN PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PchSmmPeriodicTimerProgramTimers (); +} diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmPowerButton.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmPowerButton.c new file mode 100644 index 0000000..e172808 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmPowerButton.c @@ -0,0 +1,104 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Power Button dispatch protocol. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#include "Token.h" +#include "PchSmmHelpers.h" + +const PCH_SMM_SOURCE_DESC POWER_BUTTON_SOURCE_DESC = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_PM1_EN + }, + S_PCH_ACPI_PM1_EN, + N_PCH_ACPI_PM1_EN_PWRBTN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_ACPI_PM1_STS + }, + S_PCH_ACPI_PM1_STS, + N_PCH_ACPI_PM1_STS_PWRBTN + } + } +}; + +/** + Get the power button status. + + @param[in] Record The pointer to the DATABASE_RECORD. + @param[out] Context Calling context from the hardware, will be updated with the current power button status. + + @retval None +**/ +VOID +EFIAPI +PowerButtonGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ) +{ + UINT16 GenPmCon1; + + GenPmCon1 = MmioRead16 ( + MmPciAddress (0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_GEN_PMCON_1) + ); + + if ((GenPmCon1 & B_PCH_LPC_GEN_PMCON_PWRBTN_LVL) != 0) { + Context->PowerButton.Phase = PowerButtonExit; + } else { + Context->PowerButton.Phase = PowerButtonEntry; + } + +// AMI_OVERRIDE, EIP145008, forced PowerButton.Phase as PowerButtonEntry.>>> +#if defined FORCE_PWB_PHASE_AS_ENTRY && FORCE_PWB_PHASE_AS_ENTRY == 1 + Context->PowerButton.Phase = PowerButtonEntry; +#endif +// AMI_OVERRIDE, EIP145008, forced PowerButton.Phase as PowerButtonEntry.<<< +} + +/** + Check whether Power Button status of two contexts match + + @param[in] Context1 Context 1 that includes Power Button status 1 + @param[in] Context2 Context 2 that includes Power Button status 2 + + @retval FALSE Power Button status match + @retval TRUE Power Button status don't match +**/ +BOOLEAN +EFIAPI +PowerButtonCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ) +{ + return (BOOLEAN) (Context1->PowerButton.Phase == Context2->PowerButton.Phase); +} diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmSw.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmSw.c new file mode 100644 index 0000000..9a20df3 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmSw.c @@ -0,0 +1,87 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Sw dispatch protocol. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#include "PchSmmHelpers.h" + +const PCH_SMM_SOURCE_DESC SW_SOURCE_DESC = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_APMC + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_APM + } + } +}; + +/** + Get the Software Smi value + + @param[in] Record No use + @param[out] Context The context that includes Software Smi value to be filled + + @retval None +**/ +VOID +EFIAPI +SwGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ) +{ + UINT8 ApmCnt; + + ApmCnt = IoRead8 ((UINTN) R_PCH_APM_CNT); + + Context->Sw.SwSmiInputValue = ApmCnt; +} + +/** + Check whether software SMI value of two contexts match + + @param[in] Context1 Context 1 that includes software SMI value 1 + @param[in] Context2 Context 2 that includes software SMI value 2 + + @retval FALSE Software SMI value match + @retval TRUE Software SMI value don't match +**/ +BOOLEAN +EFIAPI +SwCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ) +{ + return (BOOLEAN) (Context1->Sw.SwSmiInputValue == Context2->Sw.SwSmiInputValue); +} diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmSx.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmSx.c new file mode 100644 index 0000000..3f7e3e2 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmSx.c @@ -0,0 +1,975 @@ +/** @file + File to contain all the hardware specific stuff for the Smm Sx dispatch protocol. + +@copyright + Copyright (c) 1999 - 2013 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PchSmmHelpers.h" + +extern EFI_PHYSICAL_ADDRESS mResvMmioBaseAddr; +/// +/// Maximum loop time for GbE status check +/// +#define GBE_MAX_LOOP_TIME 4000 + +const PCH_SMM_SOURCE_DESC SX_SOURCE_DESC = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_ON_SLP_EN + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_ON_SLP_EN + } + } +}; + +/** + Get the Sleep type + + @param[in] Record No use + @param[out] Context The context that includes SLP_TYP bits to be filled + + @retval None +**/ +VOID +EFIAPI +SxGetContext ( + IN DATABASE_RECORD *Record, + OUT PCH_SMM_CONTEXT *Context + ) +{ + UINT32 Pm1Cnt; + + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT)); + + /// + /// By design, the context phase will always be ENTRY + /// + Context->Sx.Phase = SxEntry; + + /// + /// Map the PM1_CNT register's SLP_TYP bits to the context type + /// + switch (Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) { + case V_PCH_ACPI_PM1_CNT_S0: + Context->Sx.Type = SxS0; + break; + + case V_PCH_ACPI_PM1_CNT_S1: + Context->Sx.Type = SxS1; + break; + + case V_PCH_ACPI_PM1_CNT_S3: + Context->Sx.Type = SxS3; + break; + + case V_PCH_ACPI_PM1_CNT_S4: + Context->Sx.Type = SxS4; + break; + + case V_PCH_ACPI_PM1_CNT_S5: + Context->Sx.Type = SxS5; + break; + + default: + ASSERT (FALSE); + break; + } +} + +/** + Check whether sleep type of two contexts match + + @param[in] Context1 Context 1 that includes sleep type 1 + @param[in] Context2 Context 2 that includes sleep type 2 + + @retval FALSE Sleep types match + @retval TRUE Sleep types don't match +**/ +BOOLEAN +EFIAPI +SxCmpContext ( + IN PCH_SMM_CONTEXT *Context1, + IN PCH_SMM_CONTEXT *Context2 + ) +{ + return (BOOLEAN) (Context1->Sx.Type == Context2->Sx.Type); +} + +/** + Check ready flag to see if writing to MDIC is done. + + @param[in] GbEBar GbE Memory Base Address Register + + @retval EFI_SUCCESS Successfully completed. + @retval EFI_TIMEOUT Checking flag time out. +**/ +EFI_STATUS +CheckReadyFlag ( + UINT32 GbEBar + ) +{ + UINT32 ReadyFlag; + UINT32 LoopTime; + + ReadyFlag = 0; + + for (LoopTime = 0; LoopTime < GBE_MAX_LOOP_TIME; LoopTime++) { + ReadyFlag = MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR3) & B_PCH_MBARA_GBECSR3_RB; + + if (ReadyFlag) { + break; + } + + PchPmTimerStall (10); + } + + if (LoopTime >= GBE_MAX_LOOP_TIME) { + return EFI_TIMEOUT; + } + + return EFI_SUCCESS; +} + +/** + PCH BIOS Spec Rev 0.5.0 Section 10.5 + Additional Internal GbE Controller special cases WOL Support + + @param[in] None + + @retval None +**/ +VOID +GbES02SxWorkaround ( + VOID + ) +{ + UINTN PciD25F0RegBase; + UINTN PciD31F0RegBase; + UINT32 GbEBar; + UINT32 GbEBarB; + UINT16 CmdReg; + UINT32 RAL0; + UINT32 RAH0; + UINT32 PhyCtrl; + UINT32 ExtCnfCtrl; + UINT32 Buffer; + UINT32 LoopTime; + UINT32 RootComplexBar; + UINT32 PchGpioBase; + EFI_STATUS Status; + + PciD25F0RegBase = MmPciAddress ( + 0, + PCI_BUS_NUMBER_PCH_LAN, + PCI_DEVICE_NUMBER_PCH_LAN, + PCI_FUNCTION_NUMBER_PCH_LAN, + 0 + ); + PciD31F0RegBase = MmPciAddress ( + 0, + 0, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + 0 + ); + RootComplexBar = PCH_RCRB_BASE; + PchGpioBase = (MmioRead32 (PciD31F0RegBase + R_PCH_LPC_GPIO_BASE)) &~BIT0; + GbEBar = 0; + GbEBarB = 0; + CmdReg = 0; + Buffer = 0; + + if (((MmioRead16 (RootComplexBar + R_PCH_RCRB_BUC)) & BIT5) == 0) { + /// + /// System BIOS requires to program the registers listed below for internal GbE to function upon S0 to S3,4,5 transition + /// (When ME off and GbE device in D0) + /// + /// Note: Time out should be applied for MBARA + Offset 20h[28] verification to avoid non respond loop. Upon time out, + /// system BIOS is required to clear MBARA + Offset F00h [5] = 0b before exiting the WA. + /// + /// Check if GbE device is in D0 state + /// + if ((MmioRead16 (PciD25F0RegBase + R_PCH_LAN_PMCS) & (UINT16) B_PCH_LAN_PMCS_PS) == (UINT16) V_PCH_LAN_PMCS_PS0) { + GbEBar = MmioRead32 (PciD25F0RegBase + R_PCH_LAN_MEM_BASE_A); + /// + /// Step 1 + /// If MBARA + Offset 5800h [0] = 1b then proceed the steps below + /// + if (MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR9) & B_PCH_MBARA_GBECSR9_APME) { + /// + /// Step 2 + /// System BIOS perform read to MBARA + Offset 5400h [31:0], MBARA + Offset 5404h [31:0] + /// and MBARA + Offset F00h [31:0] + /// + RAL0 = MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR7); + RAH0 = MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR8); + ExtCnfCtrl = MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR5); + /// + /// Step 3 + /// Ensure that MBARA + Offset F00h [5] = 1b + /// a. Set MBARA + Offset F00h [31:0] value with the value read in step 2 or with 0x20 (set bit 5) + /// b. Read MBARA + Offset F00h + /// c. If MBARA + Offset F00h [5] = 1b (true) continue else wait X Sec and go back to step 3.b for Y times + /// (X*Y totals to ~200mSec) if false - exit flow by jumping to step 32. + /// + MmioWrite32 (GbEBar + R_PCH_MBARA_GBECSR5, ExtCnfCtrl | B_PCH_MBARA_GBECSR5_SWFLAG); + + for (LoopTime = 0; LoopTime < GBE_MAX_LOOP_TIME; LoopTime++) { + ExtCnfCtrl = MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR5); + + if (ExtCnfCtrl & B_PCH_MBARA_GBECSR5_SWFLAG) { + break; + } + + PchPmTimerStall (50); + } + + if (LoopTime >= GBE_MAX_LOOP_TIME) { + goto ExitGbEWa; + } + /// + /// Step 4 + /// If MBARA + Offset 5B54h [15] = 1b then jump to Step 10 + /// + if ((MmioRead32 (GbEBar + 0x5B54) & BIT15) != BIT15) { + /// + /// Step 5 + /// If MBARA + Offset F10h [2] = 1b, then set MBARA + Offset F10h[1] = 1b. Else clear MBARA + Offset F10h[1] = 0b + /// + if (MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR6) & B_PCH_MBARA_GBECSR6_LPLUND) { + MmioOr32 (GbEBar + R_PCH_MBARA_GBECSR6, (UINT32) B_PCH_MBARA_GBECSR6_LPLUD); + } else { + MmioAnd32 (GbEBar + R_PCH_MBARA_GBECSR6, (UINT32)~B_PCH_MBARA_GBECSR6_LPLUD); + } + /// + /// Step 6 + /// Set MBARA + Offset 20h = 0x043f0000. Verify MBARA + Offset 20h[28] = 1b + /// + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x043f0000); + + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + /// + /// Step 7 + /// Wait 4 mSec + /// + PchPmTimerStall (4 * 1000); + /// + /// Step 8 + /// Set MBARA + Offset 20h = 0x04390000 or with 0x400 or with 0x40 if MBARA + Offset F10h [3] = 1b + /// or with 0x04 if MBARA + Offset F10h [2] = 1b + /// + Buffer = 0x04390000 | 0x400; + if (MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR6) & B_PCH_MBARA_GBECSR6_GbE_DIS) { + Buffer |= 0x40; + } + + if (MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR6) & B_PCH_MBARA_GBECSR6_LPLUND) { + Buffer |= 0x04; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), Buffer); + /// + /// Step 9 + /// Verify MBARA + Offset 20h[28] = 1b + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + } + /// + /// Step 10 + /// Set MBARA + Offset 20h = 0x043f6400 + /// + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x043f6400); + /// + /// Step 11 + /// Wait 4 mSec + /// + PchPmTimerStall (4 * 1000); + /// + /// Step 12 + /// Set MBARA + Offset F10h [6] = 1b (read modify write) + /// + PhyCtrl = MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR6); + MmioWrite32 (GbEBar + R_PCH_MBARA_GBECSR6, PhyCtrl | B_PCH_MBARA_GBECSR6_GGD); + /// + /// Step 13 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4310010 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x4310010); + /// + /// Step 14 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4320000 or with + /// the least significant word of MBARA + offset 5400 that read in step 2 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), (0x4320000 | (RAL0 & 0x0000FFFF))); + /// + /// Step 15 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4310011 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x4310011); + /// + /// Step 16 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4320000 or with + /// the most significant word of MBARA + offset 5400 that read in step 2 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), (0x4320000 | (RAL0 >> 16))); + /// + /// Step 17 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4310012 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x4310012); + /// + /// Step 18 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4320000 or with + /// the least significant word of MBARA + offset 5404 that read in step 2 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), (0x4320000 | (RAH0 & B_PCH_MBARA_GBECSR8_RAH))); + /// + /// Step 19 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4310013 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x4310013); + /// + /// Step 20 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4328000 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x4328000); + /// + /// Step 21 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4310001 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x4310001); + /// + /// Step 22 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x8320000 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x8320000); + /// + /// Step 23 + /// Verify MBARA + Offset 20h[28] = 1b, TEMP[15:0] = MBARA + Offset 20h [15:0] + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + Buffer = MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR3) & B_PCH_MBARA_GBECSR3_DATA; + /// + /// Step 24 + /// Set MBARA + Offset 20h = 0x4320000 or TEMP[15:0] or 0x0001 + /// + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x4320000 | Buffer | 0x0001); + /// + /// Step 25 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x43f6460 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x43f6460); + /// + /// Step 26 + /// Wait 4 mSec + /// + PchPmTimerStall (4 * 1000); + /// + /// Step 27 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x4310042 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x4310042); + /// + /// Step 28 + /// Verify MBARA + Offset 20h[28] = 1b. + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x43F6020); + + /// + /// Step 29 + /// Wait 4 mSec + /// + PchPmTimerStall (4 * 1000); + + /// + /// Step 30 + /// Verify MBARA + Offset 20h[28] = 1b, set MBARA + Offset 20h = 0x8310000 + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x8310000); + /// + /// Step 31 + /// Verify MBARA + Offset 20h[28] = 1b, TEMP[15:0] = MBARA + 20[15:0] + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + + Buffer = MmioRead32 (GbEBar + R_PCH_MBARA_GBECSR3) & 0x0000FFFF; + + /// + /// Step 32 + /// Verify MBARA + 20h[28] = 1b, set MBARA + 20h = 4310000h or with the TEMP[15:0] or with 10h + /// + Status = CheckReadyFlag (GbEBar); + if (EFI_ERROR (Status)) { + goto ExitGbEWa; + } + +ExitGbEWa: + + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR3), 0x4310000 | Buffer | 0x10); + /// + /// Step 33 + /// Verify MBARA + Offset 20h[28] = 1b + /// + Status = CheckReadyFlag (GbEBar); + + /// + /// Step 34 + /// Clear MBARA + Offset F00h [5] = 0b (read modify write) + /// + MmioWrite32 ((GbEBar + R_PCH_MBARA_GBECSR5), (ExtCnfCtrl & (UINT32) (~BIT5))); + + } + } + } +} + +typedef struct { + UINT8 Device; + UINT8 Function; +} USB_CONTROLLER; + +/** + PCH BIOS Spec Rev 0.5.0, Section 12.10.1 + Additional Programming Requirements prior to enter + S4/S5 + + @param[in] None + + @retval None +**/ +VOID +UsbS02SxWorkaround ( + VOID + ) +{ + UINT8 Index; + UINTN EhciPciRegBase; + UINT32 UsbBar; + UINT16 CmdReg; + UINT16 PowerState; + USB_CONTROLLER EhciControllersMap[PchEhciControllerMax] = { + { + PCI_DEVICE_NUMBER_PCH_USB, + PCI_FUNCTION_NUMBER_PCH_EHCI + }, + { + PCI_DEVICE_NUMBER_PCH_USB_EXT, + PCI_FUNCTION_NUMBER_PCH_EHCI2 + } + }; + + /// + /// System BIOS must execute the following steps prior to enter S4/S5. + /// + for (Index = 0; Index < GetPchEhciMaxControllerNum (); Index++) { + /// + /// Step 1 + /// Read "Memory Base Address (MEM_BASE) Register" of D26/D29:F0 + /// + EhciPciRegBase = MmPciAddress (0, 0, EhciControllersMap[Index].Device, EhciControllersMap[Index].Function, 0); + UsbBar = MmioRead32 (EhciPciRegBase + R_PCH_EHCI_MEM_BASE); + CmdReg = MmioRead16 (EhciPciRegBase + R_PCH_EHCI_COMMAND_REGISTER); + PowerState = MmioRead16 (EhciPciRegBase + R_PCH_EHCI_PWR_CNTL_STS); + + if (UsbBar != 0xFFFFFFFF) { + /// + /// Check if the Ehci device is in D3 power state + /// + if ((PowerState & B_PCH_EHCI_PWR_CNTL_STS_PWR_STS) == V_PCH_EHCI_PWR_CNTL_STS_PWR_STS_D3) { + /// + /// Step 2 + /// Set "Power State" bit of PWR_CNTL_STS register, D26/D29:F0:54h [1:0] = 0h + /// + MmioWrite16 (EhciPciRegBase + R_PCH_EHCI_PWR_CNTL_STS, (PowerState &~B_PCH_EHCI_PWR_CNTL_STS_PWR_STS)); + /// + /// Step 3 + /// Write back the value from step 1 to the "Memory Base Address (MEM_BASE) Register" of D26/D29:F0 + /// + MmioWrite32 (EhciPciRegBase + R_PCH_EHCI_MEM_BASE, UsbBar); + /// + /// Step 4 + /// Enable "Memory Space Enable (MSE)" bit, set D26/D29:F0:04h [1] = 1b. + /// + MmioOr16 ( + EhciPciRegBase + R_PCH_EHCI_COMMAND_REGISTER, + (UINT16) (B_PCH_EHCI_COMMAND_MSE) + ); + } + /// + /// Step 5 + /// Clear "Asynchronous Schedule Enable" and "Periodic Schedule Enable" bits, if "Run/Stop (RS)" bit, MEM_BASE + offset 20h [0] = 1b. + /// Proceed to steps below if "Run/Stop (RS)" bit, MEM_BASE + offset 20h [0] = 0b. + /// + if (!(MmioRead32 (UsbBar + R_PCH_EHCI_USB2CMD) & B_PCH_EHCI_USB2CMD_RS)) { + MmioAnd32 (UsbBar + R_PCH_EHCI_USB2CMD, (UINT32)~(B_PCH_EHCI_USB2CMD_ASE | B_PCH_EHCI_USB2CMD_PSE)); + MmioOr32 (UsbBar + R_PCH_EHCI_USB2CMD, B_PCH_EHCI_USB2CMD_RS); + } + /// + /// Step 6 + /// If "Port Enabled/Disabled" bit of Port N Status and Control (PORTSC) Register is set, MEM_BASE + 64h [2] = 1b, + /// proceed steps below else continue with S4/S5. + /// + if ((MmioRead32 (UsbBar + R_PCH_EHCI_PORTSC0) & R_PCH_EHCI_PORTSC0_PORT_EN_DIS)) { + /// + /// Step 7 + /// Ensure that "Suspend" bit of Port N Status and Control (PORTSC) Register is set, MEM_BASE + 64h [7] = 1b. + /// + if (!(MmioRead32 (UsbBar + R_PCH_EHCI_PORTSC0) & R_PCH_EHCI_PORTSC0_SUSPEND)) { + MmioOr32 (UsbBar + R_PCH_EHCI_PORTSC0, R_PCH_EHCI_PORTSC0_SUSPEND); + } + /// + /// Step 8 + /// Set delay of 25ms + /// + PchPmTimerStall (25 * 1000); + /// + /// Step 9 + /// Clear "Run/Stop (RS)" bit, MEM_BASE + offset 20h [0] = 0b. + /// + MmioAnd32 (UsbBar + R_PCH_EHCI_USB2CMD, (UINT32)~(B_PCH_EHCI_USB2CMD_RS)); + } + /// + /// If the EHCI device is in D3 power state before executing this WA + /// + if ((PowerState & B_PCH_EHCI_PWR_CNTL_STS_PWR_STS) == V_PCH_EHCI_PWR_CNTL_STS_PWR_STS_D3) { + /// + /// Restore PCI Command Register + /// + MmioWrite16 (EhciPciRegBase + R_PCH_EHCI_COMMAND_REGISTER, CmdReg); + /// + /// Set "Power State" bit of PWR_CNTL_STS register to D3 state, D26/D29:F0:54h [1:0] = 3h + /// + MmioWrite16 (EhciPciRegBase + R_PCH_EHCI_PWR_CNTL_STS, PowerState); + } + /// + /// Step 10 + /// Continue with S4/S5 + /// + } + } +} + +/** + Additional xHCI Controller Configurations Prior to Entering S3/S4/S5 + + @param[in] None + + @retval None +**/ +VOID +XhciSxWorkaround ( + VOID + ) +{ + UINT32 RootComplexBar; + UINTN XhciPciMmBase; + UINT8 OrgCmdByte; + UINT32 OrgMmioAddr; + UINT32 OrgMmioHAddr; + UINT8 OrgPwrSts; + PCH_SERIES PchSeries; + UINT32 XhciMmioBase; + UINT32 PortScOffset[4]; + UINT32 Data32; + UINT32 Index; + UINT32 ResetMask; + + PchSeries = GetPchSeries(); + + RootComplexBar = PCH_RCRB_BASE; + /// + /// Check if XHCI controller is enabled + /// + if ((MmioRead32 (RootComplexBar + R_PCH_RCRB_FUNC_DIS) & (UINT32) B_PCH_RCRB_FUNC_DIS_XHCI) != 0) { + return; + } + XhciPciMmBase = MmPciAddress ( + 0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_XHCI, + PCI_FUNCTION_NUMBER_PCH_XHCI, + 0 + ); + + // + // Save Cmd and XhciBar and PwrSts registers + // + OrgCmdByte = MmioRead8 (XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER); + OrgMmioAddr = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE) & 0xFFFF0000; + OrgMmioHAddr = MmioRead32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE + 4); + OrgPwrSts = MmioRead8 (XhciPciMmBase + R_PCH_XHCI_PWR_CNTL_STS); + // + // Bring device back to D0 + // + MmioAnd8 (XhciPciMmBase + R_PCH_XHCI_PWR_CNTL_STS, (UINT8)~(B_PCH_XHCI_PWR_CNTL_STS_PWR_STS)); + // + // Use the reserved MMIO + // Clear MSE before changing MMIO address + // + MmioAnd8 (XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER, (UINT8)~(B_PCH_XHCI_COMMAND_BME | B_PCH_XHCI_COMMAND_MSE)); + MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE, (UINT32)mResvMmioBaseAddr); + MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE + 4, 0); + XhciMmioBase = (UINT32)mResvMmioBaseAddr; + // + // Set MSE + // + MmioOr8 (XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER, (B_PCH_XHCI_COMMAND_BME | B_PCH_XHCI_COMMAND_MSE)); + + // + // XHC W/A for LPT-LP + // Clear PCI CFG offset 0xB0[14:13] for LPT-LP + // Clear MMIO Offset 0x816C[14] + // Clear MMIO Offset 0x816C[2] + // Wait until all SS ports are out of polling + // For each SS port which is disconnected (i.e. PORTS.PLS=5h) and CSC=0 + // Issue Warm Port Reset + // Wait 101ms + // Write '1' to all Port Change Status bits if reset + // Set MMIO Offset 0x80E0[15] + // + // For PCH H and LP + // Clear MMIO Offset 0x8154[31] + // + if (PchSeries == PchLp) { + // + // Clear PCI CFG offset 0xB0[14:13] for LPT-LP + // + MmioAnd32 (XhciPciMmBase + 0xB0, (UINT32)~(BIT14 | BIT13)); + // + // Clear MMIO Offset 0x816C[14] + // Clear MMIO Offset 0x816C[2] + // + MmioAnd32 (XhciMmioBase + 0x816C, (UINT32)~(BIT14 | BIT2)); + + PortScOffset[0] = R_PCH_LP_XHCI_PORTSC1USB3; + PortScOffset[1] = R_PCH_LP_XHCI_PORTSC2USB3; + PortScOffset[2] = R_PCH_LP_XHCI_PORTSC3USB3; + PortScOffset[3] = R_PCH_LP_XHCI_PORTSC4USB3; + // + // Wait until all ports are out of polling (PP=1, PLS=7) + // + for (Index = 0; Index < 4; Index++) { + Data32 = MmioRead32 (XhciMmioBase + PortScOffset[Index]); + // + // Check if PLS = 7, and PP = 1 + // + while ((Data32 & B_PCH_XHCI_PORTSCXUSB3_PLS) == V_PCH_XHCI_PORTSCXUSB3_PLS_POLLING) + { + PchPmTimerStall (10); + Data32 = MmioRead32 (XhciMmioBase + PortScOffset[Index]); + } + } + ResetMask = 0; + for (Index = 0; Index < 4; Index++) { + Data32 = MmioRead32 (XhciMmioBase + PortScOffset[Index]); + // + // If Port X is Disconnected (i.e. PORTS.PLS=5h) AND PORTSC{X}.CSC=0 + // Check if PLS = 5, CSC = 0, and PP = 1 + // + if (((Data32 & B_PCH_XHCI_PORTSCXUSB3_PLS) == V_PCH_XHCI_PORTSCXUSB3_PLS_RXDETECT) && + ((Data32 & B_PCH_XHCI_PORTSCXUSB3_CSC) == 0)) + { + // + // Issue Warm Port Reset + // + ResetMask |= (1 << Index); + Data32 &= (UINT32)~(B_PCH_XHCI_PORTSCXUSB3_PED); + Data32 |= B_PCH_XHCI_PORTSCXUSB3_WPR; + MmioWrite32 (XhciMmioBase + PortScOffset[Index], Data32); + } + } + + if (ResetMask != 0) { + // + // Wait 101ms to ensure reset completed + // + PchPmTimerStall (101 * 1000); + + for (Index = 0; Index < 4; ++Index) { + if (ResetMask & (1 << Index)) { + Data32 = MmioRead32 (XhciMmioBase + PortScOffset[Index]); + Data32 &= (UINT32)~(B_PCH_XHCI_PORTSCXUSB3_PED); + // + // Write '1' to All Port Change Status + // + Data32 |= (B_PCH_XHCI_PORTSCXUSB3_CEC | + B_PCH_XHCI_PORTSCXUSB3_PLC | + B_PCH_XHCI_PORTSCXUSB3_PRC | + B_PCH_XHCI_PORTSCXUSB3_OCC | + B_PCH_XHCI_PORTSCXUSB3_WRC | + B_PCH_XHCI_PORTSCXUSB3_PEC | + B_PCH_XHCI_PORTSCXUSB3_CSC); + MmioWrite32 (XhciMmioBase + PortScOffset[Index], Data32); + } + } + } + + // + // Set MMIO Offset 0x80E0[15] + // + MmioOr32 (XhciMmioBase + 0x80E0, BIT15); + } + // + // Clear MMIO Offset 0x8154[31] + // + MmioAnd32 (XhciMmioBase + 0x8154, (UINT32)~BIT31); + + // + // Restore Cmd and XhciBar and PwrSts registers + // + MmioAnd8 (XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER, (UINT8)~(B_PCH_XHCI_COMMAND_BME | B_PCH_XHCI_COMMAND_MSE)); + MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE + 4, OrgMmioHAddr); + MmioWrite32 (XhciPciMmBase + R_PCH_XHCI_MEM_BASE, OrgMmioAddr); + MmioWrite8 (XhciPciMmBase + R_PCH_XHCI_COMMAND_REGISTER, OrgCmdByte); + + /// + /// Set D3hot state - 11b + /// + MmioOr16 ((XhciPciMmBase + R_PCH_XHCI_PWR_CNTL_STS), (UINT16) 0x3); + + /// + /// Set "PME Enable" bit of PWR_CNTL_STS register, D20:F0:74h[8] = 1h + /// + MmioOr16 ((XhciPciMmBase + R_PCH_XHCI_PWR_CNTL_STS), (UINT16) (B_PCH_XHCI_PWR_CNTL_STS_PME_EN)); + +} + +/** + When we get an SMI that indicates that we are transitioning to a sleep state, + we need to actually transition to that state. We do this by disabling the + "SMI on sleep enable" feature, which generates an SMI when the operating system + tries to put the system to sleep, and then physically putting the system to sleep. + + @param[in] None + + @retval None. +**/ +VOID +PchSmmSxGoToSleep ( + VOID + ) +{ + UINT32 Pm1Cnt; + UINT32 RootComplexBar; + PCH_SERIES PchSeries; + + PchSeries = GetPchSeries(); + RootComplexBar = PCH_RCRB_BASE; + + /// + /// Flush cache into memory before we go to sleep. It is necessary for S3 sleep + /// because we may update memory in SMM Sx sleep handlers -- the updates are in cache now + /// + AsmWbinvd (); + + /// + /// Disable SMIs + /// + PchSmmClearSource (&SX_SOURCE_DESC); + PchSmmDisableSource (&SX_SOURCE_DESC); + + /// + /// Get Power Management 1 Control Register Value + /// + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT)); + + /// + /// PCH BIOS Spec Rev 0.5.0, Section 12.10.1 + /// Additional Programming Requirements prior to enter S4/S5 + /// + if (((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S4) || + ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S5)) { + UsbS02SxWorkaround (); + } + + if (((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) || + ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S4) || + ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S5)) { + XhciSxWorkaround (); + /// + /// PCH BIOS Spec Rev 0.5.0 Section 10.6 + /// Additional Internal GbE Controller special cases WOL Support + /// + GbES02SxWorkaround (); + /// + /// PCH BIOS Spec Rev 0.5.0 Section 10.6 Additional GbE based wake events + /// The GPIO[27] is used as a wake pin when the GbE controller is enabled. + /// The System BIOS should enable this as wake event by setting the GPIO[27] + /// Enable bit (GP27_EN PMBASE + 2Ch[3]). Unlike other wake events the System + /// BIOS does not need to clear the corresponding GPIO[27] Status bit + /// (GP27_STS PMBASE + 24h[3]) as the bit will be cleared by the hardware. + /// + /// RCBA + 0x3334 [0] will be 1b while PchDeepSx is enabled and GP27 is + /// reuqired to wake up the system from PchDeepSx. + /// + if ((MmioRead32 (RootComplexBar + 0x3334) & (UINT32) BIT0) != 0) { + if (PchSeries == PchLp) { + IoOr32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_GPE0_EN_127_96), (UINT32) B_PCH_ACPI_GPE0_EN_127_96_GP27); + } else if (PchSeries == PchH) { + IoOr32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_GPE0b_EN), (UINT32) B_PCH_ACPI_GPE0b_EN_GP27); + } + } + } + + /// + /// Record S3 suspend performance data + /// + if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S3) { + /// + /// Report status code before goto S3 sleep + /// + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PROGRESS_CODE_S3_SUSPEND_END); + + /// + /// Flush cache into memory before we go to sleep. + /// + AsmWbinvd (); + } + + /// + /// Now that SMIs are disabled, write to the SLP_EN bit again to trigger the sleep + /// + Pm1Cnt |= B_PCH_ACPI_PM1_CNT_SLP_EN; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT), Pm1Cnt); + + /// + /// Should only proceed if wake event is generated. + /// + if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SLP_TYP) == V_PCH_ACPI_PM1_CNT_S1) { + while (((IoRead16 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_STS))) & B_PCH_ACPI_PM1_STS_WAK) == 0x0); + } else { + EFI_DEADLOOP (); + } + /// + /// The system just went to sleep. If the sleep state was S1, then code execution will resume + /// here when the system wakes up. + /// + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT)); + + if ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SCI_EN) == 0) { + /// + /// An ACPI OS isn't present, clear the sleep information + /// + Pm1Cnt &= ~B_PCH_ACPI_PM1_CNT_SLP_TYP; + Pm1Cnt |= V_PCH_ACPI_PM1_CNT_S0; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT), Pm1Cnt); + } + + PchSmmClearSource (&SX_SOURCE_DESC); + PchSmmEnableSource (&SX_SOURCE_DESC); +} diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmUsb.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmUsb.c new file mode 100644 index 0000000..8f24ff5 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchSmmUsb.c @@ -0,0 +1,300 @@ +/** @file + File to contain all the hardware specific stuff for the Smm USB dispatch protocol. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#include "PchSmmHelpers.h" + +PCH_SMM_SOURCE_DESC mUSB2_WAKE = { + PCH_SMM_SCI_EN_DEPENDENT, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_INTEL_USB2 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_INTEL_USB2 + } + } +}; + +PCH_SMM_SOURCE_DESC mUSB1_LEGACY = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_LEGACY_USB + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_LEGACY_USB + } + } +}; + +PCH_SMM_SOURCE_DESC mUSB2_LEGACY = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_LEGACY_USB2 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_LEGACY_USB2 + } + } +}; + +PCH_SMM_SOURCE_DESC mUSB3_LEGACY = { + PCH_SMM_NO_FLAGS, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_EN + }, + S_PCH_SMI_EN, + N_PCH_SMI_EN_LEGACY_USB3 + }, + NULL_BIT_DESC_INITIALIZER + }, + { + { + { + ACPI_ADDR_TYPE, + R_PCH_SMI_STS + }, + S_PCH_SMI_STS, + N_PCH_SMI_STS_LEGACY_USB3 + } + } +}; + +typedef enum { + PchUsbControllerLpc0 = 0, + PchUsbControllerEhci1, + PchUsbControllerEhci2, + PchUsbControllerXhci, + PchUsbControllerTypeMax +} PCH_USB_CONTROLLER_TYPE; + +typedef struct { + UINT8 Function; + UINT8 Device; + PCH_USB_CONTROLLER_TYPE UsbConType; +} USB_CONTROLLER; + +USB_CONTROLLER mUsbControllersMap[] = { + { + PCI_FUNCTION_NUMBER_PCH_LPC, + PCI_DEVICE_NUMBER_PCH_LPC, + PchUsbControllerLpc0 + }, + { + PCI_FUNCTION_NUMBER_PCH_EHCI, + PCI_DEVICE_NUMBER_PCH_USB, + PchUsbControllerEhci1 + }, + { + PCI_FUNCTION_NUMBER_PCH_EHCI2, + PCI_DEVICE_NUMBER_PCH_USB_EXT, + PchUsbControllerEhci2 + }, + { + PCI_FUNCTION_NUMBER_PCH_XHCI, + PCI_DEVICE_NUMBER_PCH_XHCI, + PchUsbControllerXhci + } +}; + +/** + Find the handle that best matches the input Device Path and return the USB controller type + + @param[in] DevicePath Pointer to the device Path table + @param[out] Controller Returned with the USB controller type of the input device path + + @retval EFI_SUCCESS Find the handle that best matches the input Device Path + @exception EFI_UNSUPPORTED Invalid device Path table or can't find any match USB device path + PCH_USB_CONTROLLER_TYPE The USB controller type of the input + device path +**/ +EFI_STATUS +DevicePathToSupportedController ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT PCH_USB_CONTROLLER_TYPE *Controller + ) +{ + EFI_STATUS Status; + EFI_HANDLE DeviceHandle; + ACPI_HID_DEVICE_PATH *AcpiNode; + PCI_DEVICE_PATH *PciNode; + EFI_DEVICE_PATH_PROTOCOL *RemaingDevicePath; + UINT8 UsbIndex; + /// + /// Find the handle that best matches the Device Path. If it is only a + /// partial match the remaining part of the device path is returned in + /// RemainingDevicePath. + /// + RemaingDevicePath = DevicePath; + Status = gBS->LocateDevicePath ( + &gEfiPciRootBridgeIoProtocolGuid, + &DevicePath, + &DeviceHandle + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + DevicePath = RemaingDevicePath; + + /// + /// Get first node: Acpi Node + /// + AcpiNode = (ACPI_HID_DEVICE_PATH *) RemaingDevicePath; + + if (AcpiNode->Header.Type != ACPI_DEVICE_PATH || + AcpiNode->Header.SubType != ACPI_DP || + DevicePathNodeLength (&AcpiNode->Header) != sizeof (ACPI_HID_DEVICE_PATH) || + AcpiNode->HID != EISA_PNP_ID (0x0A03) || + AcpiNode->UID != 0 + ) { + return EFI_UNSUPPORTED; + } else { + /// + /// Get the next node: Pci Node + /// + RemaingDevicePath = NextDevicePathNode (RemaingDevicePath); + PciNode = (PCI_DEVICE_PATH *) RemaingDevicePath; + if (PciNode->Header.Type != HARDWARE_DEVICE_PATH || + PciNode->Header.SubType != HW_PCI_DP || + DevicePathNodeLength (&PciNode->Header) != sizeof (PCI_DEVICE_PATH) + ) { + return EFI_UNSUPPORTED; + } + + for (UsbIndex = 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof (USB_CONTROLLER); UsbIndex++) { + if ((PciNode->Device == mUsbControllersMap[UsbIndex].Device) && + (PciNode->Function == mUsbControllersMap[UsbIndex].Function)) { + *Controller = mUsbControllersMap[UsbIndex].UsbConType; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; + } +} + +/** + Maps a USB context to a source description. + + @param[in] Context The context we need to map. Type must be USB. + @param[in] SrcDesc The source description that corresponds to the given context. + + @retval None. +**/ +VOID +MapUsbToSrcDesc ( + IN PCH_SMM_CONTEXT *Context, + OUT PCH_SMM_SOURCE_DESC *SrcDesc + ) +{ + PCH_USB_CONTROLLER_TYPE Controller; + EFI_STATUS Status; + + Status = DevicePathToSupportedController (Context->Usb.Device, &Controller); + /// + /// Either the device path passed in by the child is incorrect or + /// the ones stored here internally are incorrect. + /// + ASSERT_EFI_ERROR (Status); + + switch (Context->Usb.Type) { + case UsbLegacy: + switch (Controller) { + case PchUsbControllerLpc0: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUSB1_LEGACY), sizeof (PCH_SMM_SOURCE_DESC)); + break; + + case PchUsbControllerEhci1: + case PchUsbControllerEhci2: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUSB2_LEGACY), sizeof (PCH_SMM_SOURCE_DESC)); + break; + + case PchUsbControllerXhci: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUSB3_LEGACY), sizeof (PCH_SMM_SOURCE_DESC)); + break; + + default: + ASSERT (FALSE); + break; + } + break; + + case UsbWake: + switch (Controller) { + case PchUsbControllerEhci1: + case PchUsbControllerEhci2: + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUSB2_WAKE), sizeof (PCH_SMM_SOURCE_DESC)); + break; + + default: + ASSERT (FALSE); + break; + } + break; + + default: + ASSERT (FALSE); + break; + } +} diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchxSmmHelpers.c b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchxSmmHelpers.c new file mode 100644 index 0000000..f6513a7 --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchxSmmHelpers.c @@ -0,0 +1,820 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ +#include "PchSmmHelpers.h" + +// +// Help handle porting bit shifts to IA-64. +// +#define BIT_ZERO 0x00000001 + +/** + Publish SMI Dispatch protocols. + + @param[in] None + + @retval None +**/ +VOID +PchSmmPublishDispatchProtocols ( + VOID + ) +{ + EFI_STATUS Status; + + /// + /// Install protocol interfaces. + /// + Status = gBS->InstallMultipleProtocolInterfaces ( + &mPrivateData.InstallMultProtHandle, + &gEfiSmmGpiDispatchProtocolGuid, + &mPrivateData.Protocols[GpiType].Protocols.Gpi, + &gEfiSmmSxDispatchProtocolGuid, + &mPrivateData.Protocols[SxType].Protocols.Sx, + &gEfiSmmSwDispatchProtocolGuid, + &mPrivateData.Protocols[SwType].Protocols.Sw, + &gEfiSmmIchnDispatchProtocolGuid, + &mPrivateData.Protocols[IchnType].Protocols.Ichn, + &gEfiSmmIchnDispatchExProtocolGuid, + &mPrivateData.Protocols[IchnExType].Protocols.IchnEx, + &gEfiSmmPowerButtonDispatchProtocolGuid, + &mPrivateData.Protocols[PowerButtonType].Protocols.PowerButton, + &gEfiSmmPeriodicTimerDispatchProtocolGuid, + &mPrivateData.Protocols[PeriodicTimerType].Protocols.PeriodicTimer, + &gEfiSmmUsbDispatchProtocolGuid, + &mPrivateData.Protocols[UsbType].Protocols.Usb, + NULL + ); + ASSERT_EFI_ERROR (Status); +} + +/** + Initialize bits that aren't necessarily related to an SMI source. + + @param[in] None + + @retval EFI_SUCCESS SMI source initialization completed. + @retval Asserts Global Smi Bit is not enabled successfully. +**/ +EFI_STATUS +PchSmmInitHardware ( + VOID + ) +{ + EFI_STATUS Status; + + /// + /// Clear all SMIs + /// + PchSmmClearSmi (); + + Status = PchSmmEnableGlobalSmiBit (); + ASSERT_EFI_ERROR (Status); + + /// + /// Be *really* sure to clear all SMIs + /// + PchSmmClearSmi (); + + return EFI_SUCCESS; +} + +/** + Enables the PCH to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + + @param[in] None + + @retval EFI_SUCCESS Enable Global Smi Bit completed +**/ +EFI_STATUS +PchSmmEnableGlobalSmiBit ( + VOID + ) +{ + UINT32 SmiEn; + + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_SMI_EN)); + + /// + /// Set the "global smi enable" bit + /// + SmiEn |= B_PCH_SMI_EN_GBL_SMI; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_PCH_SMI_EN), SmiEn); + + return EFI_SUCCESS; +} + +/** + Clears the SMI after all SMI source have been processed. + Note that this function will not work correctly (as it is + written) unless all SMI sources have been processed. + A revision of this function could manually clear all SMI + status bits to guarantee success. + + @param[in] None + + @retval EFI_SUCCESS Clears the SMIs completed + @retval Asserts EOS was not set to a 1 +**/ +EFI_STATUS +PchSmmClearSmi ( + VOID + ) +{ + BOOLEAN EosSet; + BOOLEAN SciEn; + UINT32 Pm1Cnt; + UINT16 Pm1Sts; + UINT32 Gpe0Sts; + UINT32 Gpe0aStsLow; + UINT32 Gpe0bStsHigh; + UINT32 SmiSts; + UINT32 AltGpiSmiSts; + UINT16 DevActSts; + UINT16 Tco1Sts; + UINT16 Tco2Sts; + PCH_SERIES PchSeries; + + PchSeries = GetPchSeries(); + Gpe0Sts = 0; + Gpe0aStsLow = 0; + Gpe0bStsHigh = 0; + AltGpiSmiSts = 0; + /// + /// Determine whether an ACPI OS is present (via the SCI_EN bit) + /// + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT)); + SciEn = (BOOLEAN) ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SCI_EN) == B_PCH_ACPI_PM1_CNT_SCI_EN); + if (!SciEn) { + /// + /// Clear any SMIs that double as SCIs (when SCI_EN==0) + /// + Pm1Sts = IoRead16 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_STS)); + if (PchSeries == PchLp) { + Gpe0Sts = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_GPE0_STS_127_96)); + } else if (PchSeries == PchH) { + Gpe0aStsLow = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS)); + Gpe0bStsHigh = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_GPE0b_STS)); + } + + Pm1Sts |= + ( + B_PCH_ACPI_PM1_STS_WAK | + B_PCH_ACPI_PM1_STS_PRBTNOR | + B_PCH_ACPI_PM1_STS_RTC | + B_PCH_ACPI_PM1_STS_PWRBTN | + B_PCH_ACPI_PM1_STS_GBL | + B_PCH_ACPI_PM1_STS_TMROF + ); + + if (PchSeries == PchLp) { + Gpe0Sts |= + ( + B_PCH_ACPI_GPE0_STS_127_96_PME_B0 | + B_PCH_ACPI_GPE0_STS_127_96_PME | + B_PCH_ACPI_GPE0_STS_127_96_BATLOW | + B_PCH_ACPI_GPE0_STS_127_96_PCI_EXP | + B_PCH_ACPI_GPE0_STS_127_96_RI | + B_PCH_ACPI_GPE0_STS_127_96_SMB_WAK | + B_PCH_ACPI_GPE0_STS_127_96_TC0SCI | + B_PCH_ACPI_GPE0_STS_127_96_HOT_PLUG | + B_PCH_ACPI_GPE0_STS_127_96_BATLOW | + B_PCH_ACPI_GPE0_STS_127_96_GP27 + ); + } else if (PchSeries == PchH) { + Gpe0aStsLow |= + ( + B_PCH_ACPI_GPE0a_STS_PME_B0 | + B_PCH_ACPI_GPE0a_STS_PME | + B_PCH_ACPI_GPE0a_STS_BATLOW | + B_PCH_ACPI_GPE0a_STS_PCI_EXP | + B_PCH_ACPI_GPE0a_STS_RI | + B_PCH_ACPI_GPE0a_STS_SMB_WAK | + B_PCH_ACPI_GPE0a_STS_TC0SCI | + B_PCH_ACPI_GPE0a_STS_HOT_PLUG | + B_PCH_ACPI_GPE0a_STS_BATLOW + ); + + Gpe0bStsHigh |= (B_PCH_ACPI_GPE0b_STS_GP27); + } + + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_STS), (UINT16) Pm1Sts); + if (PchSeries == PchLp) { + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_GPE0_STS_127_96), (UINT32) Gpe0Sts); + } else if (PchSeries == PchH) { + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_GPE0a_STS), (UINT32) Gpe0aStsLow); + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_GPE0b_STS), (UINT32) Gpe0bStsHigh); + } + } + /// + /// Clear all SMIs that are unaffected by SCI_EN + /// + if (PchSeries == PchLp) { + AltGpiSmiSts = IoRead32 ((UINTN) (mGpioBaseAddr + R_PCH_LPTLP_ALT_GP_SMI_STS)); + } else if (PchSeries == PchH) { + AltGpiSmiSts = IoRead16 ((UINTN) (mAcpiBaseAddr + R_PCH_LPTH_ALT_GP_SMI_STS)); + } + SmiSts = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_SMI_STS)); + DevActSts = IoRead16 ((UINTN) (mAcpiBaseAddr + R_PCH_DEVACT_STS)); + Tco1Sts = IoRead16 ((UINTN) (mAcpiBaseAddr + PCH_TCO_BASE + R_PCH_TCO1_STS)); + Tco2Sts = IoRead16 ((UINTN) (mAcpiBaseAddr + PCH_TCO_BASE + R_PCH_TCO2_STS)); + + SmiSts |= + ( + B_PCH_SMI_STS_SMBUS | + B_PCH_SMI_STS_PERIODIC | + B_PCH_SMI_STS_TCO | + B_PCH_SMI_STS_MCSMI | + B_PCH_SMI_STS_SWSMI_TMR | + B_PCH_SMI_STS_APM | + B_PCH_SMI_STS_ON_SLP_EN | + B_PCH_SMI_STS_BIOS + ); + AltGpiSmiSts |= 0xFFFF; + DevActSts |= + ( + B_PCH_DEVACT_STS_KBC | + B_PCH_DEVACT_STS_PIRQDH | + B_PCH_DEVACT_STS_PIRQCG | + B_PCH_DEVACT_STS_PIRQBF | + B_PCH_DEVACT_STS_PIRQAE + ); + Tco1Sts |= + ( + B_PCH_TCO1_STS_DMISERR | + B_PCH_TCO1_STS_DMISMI | + B_PCH_TCO1_STS_DMISCI | + B_PCH_TCO1_STS_BIOSWR | + B_PCH_TCO1_STS_NEWCENTURY | + B_PCH_TCO1_STS_TIMEOUT | + B_PCH_TCO1_STS_TCO_INT | + B_PCH_TCO1_STS_SW_TCO_SMI + ); + if(PchSeries == PchLp){ + IoWrite32 ((UINTN) (mGpioBaseAddr + R_PCH_LPTLP_ALT_GP_SMI_STS), AltGpiSmiSts); + } else if (PchSeries == PchH) { + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_PCH_LPTH_ALT_GP_SMI_STS), (UINT16)AltGpiSmiSts); + } + IoWrite16 ((UINTN) (mAcpiBaseAddr + PCH_TCO_BASE + R_PCH_TCO1_STS), Tco1Sts); + + Tco2Sts |= B_PCH_TCO2_STS_SECOND_TO; + IoWrite16 ((UINTN) (mAcpiBaseAddr + PCH_TCO_BASE + R_PCH_TCO2_STS), Tco2Sts); + + Tco2Sts |= (B_PCH_TCO2_STS_SMLINK_SLV_SMI | B_PCH_TCO2_STS_BOOT | B_PCH_TCO2_STS_INTRD_DET); + IoWrite16 ((UINTN) (mAcpiBaseAddr + PCH_TCO_BASE + R_PCH_TCO2_STS), Tco2Sts); + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_PCH_SMI_STS), SmiSts); + + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_PCH_DEVACT_STS), DevActSts); + + /// + /// Try to clear the EOS bit. ASSERT on an error + /// + EosSet = PchSmmSetAndCheckEos (); + ASSERT (EosSet); + + return EFI_SUCCESS; +} + +/** + Set the SMI EOS bit after all SMI source have been processed. + + @param[in] None + + @retval FALSE EOS was not set to a 1; this is an error + @retval TRUE EOS was correctly set to a 1 +**/ +BOOLEAN +PchSmmSetAndCheckEos ( + VOID + ) +{ + UINT32 SmiEn; + + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_SMI_EN)); + + /// + /// Reset the PCH to generate subsequent SMIs + /// + SmiEn |= B_PCH_SMI_EN_EOS; + + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_PCH_SMI_EN), SmiEn); + + /// + /// Double check that the assert worked + /// + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_SMI_EN)); + + /// + /// Return TRUE if EOS is set correctly + /// + if ((SmiEn & B_PCH_SMI_EN_EOS) == 0) { + /// + /// EOS was not set to a 1; this is an error + /// + return FALSE; + } else { + /// + /// EOS was correctly set to a 1 + /// + return TRUE; + } +} + +/** + Determine whether an ACPI OS is present (via the SCI_EN bit) + + @param[in] None + + @retval TRUE ACPI OS is present + @retval FALSE ACPI OS is not present +**/ +BOOLEAN +PchSmmGetSciEn ( + VOID + ) +{ + BOOLEAN SciEn; + UINT32 Pm1Cnt; + + /// + /// Determine whether an ACPI OS is present (via the SCI_EN bit) + /// + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_PCH_ACPI_PM1_CNT)); + SciEn = (BOOLEAN) ((Pm1Cnt & B_PCH_ACPI_PM1_CNT_SCI_EN) == B_PCH_ACPI_PM1_CNT_SCI_EN); + + return SciEn; +} + +/** + Read a specifying bit with the register + These may or may not need to change w/ the PCH version; they're highly IA-32 dependent, though. + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + + @retval TRUE The bit is enabled + @retval FALSE The bit is disabled +**/ +BOOLEAN +ReadBitDesc ( + const PCH_SMM_BIT_DESC *BitDesc + ) +{ + EFI_STATUS Status; + UINT64 Register; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + UINTN RegSize; + BOOLEAN BitWasOne; + UINTN ShiftCount; + UINTN RegisterOffset; + UINT32 BaseAddr; + + ASSERT (BitDesc != NULL); + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); + + RegSize = 0; + Register = 0; + ShiftCount = 0; + BitWasOne = FALSE; + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + case GPIO_ADDR_TYPE: + if(BitDesc->Reg.Type == ACPI_ADDR_TYPE){ + RegisterOffset = BitDesc->Reg.Data.acpi; + BaseAddr = mAcpiBaseAddr; + } else { + RegisterOffset = BitDesc->Reg.Data.gpio; + BaseAddr = mGpioBaseAddr; + } + switch (BitDesc->SizeInBytes) { + + case 0: + /// + /// Chances are that this field didn't get initialized. + /// Check your assignments to bit descriptions. + /// + ASSERT (FALSE); + break; + + case 1: + RegSize = SMM_IO_UINT8; + break; + + case 2: + RegSize = SMM_IO_UINT16; + break; + + case 4: + RegSize = SMM_IO_UINT32; + break; + + case 8: + RegSize = SMM_IO_UINT64; + break; + + default: + /// + /// Unsupported or invalid register size + /// + ASSERT (FALSE); + break; + } + /// + /// Double check that we correctly read in the acpi base address + /// + ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1)); + + ShiftCount = BitDesc->Bit; + /// + /// As current CPU Smm Io can only support at most + /// 32-bit read/write,if Operation is 64 bit, + /// we do a 32 bit operation according to BitDesc->Bit + /// + if (RegSize == SMM_IO_UINT64) { + RegSize = SMM_IO_UINT32; + /// + /// If the operation is for high 32 bits + /// + if (BitDesc->Bit >= 32) { + RegisterOffset += 4; + ShiftCount -= 32; + } + } + + Status = mSmst->SmmIo.Io.Read ( + &mSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + + if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) != 0) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + /// + /// Read the register, and it with the bit to read + /// + switch (BitDesc->SizeInBytes) { + case 1: + Register = (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 2: + Register = (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 4: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 8: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio + 4); + break; + + default: + /// + /// Unsupported or invalid register size + /// + ASSERT (FALSE); + break; + } + + Register = Register & (LShiftU64 (BIT0, BitDesc->Bit)); + if (Register) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + case PCIE_ADDR_TYPE: + PciBus = BitDesc->Reg.Data.pcie.Fields.Bus; + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev; + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc; + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg; + switch (BitDesc->SizeInBytes) { + + case 0: + /// + /// Chances are that this field didn't get initialized. + /// Check your assignments to bit descriptions. + /// + ASSERT (FALSE); + break; + + case 1: + Register = (UINT64) MmioRead8 (MmPciAddress (0, PciBus, PciDev, PciFun, PciReg)); + break; + + case 2: + Register = (UINT64) MmioRead16 (MmPciAddress (0, PciBus, PciDev, PciFun, PciReg)); + break; + + case 4: + Register = (UINT64) MmioRead32 (MmPciAddress (0, PciBus, PciDev, PciFun, PciReg)); + break; + + default: + /// + /// Unsupported or invalid register size + /// + ASSERT (FALSE); + break; + } + + if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) != 0) { + BitWasOne = TRUE; + } else { + BitWasOne = FALSE; + } + break; + + default: + /// + /// This address type is not yet implemented + /// + ASSERT (FALSE); + break; + } + + return BitWasOne; +} + +/** + Write a specifying bit with the register + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + @param[in] ValueToWrite The value to be wrote + @param[in] WriteClear If the rest bits of the register is write clear + + @retval None +**/ +VOID +WriteBitDesc ( + const PCH_SMM_BIT_DESC *BitDesc, + const BOOLEAN ValueToWrite, + const BOOLEAN WriteClear + ) +{ + EFI_STATUS Status; + UINT64 Register; + UINT64 AndVal; + UINT64 OrVal; + UINT32 RegSize; + UINT32 PciBus; + UINT32 PciDev; + UINT32 PciFun; + UINT32 PciReg; + UINTN RegisterOffset; + UINT32 BaseAddr; + + ASSERT (BitDesc != NULL); + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); + + RegSize = 0; + Register = 0; + + if (WriteClear) { + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit); + } else { + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit)); + } + + OrVal = (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit)); + + switch (BitDesc->Reg.Type) { + + case ACPI_ADDR_TYPE: + case GPIO_ADDR_TYPE: + if(BitDesc->Reg.Type == ACPI_ADDR_TYPE){ + RegisterOffset = BitDesc->Reg.Data.acpi; + BaseAddr = mAcpiBaseAddr; + } else { + RegisterOffset = BitDesc->Reg.Data.gpio; + BaseAddr = mGpioBaseAddr; + } + switch (BitDesc->SizeInBytes) { + + case 0: + /// + /// Chances are that this field didn't get initialized. + /// Check your assignments to bit descriptions. + /// + ASSERT (FALSE); + break; + + case 1: + RegSize = SMM_IO_UINT8; + break; + + case 2: + RegSize = SMM_IO_UINT16; + break; + + case 4: + RegSize = SMM_IO_UINT32; + break; + + case 8: + RegSize = SMM_IO_UINT64; + break; + + default: + /// + /// Unsupported or invalid register size + /// + ASSERT (FALSE); + break; + } + /// + /// Double check that we correctly read in the acpi base address + /// + ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1)); + + /// + /// As current CPU Smm Io can only support at most + /// 32-bit read/write,if Operation is 64 bit, + /// we do a 32 bit operation according to BitDesc->Bit + /// + if (RegSize == SMM_IO_UINT64) { + RegSize = SMM_IO_UINT32; + /// + /// If the operation is for high 32 bits + /// + if (BitDesc->Bit >= 32) { + RegisterOffset += 4; + + if (WriteClear) { + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit - 32); + } else { + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32)); + } + + OrVal = LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32); + } + } + + Status = mSmst->SmmIo.Io.Read ( + &mSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + + Register &= AndVal; + Register |= OrVal; + + Status = mSmst->SmmIo.Io.Write ( + &mSmst->SmmIo, + RegSize, + BaseAddr + RegisterOffset, + 1, + &Register + ); + ASSERT_EFI_ERROR (Status); + break; + + case MEMORY_MAPPED_IO_ADDRESS_TYPE: + /// + /// Read the register, or it with the bit to set, then write it back. + /// + switch (BitDesc->SizeInBytes) { + case 1: + Register = (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 2: + Register = (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 4: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + break; + + case 8: + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio); + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio + 4); + break; + + default: + /// + /// Unsupported or invalid register size + /// + ASSERT (FALSE); + break; + } + + Register &= AndVal; + Register |= OrVal; + /// + /// Read the register, or it with the bit to set, then write it back. + /// + switch (BitDesc->SizeInBytes) { + case 1: + MmioWrite8 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT8) Register); + break; + + case 2: + MmioWrite16 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT16) Register); + break; + + case 4: + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register); + break; + + case 8: + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register); + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio + 4, *((UINT32 *) (&Register) + 1)); + break; + + default: + /// + /// Unsupported or invalid register size + /// + ASSERT (FALSE); + break; + } + break; + + case PCIE_ADDR_TYPE: + PciBus = BitDesc->Reg.Data.pcie.Fields.Bus; + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev; + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc; + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg; + switch (BitDesc->SizeInBytes) { + + case 0: + /// + /// Chances are that this field didn't get initialized -- check your assignments + /// to bit descriptions. + /// + ASSERT (FALSE); + break; + + case 1: + MmioAndThenOr8 (MmPciAddress (0, PciBus, PciDev, PciFun, PciReg), (UINT8) AndVal, (UINT8) OrVal); + break; + + case 2: + MmioAndThenOr16 (MmPciAddress (0, PciBus, PciDev, PciFun, PciReg), (UINT16) AndVal, (UINT16) OrVal); + break; + + case 4: + MmioAndThenOr32 (MmPciAddress (0, PciBus, PciDev, PciFun, PciReg), (UINT32) AndVal, (UINT32) OrVal); + break; + + default: + /// + /// Unsupported or invalid register size + /// + ASSERT (FALSE); + break; + } + break; + + default: + /// + /// This address type is not yet implemented + /// + ASSERT (FALSE); + break; + } +} diff --git a/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchxSmmHelpers.h b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchxSmmHelpers.h new file mode 100644 index 0000000..ead184c --- /dev/null +++ b/ReferenceCode/Chipset/LynxPoint/PchSmiDispatcher/Smm/PchxSmmHelpers.h @@ -0,0 +1,128 @@ +/** @file + This driver is responsible for the registration of child drivers + and the abstraction of the PCH SMI sources. + +@copyright + Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +**/ +#ifndef _PCHX_SMM_HELPERS_H_ +#define _PCHX_SMM_HELPERS_H_ + +#include "PchSmm.h" +#include "PchPlatformLib.h" + +/** + Initialize bits that aren't necessarily related to an SMI source. + + @param[in] None + + @retval EFI_SUCCESS SMI source initialization completed. + @retval Asserts Global Smi Bit is not enabled successfully. +**/ +EFI_STATUS +PchSmmInitHardware ( + VOID + ); + +/** + Enables the PCH to generate SMIs. Note that no SMIs will be generated + if no SMI sources are enabled. Conversely, no enabled SMI source will + generate SMIs if SMIs are not globally enabled. This is the main + switchbox for SMI generation. + + @param[in] None + + @retval EFI_SUCCESS Enable Global Smi Bit completed +**/ +EFI_STATUS +PchSmmEnableGlobalSmiBit ( + VOID + ); + +/** + Clears the SMI after all SMI source have been processed. + Note that this function will not work correctly (as it is + written) unless all SMI sources have been processed. + A revision of this function could manually clear all SMI + status bits to guarantee success. + + @param[in] None + + @retval EFI_SUCCESS Clears the SMIs completed + @retval Asserts EOS was not set to a 1 +**/ +EFI_STATUS +PchSmmClearSmi ( + VOID + ); + +/** + Set the SMI EOS bit after all SMI source have been processed. + + @param[in] None + + @retval FALSE EOS was not set to a 1; this is an error + @retval TRUE EOS was correctly set to a 1 +**/ +BOOLEAN +PchSmmSetAndCheckEos ( + VOID + ); + +/** + Determine whether an ACPI OS is present (via the SCI_EN bit) + + @param[in] None + + @retval TRUE ACPI OS is present + @retval FALSE ACPI OS is not present +**/ +BOOLEAN +PchSmmGetSciEn ( + VOID + ); + +/** + Read a specifying bit with the register + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + + @retval TRUE The bit is enabled + @retval FALSE The bit is disabled +**/ +BOOLEAN +ReadBitDesc ( + const PCH_SMM_BIT_DESC *BitDesc + ); + +/** + Write a specifying bit with the register + + @param[in] BitDesc The struct that includes register address, size in byte and bit number + @param[in] ValueToWrite The value to be wrote + @param[in] WriteClear If the rest bits of the register is write clear + + @retval None +**/ +VOID +WriteBitDesc ( + const PCH_SMM_BIT_DESC *BitDesc, + const BOOLEAN ValueToWrite, + const BOOLEAN WriteClear + ); + +#endif |