summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-06-02 13:59:07 +0800
committerHao Wu <hao.a.wu@intel.com>2016-06-07 09:55:44 +0800
commit2d29f5af46ba7fe2afc000badf5746c34e42f0cf (patch)
treead6d1a2d027a5db829aa688834e6697c7e5de53c
parent027f496a7e6db871ef6590cec153004def4fc12f (diff)
downloadedk2-platforms-2d29f5af46ba7fe2afc000badf5746c34e42f0cf.tar.xz
ChvRefCodePkg: Add PchSmiDispatcher module.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmiDispatcher.inf89
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmm.h748
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmCore.c775
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmGpi.c56
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmHelpers.c308
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmHelpers.h143
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmIchn.c987
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c555
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmPowerButton.c95
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmSw.c161
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmSx.c257
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmUsb.c249
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchxSmmHelpers.c730
-rw-r--r--ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchxSmmHelpers.h112
14 files changed, 5265 insertions, 0 deletions
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmiDispatcher.inf b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmiDispatcher.inf
new file mode 100644
index 0000000000..a86c37b8df
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmiDispatcher.inf
@@ -0,0 +1,89 @@
+## @file
+# SMM Dispatcher Driver
+#
+# This module provides the ability for system drivers to register and unregister
+# handlers for specific SMI events.
+#
+# Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PchSmiDispatcher
+ FILE_GUID = E7AEA323-2363-45BE-ADF5-2C69A4E5C6FD
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = InitializePchSmmDispatcher
+
+[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
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ ChvRefCodePkg/ChvRefCodePkg.dec
+
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ IoLib
+ DebugLib
+ PcdLib
+ BaseLib
+ BaseMemoryLib
+ DevicePathLib
+ PchPlatformLib
+ SmmServicesTableLib
+ ReportStatusCodeLib
+ PerformanceLib
+ DxeServicesTableLib
+ ReportStatusCodeLib
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid #CONSUMES
+ gEfiSmmGpiDispatch2ProtocolGuid #PRODUCES
+ gEfiSmmSxDispatch2ProtocolGuid #PRODUCES
+ gEfiSmmSwDispatch2ProtocolGuid #PRODUCES
+ gEfiSmmIchnDispatchProtocolGuid #PRODUCES
+ gEfiSmmUsbDispatch2ProtocolGuid #PRODUCES
+ gEfiSmmIchnDispatchExProtocolGuid #PRODUCES
+ gEfiSmmPowerButtonDispatch2ProtocolGuid #PRODUCES
+ gEfiSmmPeriodicTimerDispatch2ProtocolGuid #PRODUCES
+ gEfiSmmBase2ProtocolGuid #CONSUMES
+ gEfiSmmCpuProtocolGuid #CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd ## CONSUMES
+
+[Depex]
+ gEfiSmmCpuProtocolGuid AND
+ gEfiSmmBase2ProtocolGuid AND
+ gEfiPciRootBridgeIoProtocolGuid
+
+[BuildOptions]
+ *_*_X64_CC_FLAGS = -D X64_BUILD_SUPPORT=1
+
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmm.h b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmm.h
new file mode 100644
index 0000000000..3ce4fac529
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmm.h
@@ -0,0 +1,748 @@
+/** @file
+ Prototypes and defines for the PCH SMM Dispatcher.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef PCH_SMM_H
+#define PCH_SMM_H
+
+#include <PiSmm.h>
+
+#include <Uefi.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SmmControl2.h>
+#include <Protocol/SmmUsbDispatch2.h>
+#include <Protocol/SmmSxDispatch2.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/SmmGpiDispatch2.h>
+#include <Protocol/SmmIchnDispatch.h>
+#include <Protocol/SmmPowerButtonDispatch2.h>
+#include <Protocol/SmmPeriodicTimerDispatch2.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PerformanceLib.h>
+#include <Protocol/SmmIchnDispatchEx.h>
+#include <PchAccess.h>
+#include <Library/PchPlatformLib.h>
+
+#if (defined X64_BUILD_SUPPORT) && (X64_BUILD_SUPPORT == 1)
+#define EFI_BAD_POINTER 0xAFAFAFAFAFAFAFAFULL
+#else
+#define EFI_BAD_POINTER 0xAFAFAFAFUL
+#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
+/// Memory (or Memory Mapped I/O) Only if we want to
+/// PCIE Yes, for BiosWp
+
+///
+typedef enum {
+ ///
+ /// IO_ADDR_TYPE, /// unimplemented
+ ///
+ ACPI_ADDR_TYPE,
+ ///
+ /// MEMORY_ADDR_TYPE, /// unimplemented
+ ///
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+#ifdef PCIESC_SUPPORT
+ PCIE_ADDR_TYPE,
+#endif
+ 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 ACPI_ADDR; /// can omit
+typedef IO_ADDR TCO_ADDR; /// can omit
+typedef UINTN MEM_ADDR;
+typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS;
+#ifdef PCIESC_SUPPORT
+typedef union {
+ UINT32 Raw;
+ struct {
+ UINT8 Reg;
+ UINT8 Fnc;
+ UINT8 Dev;
+ UINT8 Bus;
+ } Fields;
+} PCIE_ADDR;
+#endif
+
+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;
+ MEM_ADDR mem;
+ MEMORY_MAPPED_IO_ADDRESS Mmio;
+#ifdef PCIESC_SUPPORT
+ PCIE_ADDR pcie;
+#endif
+
+ } 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_REGISTER_CONTEXT Sx;
+ EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer;
+ EFI_SMM_SW_REGISTER_CONTEXT Sw;
+ EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton;
+ EFI_SMM_USB_REGISTER_CONTEXT Usb;
+ EFI_SMM_GPI_REGISTER_CONTEXT Gpi;
+} PCH_SMM_CONTEXT;
+
+///
+/// Misc data for PchDispatcher usage.
+/// For PeriodicTimer, since the ElapsedTime is removed from EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT of EDKII,
+/// and PchDispatcher needs it for every record. Thus move it here to support ElapsedTime.
+///
+typedef union {
+ UINTN ElapsedTime;
+}PCH_SMM_MISC_DATA;
+
+//
+// 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
+/// In addition, we need a function to acquire CommBuffer and CommBufferSize for
+/// dispatch callback function of EDKII native support.
+///
+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
+ );
+
+typedef
+VOID
+(EFIAPI *GET_COMMBUFFER) (
+ IN DATABASE_RECORD * Record,
+ OUT VOID **CommBuffer,
+ OUT UINTN * CommBufferSize
+ );
+
+///
+/// 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;
+ GET_COMMBUFFER GetCommBuffer;
+} 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.
+
+**/
+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
+
+**/
+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 GPI_SOURCE_DESC[NUM_SUPPORTED_GPIS];
+
+extern PCH_SMM_SOURCE_DESC ICHN_SOURCE_DESCS[NUM_ICHN_TYPES];
+extern PCH_SMM_SOURCE_DESC ICHN_SOURCE_DESCS_AX[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
+///
+/// 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 SIGNATURE_32 ('D', 'B', 'R', 'C')
+
+struct _DATABASE_RECORD {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ BOOLEAN Processed;
+
+ ///
+ /// Status and Enable bit description
+ ///
+ PCH_SMM_SOURCE_DESC SrcDesc;
+
+ ///
+ /// Callback function
+ ///
+ EFI_SMM_HANDLER_ENTRY_POINT2 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;
+
+ ///
+ /// Misc data for private usage
+ ///
+ PCH_SMM_MISC_DATA MiscData;
+};
+
+#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE)
+#define DATABASE_RECORD_FROM_CHILDCONTEXT(_record) CR (_record, DATABASE_RECORD, ChildContext, 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 EFI_SMM_HANDLER_ENTRY_POINT2 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_DISPATCH2_PROTOCOL Usb;
+ EFI_SMM_SX_DISPATCH2_PROTOCOL Sx;
+ EFI_SMM_SW_DISPATCH2_PROTOCOL Sw;
+ EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi;
+ EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton;
+ EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer;
+ EFI_SMM_ICHN_DISPATCH_PROTOCOL Ichn;
+ EFI_SMM_ICHN_DISPATCH_EX_PROTOCOL IchnEx;
+} PCH_SMM_PROTOCOL;
+
+///
+/// Define a structure to help us identify the generic protocol
+///
+#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T')
+
+typedef struct {
+ UINTN Signature;
+
+ PCH_SMM_PROTOCOL_TYPE Type;
+ EFI_GUID *Guid;
+ 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 SmiHandle;
+ EFI_HANDLE InstallMultProtHandle;
+ PCH_SMM_QUALIFIED_PROTOCOL Protocols[PchSmmProtocolTypeMax];
+} PRIVATE_DATA;
+
+extern PRIVATE_DATA mPrivateData;
+extern UINT32 AcpiBase;
+
+/**
+ Get the Software Smi value
+
+ @param[in] Record No use
+ @param[out] Context The context that includes Software Smi value to be filled
+
+**/
+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
+ );
+
+/**
+ Gather the CommBuffer information of SmmSwDispatch2.
+
+ @param[in] Record No use
+ @param[out] CommBuffer Point to the CommBuffer structure
+ @param[out] CommBufferSize Point to the Size of CommBuffer structure
+
+**/
+VOID
+EFIAPI
+SwGetCommBuffer (
+ IN DATABASE_RECORD *Record,
+ OUT VOID **CommBuffer,
+ OUT UINTN *CommBufferSize
+ );
+
+/**
+ Get the Sleep type
+
+ @param[in] Record No use
+ @param[out] Context The context that includes SLP_TYP bits to be filled
+
+**/
+VOID
+EFIAPI
+SxGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT PCH_SMM_CONTEXT *Context
+ );
+
+/**
+ Init required protocol for Pch Sw Dispatch protocol.
+
+**/
+VOID
+PchSwDispatchInit (
+ VOID
+ );
+
+/**
+ 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.
+
+**/
+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
+ );
+
+/**
+ Gather the CommBuffer information of SmmPeriodicTimerDispatch2.
+
+ @param[in] Record No use
+ @param[out] CommBuffer Point to the CommBuffer structure
+ @param[out] CommBufferSize Point to the Size of CommBuffer structure
+
+**/
+VOID
+EFIAPI
+PeriodicTimerGetCommBuffer (
+ IN DATABASE_RECORD *Record,
+ OUT VOID **CommBuffer,
+ OUT UINTN *CommBufferSize
+ );
+
+/**
+ 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.
+
+**/
+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.
+
+**/
+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 CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_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.
+
+**/
+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
+
+**/
+VOID
+EFIAPI
+PchSmmIchnClearSource (
+ IN PCH_SMM_SOURCE_DESC *SrcDesc
+ );
+
+#endif
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmCore.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmCore.c
new file mode 100644
index 0000000000..b1ba80f435
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmCore.c
@@ -0,0 +1,775 @@
+/** @file
+ This driver is responsible for the registration of child drivers
+ and the abstraction of the PCH SMI sources.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PchSmm.h"
+#include "PchSmmHelpers.h"
+
+#include <Protocol/SmmBase2.h>
+#include <Protocol/SmmControl2.h>
+//
+// MODULE / GLOBAL DATA
+//
+// Module variables used by the both the main dispatcher and the source dispatchers
+// Declared in PchSmmSources.h
+//
+
+UINT32 AcpiBase;
+PRIVATE_DATA mPrivateData = { ///< for the structure
+ {
+ NULL
+ }, ///< CallbackDataBase linked list head
+ NULL, ///< EFI handle returned when calling InstallMultipleProtocolInterfaces
+ NULL, ///< EFI handle returned when calling InstallMultipleProtocolInterfaces
+ { ///< protocol arrays
+ ///
+ /// elements within the array
+ ///
+ {
+ PROTOCOL_SIGNATURE,
+ UsbType,
+ &gEfiSmmUsbDispatch2ProtocolGuid,
+ {
+ (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister,
+ (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ SxType,
+ &gEfiSmmSxDispatch2ProtocolGuid,
+ {
+ (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister,
+ (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ SwType,
+ &gEfiSmmSwDispatch2ProtocolGuid,
+ {
+ (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister,
+ (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister,
+ (UINTN) MAXIMUM_SWI_VALUE
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ GpiType,
+ &gEfiSmmGpiDispatch2ProtocolGuid,
+ {
+ (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister,
+ (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister,
+ (UINTN) NUM_SUPPORTED_GPIS
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ IchnType,
+ &gEfiSmmIchnDispatchProtocolGuid,
+ {
+ (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister,
+ (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ IchnExType,
+ &gEfiSmmIchnDispatchExProtocolGuid,
+ {
+ (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister,
+ (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ PowerButtonType,
+ &gEfiSmmPowerButtonDispatch2ProtocolGuid,
+ {
+ (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister,
+ (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ PeriodicTimerType,
+ &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,
+ {
+ (PCH_SMM_GENERIC_REGISTER) PchSmmCoreRegister,
+ (PCH_SMM_GENERIC_UNREGISTER) PchSmmCoreUnRegister,
+ (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval
+ }
+ },
+ }
+};
+
+CONTEXT_FUNCTIONS mContextFunctions[PchSmmProtocolTypeMax] = {
+ {
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ SxGetContext,
+ SxCmpContext,
+ NULL
+ },
+ {
+ SwGetContext,
+ SwCmpContext,
+ SwGetCommBuffer
+ },
+ {
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ PowerButtonGetContext,
+ PowerButtonCmpContext,
+ NULL
+ },
+ {
+ PeriodicTimerGetContext,
+ PeriodicTimerCmpContext,
+ PeriodicTimerGetCommBuffer
+ },
+};
+
+//
+// PROTOTYPES
+//
+// Functions use only in this file
+//
+EFI_STATUS
+EFIAPI
+PchSmmCoreDispatcher (
+ IN EFI_HANDLE SmmImageHandle,
+ IN CONST VOID *ContextData, OPTIONAL
+ IN OUT VOID *CommunicationBuffer, OPTIONAL
+ IN OUT UINTN *SourceSize OPTIONAL
+ );
+
+//
+// FUNCTIONS
+//
+/**
+ 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;
+ //
+ // Access ACPI Base Addresses Register
+ //
+ AcpiBase = (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 (AcpiBase != 0);
+
+ ///
+ /// Init required protocol for Pch Sw Dispatch protocol.
+ ///
+ PchSwDispatchInit ();
+
+ ///
+ /// Register a callback function to handle subsequent SMIs. This callback
+ /// will be called by SmmCoreDispatcher.
+ ///
+ Status = gSmst->SmiHandlerRegister (PchSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Initialize Callback DataBase
+ ///
+ InitializeListHead (&mPrivateData.CallbackDataBase);
+ PchSmmPublishDispatchProtocols ();
+
+ ///
+ /// Enable SMIs on the PCH now that we have a callback
+ ///
+ PchSmmInitHardware ();
+
+ 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 EFI_SMM_HANDLER_ENTRY_POINT2 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;
+ UINTN Index;
+
+ Index = 0;
+ ///
+ /// Create database record and add to database
+ ///
+
+ Status = gSmst->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 == (UINTN)-1) {
+ for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {
+ if (!EFI_ERROR (SmiInputValueDuplicateCheck (Index))) {
+ Record->ChildContext.Sw.SwSmiInputValue = Index;
+ break;
+ }
+ }
+ if (Record->ChildContext.Sw.SwSmiInputValue == (UINTN)-1) {
+ goto Error;
+ }
+ }
+ 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:
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+ CopyMem (
+ (VOID *) &(Record->SrcDesc),
+ (VOID *) &(GPI_SOURCE_DESC[Record->ChildContext.Gpi.GpiNum]),
+ 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 (SocStepping () < SocB0) {
+ CopyMem (
+ (VOID *) &(Record->SrcDesc),
+ (VOID *) &(ICHN_SOURCE_DESCS_AX[Record->ChildContext.Ichn.Type]),
+ sizeof (PCH_SMM_SOURCE_DESC)
+ );
+ } else {
+ CopyMem (
+ (VOID *) &(Record->SrcDesc),
+ (VOID *) &(ICHN_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 < EfiPowerButtonEntry) ||
+ (Record->ChildContext.PowerButton.Phase > EfiPowerButtonExit)
+ )
+ {
+ 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:
+ goto Error;
+ 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);
+
+ ///
+ /// Child's handle will be the address linked list link in the record
+ ///
+ *DispatchHandle = (EFI_HANDLE) (&Record->Link);
+ *DispatchContext = Record->ChildContext;
+
+ return EFI_SUCCESS;
+
+Error:
+ Status = gSmst->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);
+
+ 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 CONST VOID *ContextData, OPTIONAL
+ IN OUT VOID *CommunicationBuffer, OPTIONAL
+ IN OUT UINTN *SourceSize OPTIONAL
+ )
+{
+ ///
+ /// 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;
+ VOID *CommBuffer;
+ UINTN CommBufferSize;
+
+ 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) {
+
+ if (RecordToExhaust->Callback != NULL) {
+ if (RecordToExhaust->ContextFunctions.GetCommBuffer != NULL) {
+ ///
+ /// This callback function needs CommBuffer and CommBufferSize.
+ /// Get those from child and then pass to callback function.
+ ///
+ RecordToExhaust->ContextFunctions.GetCommBuffer (RecordToExhaust, &CommBuffer, &CommBufferSize);
+ } else {
+ ///
+ /// Child doesn't support the CommBuffer and CommBufferSize.
+ /// Just pass NULL value to callback function.
+ ///
+ CommBuffer = NULL;
+ CommBufferSize = 0;
+ }
+
+ PERF_START_EX (NULL, "SmmFunction", NULL, AsmReadTsc(), RecordToExhaust->ProtocolType);
+ RecordToExhaust->Callback ((EFI_HANDLE) & RecordToExhaust->Link, &Context, CommBuffer, &CommBufferSize);
+ PERF_END_EX (NULL, "SmmFunction", NULL, AsmReadTsc(), RecordToExhaust->ProtocolType);
+ if (RecordToExhaust->ProtocolType == SxType) {
+ SxChildWasDispatched = TRUE;
+ }
+ } else {
+ ASSERT (FALSE);
+ }
+ }
+ }
+ }
+
+ 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/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmGpi.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmGpi.c
new file mode 100644
index 0000000000..1004810a40
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmGpi.c
@@ -0,0 +1,56 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PchSmmHelpers.h"
+
+#define GPI_INIT_ELEMENT(num) { \
+ PCH_SMM_NO_FLAGS, \
+ { \
+ { \
+ { \
+ ACPI_ADDR_TYPE, R_PCH_ALT_GP_SMI_EN \
+ }, \
+ S_PCH_ALT_GP_SMI_EN, num, \
+ }, \
+ NULL_BIT_DESC_INITIALIZER \
+ }, \
+ { \
+ { \
+ { \
+ ACPI_ADDR_TYPE, R_PCH_ALT_GP_SMI_STS \
+ }, \
+ S_PCH_ALT_GP_SMI_STS, (num), \
+ }, \
+ } \
+ }
+
+CONST PCH_SMM_SOURCE_DESC GPI_SOURCE_DESC[NUM_SUPPORTED_GPIS] = {
+ GPI_INIT_ELEMENT(0),
+ GPI_INIT_ELEMENT(1),
+ GPI_INIT_ELEMENT(2),
+ GPI_INIT_ELEMENT(3),
+ GPI_INIT_ELEMENT(4),
+ GPI_INIT_ELEMENT(5),
+ GPI_INIT_ELEMENT(6),
+ GPI_INIT_ELEMENT(7),
+ GPI_INIT_ELEMENT(8),
+ GPI_INIT_ELEMENT(9),
+ GPI_INIT_ELEMENT(10),
+ GPI_INIT_ELEMENT(11),
+ GPI_INIT_ELEMENT(12),
+ GPI_INIT_ELEMENT(13),
+ GPI_INIT_ELEMENT(14),
+ GPI_INIT_ELEMENT(15),
+};
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmHelpers.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmHelpers.c
new file mode 100644
index 0000000000..eb2a4a6d9f
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmHelpers.c
@@ -0,0 +1,308 @@
+/** @file
+ Helper functions for PCH SMM dispatcher.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "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
+
+**/
+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
+
+**/
+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
+
+**/
+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
+
+**/
+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/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmHelpers.h b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmHelpers.h
new file mode 100644
index 0000000000..8a54816ccb
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmHelpers.h
@@ -0,0 +1,143 @@
+/** @file
+ Helper functions for PCH SMM
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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.
+
+**/
+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
+
+**/
+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
+
+**/
+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
+
+**/
+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
+
+**/
+VOID
+PchSmmClearSourceAndBlock (
+ CONST PCH_SMM_SOURCE_DESC *SrcDesc
+ );
+
+#endif
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmIchn.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmIchn.c
new file mode 100644
index 0000000000..dd0061d035
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmIchn.c
@@ -0,0 +1,987 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Ichn dispatch protocol.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PchSmmHelpers.h"
+#include "PlatformBaseAddresses.h"
+#include <Library/PchPlatformLib.h>
+
+PCH_SMM_SOURCE_DESC ICHN_SOURCE_DESCS[NUM_ICHN_TYPES] = {
+ ///
+ /// IchnMch
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// IchnPme
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// 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_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// IchnAc97Wake
+ /// Not supported,
+ /// 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_ILB
+ }
+ }
+ },
+ ///
+ /// IchnY2KRollover
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// IchnTcoTimeout
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_PCH_ACPI_GPE0a_EN
+ },
+ S_PCH_ACPI_GPE0a_EN,
+ N_PCH_ACPI_GPE0a_EN_TCO
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_PCH_TCO_STS
+ },
+ S_PCH_TCO_STS,
+ N_PCH_TCO_STS_TIMEOUT
+ }
+ }
+ },
+ ///
+ /// IchnOsTco
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// IchnNmi
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_PCH_ACPI_GPE0a_EN
+ },
+ S_PCH_ACPI_GPE0a_EN,
+ N_PCH_ACPI_GPE0a_EN_TCO
+ },
+ {
+ {
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ (ILB_BASE_ADDRESS + R_PCH_ILB_GNMI)
+ },
+ S_PCH_ILB_GNMI,
+ N_PCH_ILB_GNMI_NMI2SMIEN
+ }
+ },
+ {
+ {
+ {
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ (ILB_BASE_ADDRESS + R_PCH_ILB_GNMI)
+ },
+ S_PCH_ILB_GNMI,
+ N_PCH_ILB_GNMI_NMI2SMIST
+ }
+ }
+ },
+ ///
+ /// IchnIntruderDetect
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// IchnBiosWp
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_PCH_ACPI_GPE0a_EN
+ },
+ S_PCH_ACPI_GPE0a_EN,
+ N_PCH_ACPI_GPE0a_EN_TCO
+ },
+ {
+ {
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ (SPI_BASE_ADDRESS + R_PCH_SPI_SCS)
+ },
+ S_PCH_SPI_SCS,
+ N_PCH_SPI_SCS_SMIWPEN
+ }
+ },
+ {
+ {
+ {
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ (SPI_BASE_ADDRESS + R_PCH_SPI_SCS)
+ },
+ S_PCH_SPI_SCS,
+ N_PCH_SPI_SCS_SMIWPST
+ }
+ }
+ },
+ ///
+ /// IchnMcSmi
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// 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
+ ///
+ {
+ 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
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnMonSmi6
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnMonSmi5
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnMonSmi4
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap13
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap12, KBC_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap11
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap10
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap9, PIRQDH_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap8, PIRQCG_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap7, PIRQBF_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap6, PIRQAE_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap5
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap3
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap2
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap1
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap0, IDE_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// 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.
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// PCH I/O Trap register 2 monitor
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// PCH I/O Trap register 1 monitor
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// PCH I/O Trap register 0 monitor
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+};
+
+PCH_SMM_SOURCE_DESC ICHN_SOURCE_DESCS_AX[NUM_ICHN_TYPES] = {
+ ///
+ /// IchnMch
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// IchnPme
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// 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_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// IchnAc97Wake
+ /// Not supported,
+ /// 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_ILB
+ }
+ }
+ },
+ ///
+ /// IchnY2KRollover
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// 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,
+ R_PCH_TCO_STS
+ },
+ S_PCH_TCO_STS,
+ N_PCH_TCO_STS_TIMEOUT
+ }
+ }
+ },
+ ///
+ /// IchnOsTco
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// IchnNmi
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_PCH_SMI_EN
+ },
+ S_PCH_SMI_EN,
+ N_PCH_SMI_EN_TCO
+ },
+ {
+ {
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ (ILB_BASE_ADDRESS + R_PCH_ILB_GNMI)
+ },
+ S_PCH_ILB_GNMI,
+ N_PCH_ILB_GNMI_NMI2SMIEN
+ }
+ },
+ {
+ {
+ {
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ (ILB_BASE_ADDRESS + R_PCH_ILB_GNMI)
+ },
+ S_PCH_ILB_GNMI,
+ N_PCH_ILB_GNMI_NMI2SMIST
+ }
+ }
+ },
+ ///
+ /// IchnIntruderDetect
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// IchnBiosWp
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_PCH_SMI_EN
+ },
+ S_PCH_SMI_EN,
+ N_PCH_SMI_EN_TCO
+ },
+ {
+ {
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ (SPI_BASE_ADDRESS + R_PCH_SPI_SCS)
+ },
+ S_PCH_SPI_SCS,
+ N_PCH_SPI_SCS_SMIWPEN
+ }
+ },
+ {
+ {
+ {
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ (SPI_BASE_ADDRESS + R_PCH_SPI_SCS)
+ },
+ S_PCH_SPI_SCS,
+ N_PCH_SPI_SCS_SMIWPST
+ }
+ }
+ },
+ ///
+ /// IchnMcSmi
+ ///
+ {
+ PCH_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// 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
+ ///
+ {
+ 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
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnMonSmi6
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnMonSmi5
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnMonSmi4
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap13
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap12, KBC_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap11
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap10
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap9, PIRQDH_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap8, PIRQCG_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap7, PIRQBF_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap6, PIRQAE_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap5
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap3
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap2
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap1
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// IchnDevTrap0, IDE_ACT_STS
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// 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.
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// PCH I/O Trap register 2 monitor
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// PCH I/O Trap register 1 monitor
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// PCH I/O Trap register 0 monitor
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+};
+
+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,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+ ///
+ /// 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
+ }
+ }
+ },
+
+};
+
+///
+/// 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_ACPI_GPE0a_STS
+ },
+ S_PCH_ACPI_GPE0a_STS,
+ N_PCH_ACPI_GPE0a_STS_TCO
+ }
+ }
+};
+
+PCH_SMM_SOURCE_DESC TCO_STS_AX = {
+ 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
+
+**/
+VOID
+EFIAPI
+PchSmmIchnClearSource (
+ PCH_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ 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
+ ///
+ if (SocStepping () < SocB0) {
+ PchSmmClearSource (&TCO_STS_AX);
+ } else {
+ PchSmmClearSource (&TCO_STS);
+ }
+}
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c
new file mode 100644
index 0000000000..c8e43f2d86
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmPeriodicTimer.c
@@ -0,0 +1,555 @@
+/** @file
+ File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PchSmmHelpers.h"
+
+//
+// There is only one instance for PeriodicTimerCommBuffer.
+// It's safe in SMM since there is no re-entry for the function.
+//
+EFI_SMM_PERIODIC_TIMER_CONTEXT mPchPeriodicTimerCommBuffer;
+
+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
+
+**/
+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.
+
+**/
+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
+ ///
+#if (defined X64_BUILD_SUPPORT) && (X64_BUILD_SUPPORT == 1)
+ Record->MiscData.ElapsedTime += TimerInterval->Interval;
+#else
+ Record->MiscData.ElapsedTime += (UINT32)TimerInterval->Interval;
+#endif
+ *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
+ )
+{
+ DATABASE_RECORD *Record;
+ Record = DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext);
+
+ if (Record->MiscData.ElapsedTime >= ChildContext->PeriodicTimer.Period) {
+ ///
+ /// This child should be dispatched
+ /// Need reset ElapsedTime, or SMI handler will be invoked during SmiTickInterval instead of Period.
+ ///
+ ///
+ /// For EDKII, the ElapsedTime is reset when PeriodicTimerGetCommBuffer
+ ///
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Gather the CommBuffer information of SmmPeriodicTimerDispatch2.
+
+ @param[in] Record No use
+ @param[out] CommBuffer Point to the CommBuffer structure
+ @param[out] CommBufferSize Point to the Size of CommBuffer structure
+
+**/
+VOID
+EFIAPI
+PeriodicTimerGetCommBuffer (
+ IN DATABASE_RECORD *Record,
+ OUT VOID **CommBuffer,
+ OUT UINTN *CommBufferSize
+ )
+{
+ ASSERT (Record->ProtocolType == PeriodicTimerType);
+
+ mPchPeriodicTimerCommBuffer.ElapsedTime = Record->MiscData.ElapsedTime;
+
+ ///
+ /// For EDKII, the ElapsedTime is reset here
+ ///
+ Record->MiscData.ElapsedTime = 0;
+
+ ///
+ /// Return the CommBuffer
+ ///
+ *CommBuffer = (VOID *) &mPchPeriodicTimerCommBuffer;
+ *CommBufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);
+}
+
+/**
+ Program Smm Periodic Timer
+
+**/
+VOID
+PchSmmPeriodicTimerProgramTimers (
+ VOID
+ )
+{
+ UINT8 GenPmCon1;
+ UINT8 GenPmCon2;
+ SUPPORTED_TIMER Timer;
+ DATABASE_RECORD *RecordInDb;
+ LIST_ENTRY *LinkInDb;
+ UINTN PciD31F0RegBase;
+ UINT32 PmcBase;
+ TIMER_INTERVAL *TimerInterval;
+
+ PciD31F0RegBase = MmPciAddress (0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ 0
+ );
+ PmcBase = MmioRead32 (PciD31F0RegBase + R_PCH_LPC_PMC_BASE) & B_PCH_LPC_PMC_BASE_BAR;
+ ///
+ /// 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);
+ CpuDeadLoop ();
+ }
+
+ 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) {
+ GenPmCon2 = MmioRead8 (PmcBase + R_PCH_PMC_GEN_PMCON_2);
+
+ GenPmCon2 &= ~B_PCH_PMC_GEN_PMCON_PER_SMI_SEL;
+ switch (mTimers[PERIODIC_TIMER].MinReqInterval) {
+ case TIME_64s:
+ GenPmCon2 |= V_PCH_PMC_GEN_PMCON_PER_SMI_64S;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;
+ break;
+
+ case TIME_32s:
+ GenPmCon2 |= V_PCH_PMC_GEN_PMCON_PER_SMI_32S;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;
+ break;
+
+ case TIME_16s:
+ GenPmCon2 |= V_PCH_PMC_GEN_PMCON_PER_SMI_16S;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;
+ break;
+
+ case TIME_8s:
+ GenPmCon2 |= V_PCH_PMC_GEN_PMCON_PER_SMI_8S;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ MmioWrite8 (PmcBase + R_PCH_PMC_GEN_PMCON_2, GenPmCon2);
+
+ ///
+ /// 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
+ ///
+ GenPmCon1 = MmioRead8 (PmcBase + R_PCH_PMC_GEN_PMCON_1);
+ GenPmCon1 &= ~B_PCH_PMC_GEN_PMCON_SWSMI_RTSL;
+ switch (mTimers[SWSMI_TIMER].MinReqInterval) {
+ case TIME_64ms:
+ GenPmCon1 |= V_PCH_PMC_GEN_PMCON_SWSMI_RTSL_64MS;
+ mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_64ms;
+ break;
+
+ case TIME_32ms:
+ GenPmCon1 |= V_PCH_PMC_GEN_PMCON_SWSMI_RTSL_32MS;
+ mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_32ms;
+ break;
+
+ case TIME_16ms:
+ GenPmCon1 |= V_PCH_PMC_GEN_PMCON_SWSMI_RTSL_16MS;
+ mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_16ms;
+ break;
+
+ case TIME_1_5ms:
+ GenPmCon1 |= V_PCH_PMC_GEN_PMCON_SWSMI_RTSL_1_5MS;
+ mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_1_5ms;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ MmioWrite8 (PmcBase + R_PCH_PMC_GEN_PMCON_1, GenPmCon1);
+
+ ///
+ /// 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 CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,
+ IN OUT UINT64 **SmiTickInterval
+ )
+{
+ TIMER_INTERVAL *IntervalPointer;
+
+ if (SmiTickInterval == NULL) {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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.
+
+**/
+VOID
+EFIAPI
+PchSmmPeriodicTimerClearSource (
+ IN PCH_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ PchSmmPeriodicTimerProgramTimers ();
+}
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmPowerButton.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmPowerButton.c
new file mode 100644
index 0000000000..efe8c61fc0
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmPowerButton.c
@@ -0,0 +1,95 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Power Button dispatch protocol.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <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.
+
+**/
+VOID
+EFIAPI
+PowerButtonGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT PCH_SMM_CONTEXT *Context
+ )
+{
+ UINT16 GenPmCon2;
+ UINT32 PmcBase;
+
+ PmcBase = MmioRead32 (
+ MmPciAddress (0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ R_PCH_LPC_PMC_BASE
+ )
+ ) & B_PCH_LPC_PMC_BASE_BAR;
+
+ GenPmCon2 = MmioRead16 (PmcBase + R_PCH_PMC_GEN_PMCON_2);
+
+ if ((GenPmCon2 & B_PCH_PMC_GEN_PMCON_PWRBTN_LVL) == 0) {
+ Context->PowerButton.Phase = EfiPowerButtonExit;
+ } else {
+ Context->PowerButton.Phase = EfiPowerButtonEntry;
+ }
+}
+
+/**
+ 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/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmSw.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmSw.c
new file mode 100644
index 0000000000..eedc3b811c
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmSw.c
@@ -0,0 +1,161 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Sw dispatch protocol.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PchSmmHelpers.h"
+#include "PlatformBaseAddresses.h"
+#include <Protocol/SmmCpu.h>
+//
+// There is only one instance for SwCommBuffer.
+// It's safe in SMM since there is no re-entry for the function.
+//
+EFI_SMM_SW_CONTEXT mPchSwCommBuffer;
+EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol;
+
+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
+
+**/
+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);
+}
+/**
+ Gather the CommBuffer information of SmmSwDispatch2.
+
+ @param[in] Record No use
+ @param[out] CommBuffer Point to the CommBuffer structure
+ @param[out] CommBufferSize Point to the Size of CommBuffer structure
+
+**/
+VOID
+EFIAPI
+SwGetCommBuffer (
+ IN DATABASE_RECORD *Record,
+ OUT VOID **CommBuffer,
+ OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_SAVE_STATE_IO_INFO SmiIoInfo;
+ UINTN Index;
+
+ ASSERT (Record->ProtocolType == SwType);
+
+ mPchSwCommBuffer.CommandPort = IoRead8 (R_PCH_APM_CNT);
+ mPchSwCommBuffer.DataPort = IoRead8 (R_PCH_APM_STS);
+
+ //
+ // Try to find which CPU trigger SWSMI
+ //
+ mPchSwCommBuffer.SwSmiCpuIndex = 0;
+ for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
+ Status = mSmmCpuProtocol->ReadSaveState (
+ mSmmCpuProtocol,
+ sizeof(EFI_SMM_SAVE_STATE_IO_INFO),
+ EFI_SMM_SAVE_STATE_REGISTER_IO,
+ Index,
+ &SmiIoInfo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ if (SmiIoInfo.IoPort == R_PCH_APM_CNT) {
+ //
+ // Find matched CPU.
+ //
+ mPchSwCommBuffer.SwSmiCpuIndex = Index;
+ break;
+ }
+ }
+
+ ///
+ /// Return the CommBuffer
+ ///
+ *CommBuffer = (VOID *) &mPchSwCommBuffer;
+ *CommBufferSize = sizeof (EFI_SMM_SW_CONTEXT);
+}
+
+/**
+ Init required protocol for Pch Sw Dispatch protocol.
+
+**/
+VOID
+PchSwDispatchInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ //
+ // Locate PI SMM CPU protocol
+ //
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **)&mSmmCpuProtocol);
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmSx.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmSx.c
new file mode 100644
index 0000000000..daa7ad86f7
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmSx.c
@@ -0,0 +1,257 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Sx dispatch protocol.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PchSmmHelpers.h"
+#ifndef PROGRESS_CODE_S3_SUSPEND_END
+#define PROGRESS_CODE_S3_SUSPEND_END (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000001))
+#endif
+#include <Library/ReportStatusCodeLib.h>
+
+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
+
+**/
+VOID
+EFIAPI
+SxGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT PCH_SMM_CONTEXT *Context
+ )
+{
+ UINT32 Pm1Cnt;
+
+ Pm1Cnt = IoRead32 ((UINTN) (AcpiBase + 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);
+}
+
+/**
+ Additional xHCI Controller Configurations Prior to Entering S3/S4/S5
+
+**/
+VOID
+XhciSxWorkaround (
+ VOID
+ )
+{
+ UINTN PciD31F0RegBase;
+ UINT32 PmcBase;
+ UINTN XhciPciMmBase;
+
+ PciD31F0RegBase = MmPciAddress (0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ 0
+ );
+ PmcBase = MmioRead32 (PciD31F0RegBase + R_PCH_LPC_PMC_BASE) & B_PCH_LPC_PMC_BASE_BAR;
+ ///
+ /// Check if XHCI controller is enabled
+ ///
+ if ((MmioRead32 (PmcBase + R_PCH_PMC_FUNC_DIS) & (UINT32) B_PCH_PMC_FUNC_DIS_USH) != 0) {
+ return ;
+ }
+ XhciPciMmBase = MmPciAddress (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_PCH,
+ PCI_DEVICE_NUMBER_PCH_XHCI,
+ PCI_FUNCTION_NUMBER_PCH_XHCI,
+ 0
+ );
+ ///
+ /// 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.
+
+**/
+VOID
+PchSmmSxGoToSleep (
+ VOID
+ )
+{
+ UINT32 Pm1Cnt;
+
+ ///
+ /// 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) (AcpiBase + R_PCH_ACPI_PM1_CNT));
+
+ 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, PcdGet32 (PcdProgressCodeS3SuspendEnd));
+
+ //
+ // Flush cache into memory before we go to sleep
+ //
+ AsmWbinvd ();
+ }
+ ///
+ /// CHV BIOS Spec, Section 18.2.6
+ /// Additional Programming Requirements prior to enter S4/S5
+ ///
+ 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 ();
+ }
+ ///
+ /// 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) (AcpiBase + 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) (AcpiBase + R_PCH_ACPI_PM1_STS))) & B_PCH_ACPI_PM1_STS_WAK) == 0x0);
+ } else {
+ CpuDeadLoop ();
+ }
+ ///
+ /// 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) (AcpiBase + 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) (AcpiBase + R_PCH_ACPI_PM1_CNT), Pm1Cnt);
+ }
+
+ PchSmmClearSource (&SX_SOURCE_DESC);
+ PchSmmEnableSource (&SX_SOURCE_DESC);
+}
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmUsb.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmUsb.c
new file mode 100644
index 0000000000..4fba82cc5e
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchSmmUsb.c
@@ -0,0 +1,249 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm USB dispatch protocol.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PchSmmHelpers.h"
+#include <Protocol/PciRootBridgeIo.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 mUSB2_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_ILB
+ }
+ }
+};
+
+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_USB
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_PCH_SMI_STS
+ },
+ S_PCH_SMI_STS,
+ N_PCH_SMI_STS_LEGACY_USB
+ }
+ }
+};
+
+typedef enum {
+ PchUsbControllerLpc0 = 0,
+ 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_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.
+
+
+**/
+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 *) (&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) {
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+}
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchxSmmHelpers.c b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchxSmmHelpers.c
new file mode 100644
index 0000000000..6cb899ea44
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchxSmmHelpers.c
@@ -0,0 +1,730 @@
+/** @file
+ This driver is responsible for the registration of child drivers
+ and the abstraction of the PCH SMI sources.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PchSmmHelpers.h"
+
+//
+// Help handle porting bit shifts to IA-64.
+//
+#define BIT_ZERO 0x00000001
+
+/**
+ Publish SMI Dispatch protocols.
+
+**/
+VOID
+PchSmmPublishDispatchProtocols (
+ VOID
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ UINTN Index;
+ //
+ // Install protocol interfaces.
+ //
+ for (Index = 0; Index < PchSmmProtocolTypeMax; Index++) {
+ Status = gSmst->SmmInstallProtocolInterface (
+ &mPrivateData.InstallMultProtHandle,
+ mPrivateData.Protocols[Index].Guid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.Protocols[Index].Protocols.Generic
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Initialize bits that aren't necessarily related to an SMI source.
+
+ @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.
+
+ @retval EFI_SUCCESS Enable Global Smi Bit completed
+**/
+EFI_STATUS
+PchSmmEnableGlobalSmiBit (
+ VOID
+ )
+{
+ UINT32 SmiEn;
+
+ SmiEn = IoRead32 ((UINTN) (AcpiBase + R_PCH_SMI_EN));
+
+ ///
+ /// Set the "global smi enable" bit
+ ///
+ SmiEn |= B_PCH_SMI_EN_GBL_SMI;
+
+ IoWrite32 ((UINTN) (AcpiBase + 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.
+
+ @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 Gpe0aStsLow;
+ UINT32 SmiSts;
+ UINT16 AltGpiSmiSts;
+ UINT32 TcoSts;
+
+ ///
+ /// Determine whether an ACPI OS is present (via the SCI_EN bit)
+ ///
+ Pm1Cnt = IoRead32 ((UINTN) (AcpiBase + 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) (AcpiBase + R_PCH_ACPI_PM1_STS));
+ Gpe0aStsLow = IoRead32 ((UINTN) (AcpiBase + R_PCH_ACPI_GPE0a_STS));
+
+ Pm1Sts |=
+ (
+ B_PCH_ACPI_PM1_STS_WAK |
+#ifdef PCIESC_SUPPORT
+ B_PCH_ACPI_PM1_STS_WAK_PCIE |
+#endif
+ 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
+ );
+
+ Gpe0aStsLow |=
+ (
+ B_PCH_ACPI_GPE0a_STS_TCO |
+ B_PCH_ACPI_GPE0a_STS_PME_B0 |
+ B_PCH_ACPI_GPE0a_STS_BATLOW |
+#ifdef PCIESC_SUPPORT
+ B_PCH_ACPI_GPE0a_STS_PCI_EXP |
+ B_PCH_ACPI_GPE0a_STS_PCIE_WAKE3 |
+ B_PCH_ACPI_GPE0a_STS_PCIE_WAKE2 |
+ B_PCH_ACPI_GPE0a_STS_PCIE_WAKE1 |
+ B_PCH_ACPI_GPE0a_STS_PCIE_WAKE0 |
+#endif
+ B_PCH_ACPI_GPE0a_STS_GUNIT_SCI |
+ B_PCH_ACPI_GPE0a_STS_PUNIT_SCI |
+ B_PCH_ACPI_GPE0a_STS_SWGPE |
+ B_PCH_ACPI_GPE0a_STS_HOT_PLUG |
+ B_PCH_ACPI_GPE0a_STS_PMU_WAKEB
+ );
+
+ IoWrite16 ((UINTN) (AcpiBase + R_PCH_ACPI_PM1_STS), (UINT16) Pm1Sts);
+ IoWrite32 ((UINTN) (AcpiBase + R_PCH_ACPI_GPE0a_STS), (UINT32) Gpe0aStsLow);
+ }
+ ///
+ /// Clear all SMIs that are unaffected by SCI_EN
+ ///
+ AltGpiSmiSts = IoRead16 ((UINTN) (AcpiBase + R_PCH_ALT_GP_SMI_STS));
+ SmiSts = IoRead32 ((UINTN) (AcpiBase + R_PCH_SMI_STS));
+ TcoSts = IoRead32 ((UINTN) (AcpiBase + R_PCH_TCO_STS));
+
+ SmiSts |=
+ (
+ B_PCH_SMI_STS_SMBUS |
+ B_PCH_SMI_STS_PERIODIC |
+ B_PCH_SMI_STS_TCO |
+ B_PCH_SMI_STS_SWSMI_TMR |
+ B_PCH_SMI_STS_APM |
+ B_PCH_SMI_STS_ON_SLP_EN |
+ B_PCH_SMI_STS_BIOS
+ );
+ AltGpiSmiSts |= (B_PCH_ALT_GP_SMI_STS_CORE_GPIO | B_PCH_ALT_GP_SMI_STS_SUS_GPIO);
+
+ TcoSts |=
+ (
+ B_PCH_TCO_STS_SECOND_TO |
+ B_PCH_TCO_STS_TIMEOUT
+ );
+
+ IoWrite16 ((UINTN) (AcpiBase + R_PCH_ALT_GP_SMI_STS), AltGpiSmiSts);
+
+ IoWrite32 ((UINTN) (AcpiBase + R_PCH_TCO_STS), TcoSts);
+
+ IoWrite32 ((UINTN) (AcpiBase + R_PCH_SMI_STS), SmiSts);
+
+ ///
+ /// 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.
+
+ @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) (AcpiBase + R_PCH_SMI_EN));
+
+ ///
+ /// Reset the PCH to generate subsequent SMIs
+ ///
+ SmiEn |= B_PCH_SMI_EN_EOS;
+
+ IoWrite32 ((UINTN) (AcpiBase + R_PCH_SMI_EN), SmiEn);
+
+ ///
+ /// Double check that the assert worked
+ ///
+ SmiEn = IoRead32 ((UINTN) (AcpiBase + 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)
+
+ @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) (AcpiBase + 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;
+#ifdef PCIESC_SUPPORT
+ UINT32 PciBus;
+ UINT32 PciDev;
+ UINT32 PciFun;
+ UINT32 PciReg;
+#endif
+ UINTN RegSize;
+ BOOLEAN BitWasOne;
+ UINTN ShiftCount;
+ UINTN RegisterOffset;
+
+ if ((BitDesc == NULL) ||
+ IS_BIT_DESC_NULL (*BitDesc)) {
+ ASSERT (FALSE);
+ return FALSE;
+ }
+
+ RegSize = 0;
+ Register = 0;
+ ShiftCount = 0;
+ BitWasOne = FALSE;
+
+ switch (BitDesc->Reg.Type) {
+ case ACPI_ADDR_TYPE:
+ 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 ((AcpiBase != 0x0) && ((AcpiBase & B_PCH_LPC_ACPI_BASE_EN) != B_PCH_LPC_ACPI_BASE_EN));
+
+ RegisterOffset = BitDesc->Reg.Data.acpi;
+ 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 = gSmst->SmmIo.Io.Read (
+ &gSmst->SmmIo,
+ RegSize,
+ AcpiBase + 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;
+
+#ifdef PCIESC_SUPPORT
+ 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;
+#endif
+
+ 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
+
+
+**/
+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;
+#ifdef PCIESC_SUPPORT
+ UINT32 PciBus;
+ UINT32 PciDev;
+ UINT32 PciFun;
+ UINT32 PciReg;
+#endif
+ UINTN RegisterOffset;
+
+ ASSERT (BitDesc != NULL);
+
+ if ((BitDesc == NULL) ||
+ IS_BIT_DESC_NULL (*BitDesc))
+ {
+ ASSERT (FALSE);
+ return;
+ }
+
+ 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:
+ 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 ((AcpiBase != 0x0) && ((AcpiBase & B_PCH_LPC_ACPI_BASE_EN) != B_PCH_LPC_ACPI_BASE_EN));
+
+ RegisterOffset = BitDesc->Reg.Data.acpi;
+ ///
+ /// 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 = gSmst->SmmIo.Io.Read (
+ &gSmst->SmmIo,
+ RegSize,
+ AcpiBase + RegisterOffset,
+ 1,
+ &Register
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Register &= AndVal;
+ Register |= OrVal;
+
+ Status = gSmst->SmmIo.Io.Write (
+ &gSmst->SmmIo,
+ RegSize,
+ AcpiBase + 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;
+
+#ifdef PCIESC_SUPPORT
+ 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;
+#endif
+
+ default:
+ ///
+ /// This address type is not yet implemented
+ ///
+ ASSERT (FALSE);
+ break;
+ }
+}
diff --git a/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchxSmmHelpers.h b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchxSmmHelpers.h
new file mode 100644
index 0000000000..fccd7bcc48
--- /dev/null
+++ b/ChvRefCodePkg/CherryViewSoc/SouthCluster/PchSmiDispatcher/Smm/PchxSmmHelpers.h
@@ -0,0 +1,112 @@
+/** @file
+ This driver is responsible for the registration of child drivers
+ and the abstraction of the PCH SMI sources.
+
+ Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php.
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PCHX_SMM_HELPERS_H_
+#define _PCHX_SMM_HELPERS_H_
+
+#include "PchSmm.h"
+#include <Library/PchPlatformLib.h>
+
+/**
+ Initialize bits that aren't necessarily related to an SMI source.
+
+ @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.
+
+ @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.
+
+ @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.
+
+ @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)
+
+ @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
+
+**/
+VOID
+WriteBitDesc (
+ CONST PCH_SMM_BIT_DESC *BitDesc,
+ CONST BOOLEAN ValueToWrite,
+ CONST BOOLEAN WriteClear
+ );
+
+#endif