summaryrefslogtreecommitdiff
path: root/Silicon
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-12-23 12:55:24 +0800
committerGuo Mang <mang.guo@intel.com>2016-12-26 19:15:07 +0800
commit1f6e7e4d497661bebaa19884106997ee35201d14 (patch)
treec20058600615103d12fa19da481592fee4b1b9fe /Silicon
parent99ff4022da8518a288b6c02bc7492267ce34c114 (diff)
downloadedk2-platforms-1f6e7e4d497661bebaa19884106997ee35201d14.tar.xz
ScSmiDispatcher
Diffstat (limited to 'Silicon')
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmiDispatcher.inf85
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmm.h793
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmCore.c754
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmGpi.c45
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmHelpers.c314
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmHelpers.h146
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmIchn.c515
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmPeriodicTimer.c574
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmPowerButton.c95
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmSw.c172
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmSx.c262
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmUsb.c230
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScxSmmHelpers.c806
-rw-r--r--Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScxSmmHelpers.h128
14 files changed, 4919 insertions, 0 deletions
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmiDispatcher.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmiDispatcher.inf
new file mode 100644
index 0000000000..9ba40ca088
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmiDispatcher.inf
@@ -0,0 +1,85 @@
+## @file
+# Sc Smi Dispatcher driver.
+#
+# Copyright (c) 2012 - 2016, 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 = ScSmiDispatcher
+ FILE_GUID = 6BE18C9C-BF61-499e-88EC-5CD57430460C
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = InitializeScSmmDispatcher
+
+[sources.common]
+ ScSmm.h
+ ScSmmCore.c
+ ScSmmHelpers.h
+ ScSmmHelpers.c
+ ScxSmmHelpers.h
+ ScxSmmHelpers.c
+ ScSmmUsb.c
+ ScSmmGpi.c
+ ScSmmPowerButton.c
+ ScSmmSw.c
+ ScSmmSx.c
+ ScSmmIchn.c
+ ScSmmPeriodicTimer.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ IoLib
+ DebugLib
+ PcdLib
+ BaseLib
+ BaseMemoryLib
+ DevicePathLib
+ ScPlatformLib
+ SmmServicesTableLib
+ ReportStatusCodeLib
+ PerformanceLib
+ DxeServicesTableLib
+ GpioLib
+ SteppingLib
+
+[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
+ gEfiBxtTokenSpaceGuid.PcdScAcpiIoPortBaseAddress ## SOMETIMES_CONSUMES
+ gEfiBxtTokenSpaceGuid.PcdPmcGcrBaseAddress ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiSmmCpuProtocolGuid AND
+ gEfiSmmBase2ProtocolGuid AND
+ gEfiPciRootBridgeIoProtocolGuid
+
+[BuildOptions]
+ *_*_X64_CC_FLAGS = -D X64_BUILD_SUPPORT = 1
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmm.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmm.h
new file mode 100644
index 0000000000..ef6274a1ef
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmm.h
@@ -0,0 +1,793 @@
+/** @file
+ Prototypes and defines for the SC SMM Dispatcher.
+
+ Copyright (c) 2012 - 2016, 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 _SC_SMM_H_
+#define _SC_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 <ScAccess.h>
+#include <Library/GpioLib.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,
+ ScSmmProtocolTypeMax
+} SC_SMM_PROTOCOL_TYPE;
+
+///
+/// SPECIFYING A REGISTER
+/// We want a general way of referring to addresses. For this case, we'll only
+/// need addresses in the ACPI table (and the TCO entries within the ACPI table).
+/// However, it's interesting to consider what it would take to support other types
+/// of addresses. To address Will's concern, I think it prudent to accommodate it
+/// early on in the design.
+///
+/// Addresses we need to consider:
+///
+/// Type: Required:
+/// I/O Yes
+/// ACPI (special case of I/O) Only if we want to
+/// TCO (special case of ACPI) Only if we want to
+/// GPIO (special case of MMIO) Only if we want to
+/// Memory (or Memory Mapped I/O) Only if we want to
+///
+#ifdef PCIESC_SUPPORT
+typedef enum {
+ ACPI_ADDR_TYPE,
+ GPIO_ADDR_TYPE,
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ PCIE_ADDR_TYPE,
+ PCR_ADDR_TYPE,
+ NUM_ADDR_TYPES, ///< count of items in this enum
+ SC_SMM_ADDR_TYPE_NULL = -1 ///< sentinel to indicate NULL or to signal end of arrays
+} ADDR_TYPE;
+#else
+typedef enum {
+ ACPI_ADDR_TYPE,
+ GPIO_ADDR_TYPE,
+ MEMORY_MAPPED_IO_ADDRESS_TYPE,
+ PCR_ADDR_TYPE,
+ NUM_ADDR_TYPES, ///< count of items in this enum
+ SC_SMM_ADDR_TYPE_NULL = -1 ///< sentinel to indicate NULL or to signal end of arrays
+} ADDR_TYPE;
+#endif
+
+///
+/// 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;
+typedef MEM_ADDR *GPIO_ADDR;
+
+#ifdef PCIESC_SUPPORT
+typedef union {
+ UINT32 Raw;
+ struct {
+ UINT8 Reg;
+ UINT8 Fnc;
+ UINT8 Dev;
+ UINT8 Bus;
+ } Fields;
+} PCIE_ADDR;
+#endif
+
+typedef union {
+ UINT32 Raw;
+ struct {
+ UINT16 Offset;
+ UINT8 Pid;
+ UINT8 Base;
+ } Fields;
+} PCR_ADDR;
+
+typedef struct {
+ ADDR_TYPE Type;
+ union {
+ ///
+ /// used to initialize during declaration/definition
+ ///
+ UINT32 raw;
+
+ ///
+ /// used to access useful data
+ ///
+ IO_ADDR io;
+ ACPI_ADDR acpi;
+ TCO_ADDR tco;
+ MEM_ADDR mem;
+ MEMORY_MAPPED_IO_ADDRESS Mmio;
+#ifdef PCIESC_SUPPORT
+ PCIE_ADDR pcie;
+#endif
+ PCR_ADDR Pcr;
+ } Data;
+
+} SC_SMM_ADDRESS;
+
+///
+/// SPECIFYING BITS WITHIN A REGISTER
+/// Here's a struct that helps us specify a source or enable bit.
+///
+typedef struct {
+ SC_SMM_ADDRESS Reg;
+ UINT8 SizeInBytes;
+ UINT8 Bit;
+} SC_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 == SC_SMM_ADDR_TYPE_NULL) // "returns" true when BitDesc is NULL
+#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type = SC_SMM_ADDR_TYPE_NULL) // will "return" an integer w/ value of 0
+#define NULL_BIT_DESC_INITIALIZER \
+ { \
+ { \
+ SC_SMM_ADDR_TYPE_NULL, \
+ { \
+ 0 \
+ } \
+ }, \
+ 0, 0 \
+ }
+//
+// The 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 SC_SMM_SOURCE_FLAGS;
+
+//
+// Flags required today
+//
+#define SC_SMM_NO_FLAGS 0
+#define SC_SMM_SCI_EN_DEPENDENT 1
+
+//
+// Flags that might be required tomorrow
+//
+typedef struct {
+ SC_SMM_SOURCE_FLAGS Flags;
+ SC_SMM_BIT_DESC En[NUM_EN_BITS]; ///< Describes the enable bit(s) for the SMI event
+ SC_SMM_BIT_DESC Sts[NUM_STS_BITS]; ///< Describes the secondary status bit for the SMI event. Might be the same as TopLevelSmi
+} SC_SMM_SOURCE_DESC;
+
+///
+/// Used to initialize null source descriptor
+///
+#define NULL_SOURCE_DESC_INITIALIZER \
+ { \
+ SC_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. The general type for these
+/// "GetContext" functions, so 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;
+} SC_SMM_CONTEXT;
+
+typedef union {
+ UINTN ElapsedTime;
+} SC_SMM_MISC_DATA;
+
+typedef struct _DATABASE_RECORD DATABASE_RECORD;
+
+/**
+ Get SMM context address
+
+ @param[in] Record The Database address
+ @param[out] Context The Smm Context address.
+
+ @retval None
+
+**/
+typedef
+VOID
+(EFIAPI *GET_CONTEXT) (
+ IN DATABASE_RECORD *Record,
+ OUT SC_SMM_CONTEXT *Context
+ );
+
+/**
+ Compare two buffer Context
+
+ @param[IN] Context1 Context1 buffer address.
+ @param[IN] Context2 Context2 buffer address.
+
+ @retval TRUE Context1 and Context2 is same.
+ @retval FALSE Context1 and Context2 is diffrent.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *CMP_CONTEXT) (
+ IN SC_SMM_CONTEXT *Context1,
+ IN SC_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[ScSmmProtocolTypeMax];
+
+/**
+ 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 SC_SMM_CONTEXT *Context,
+ OUT SC_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 SC_SMM_CONTEXT *DispatchContext,
+ OUT SC_SMM_SOURCE_DESC *SrcDesc
+ );
+
+///
+/// Mapping simple contexts can be done by assignment or lookup table
+///
+extern CONST SC_SMM_SOURCE_DESC SW_SOURCE_DESC;
+extern CONST SC_SMM_SOURCE_DESC SX_SOURCE_DESC;
+extern CONST SC_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:
+///
+extern CONST SC_SMM_SOURCE_DESC SC_GPI_SOURCE_DESC_TEMPLATE;
+extern SC_SMM_SOURCE_DESC ICHN_SOURCE_DESCS[NUM_ICHN_TYPES];
+extern SC_SMM_SOURCE_DESC ICHN_EX_SOURCE_DESCS[IchnExTypeMAX - IchnExPciExpress];
+
+///
+/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF.
+///
+#define MAXIMUM_SWI_VALUE 0xFF
+
+///
+/// GENERALIZING THE CALLBACK
+/// All SmmXxxDispatch callbacks have the same form:
+///
+/// VOID Callback( EFI_HANDLE, EFI_SMM_Xxx_DISPATCH_CONTEXT )
+/// We need a typedef that'll allow us to call any callback
+///
+/**
+ Clear the SMI status bit by set the source bit of SMI status register
+
+ @param[in] SrcDesc Pointer to the SC SMI source description table
+
+ @return None
+
+**/
+typedef
+VOID
+(EFIAPI *SC_SMM_CLEAR_SOURCE) (
+ IN SC_SMM_SOURCE_DESC *SrcDesc
+ );
+
+///
+/// "DATABASE" RECORD
+/// Linked list data structures
+///
+#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C')
+
+typedef struct _DATABASE_RECORD {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ BOOLEAN Processed;
+
+ ///
+ /// Status and Enable bit description
+ ///
+ SC_SMM_SOURCE_DESC SrcDesc;
+
+ ///
+ /// Callback function
+ ///
+ EFI_SMM_HANDLER_ENTRY_POINT2 Callback;
+ SC_SMM_CONTEXT ChildContext;
+
+ ///
+ /// Special handling hooks -- init them to NULL if unused/unneeded
+ ///
+ SC_SMM_CLEAR_SOURCE ClearSource;
+
+ ///
+ /// Functions required to make callback code general
+ ///
+ CONTEXT_FUNCTIONS ContextFunctions;
+
+ ///
+ /// The protocol that this record dispatches
+ ///
+ SC_SMM_PROTOCOL_TYPE ProtocolType;
+
+ ///
+ /// Misc data for private usage
+ ///
+ SC_SMM_MISC_DATA MiscData;
+
+} DATABASE_RECORD;
+
+#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)
+
+/**
+ Register a South Cluster child SMI dispatch function with a parent SMM driver.
+
+ @param[in] This Pointer to the SC_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.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_SMM_GENERIC_REGISTER) (
+ IN VOID **This,
+ IN VOID *DispatchFunction,
+ IN VOID *DispatchContext,
+ OUT EFI_HANDLE *DispatchHandle
+ );
+
+/**
+ Unregister a South Cluster 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.
+ @retval EFI_SUCCESS The function has been successfully unregistered child SMI source.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_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 {
+ SC_SMM_GENERIC_REGISTER Register;
+ SC_SMM_GENERIC_UNREGISTER Unregister;
+ UINTN Extra1;
+ UINTN Extra2; // may not need this one
+} SC_SMM_GENERIC_PROTOCOL;
+
+/**
+ Register a child SMI dispatch function with a parent SMM driver.
+
+ @param[in] This Pointer to the SC_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
+ScSmmCoreRegister (
+ IN SC_SMM_GENERIC_PROTOCOL *This,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
+ IN SC_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.
+ @retval EFI_SUCCESS The function has been successfully unregistered child SMI source.
+
+**/
+EFI_STATUS
+ScSmmCoreUnRegister (
+ IN SC_SMM_GENERIC_PROTOCOL *This,
+ IN EFI_HANDLE *DispatchHandle
+ );
+
+///
+/// South Cluster SMM Protocol
+///
+typedef union {
+ SC_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;
+} SC_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;
+
+ SC_SMM_PROTOCOL_TYPE Type;
+ EFI_GUID *Guid;
+ SC_SMM_PROTOCOL Protocols;
+} SC_SMM_QUALIFIED_PROTOCOL;
+
+#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \
+ CR ( \
+ _generic, \
+ SC_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;
+ SC_SMM_QUALIFIED_PROTOCOL Protocols[ScSmmProtocolTypeMax];
+} PRIVATE_DATA;
+
+extern PRIVATE_DATA mPrivateData;
+extern UINT16 AcpiBaseAddr;
+
+/**
+ 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 SC_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 SC_SMM_CONTEXT *Context1,
+ IN SC_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 SC_SMM_CONTEXT *Context
+ );
+
+/**
+ Init required protocol for Pch Sw Dispatch protocol.
+
+**/
+VOID
+ScSwDispatchInit (
+ 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 SC_SMM_CONTEXT *Context1,
+ IN SC_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 SC_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 SC_SMM_CONTEXT *Context1,
+ IN SC_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 SC_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 SC_SMM_CONTEXT *Context1,
+ IN SC_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 SC_SMM_SOURCE_DESC instance.
+
+**/
+VOID
+EFIAPI
+ScSmmPeriodicTimerClearSource (
+ IN SC_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
+ScSmmPeriodicTimerDispatchGetNextShorterInterval (
+ IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,
+ IN OUT UINT64 **SmiTickInterval
+ );
+
+VOID
+ScSmmSxGoToSleep (
+ VOID
+ );
+
+/**
+ Clear the SMI status bit after the SMI handling is done
+
+ @param[in] SrcDesc Pointer to the SC SMI source description table
+
+**/
+VOID
+EFIAPI
+ScSmmIchnClearSource (
+ IN SC_SMM_SOURCE_DESC *SrcDesc
+ );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmCore.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmCore.c
new file mode 100644
index 0000000000..c9a956677b
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmCore.c
@@ -0,0 +1,754 @@
+/** @file
+ This driver is responsible for the registration of child drivers
+ and the abstraction of the SC SMI sources.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.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
+//
+
+UINT16 AcpiBaseAddr;
+PRIVATE_DATA mPrivateData = { // for the structure
+ {
+ NULL
+ }, // CallbackDataBase linked list head
+ NULL, // Handler returned whan calling SmiHandlerRegister
+ NULL, // EFI handle returned when calling InstallMultipleProtocolInterfaces
+ { // protocol arrays
+ //
+ // elements within the array
+ //
+ {
+ PROTOCOL_SIGNATURE,
+ UsbType,
+ &gEfiSmmUsbDispatch2ProtocolGuid,
+ {
+ (SC_SMM_GENERIC_REGISTER) ScSmmCoreRegister,
+ (SC_SMM_GENERIC_UNREGISTER) ScSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ SxType,
+ &gEfiSmmSxDispatch2ProtocolGuid,
+ {
+ (SC_SMM_GENERIC_REGISTER) ScSmmCoreRegister,
+ (SC_SMM_GENERIC_UNREGISTER) ScSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ SwType,
+ &gEfiSmmSwDispatch2ProtocolGuid,
+ {
+ (SC_SMM_GENERIC_REGISTER) ScSmmCoreRegister,
+ (SC_SMM_GENERIC_UNREGISTER) ScSmmCoreUnRegister,
+ (UINTN) MAXIMUM_SWI_VALUE
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ GpiType,
+ &gEfiSmmGpiDispatch2ProtocolGuid,
+ {
+ (SC_SMM_GENERIC_REGISTER) ScSmmCoreRegister,
+ (SC_SMM_GENERIC_UNREGISTER) ScSmmCoreUnRegister,
+ (UINTN) V_GPIO_NUM_SUPPORTED_GPIS
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ IchnType,
+ &gEfiSmmIchnDispatchProtocolGuid,
+ {
+ (SC_SMM_GENERIC_REGISTER) ScSmmCoreRegister,
+ (SC_SMM_GENERIC_UNREGISTER) ScSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ IchnExType,
+ &gEfiSmmIchnDispatchExProtocolGuid,
+ {
+ (SC_SMM_GENERIC_REGISTER) ScSmmCoreRegister,
+ (SC_SMM_GENERIC_UNREGISTER) ScSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ PowerButtonType,
+ &gEfiSmmPowerButtonDispatch2ProtocolGuid,
+ {
+ (SC_SMM_GENERIC_REGISTER) ScSmmCoreRegister,
+ (SC_SMM_GENERIC_UNREGISTER) ScSmmCoreUnRegister
+ }
+ },
+ {
+ PROTOCOL_SIGNATURE,
+ PeriodicTimerType,
+ &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,
+ {
+ (SC_SMM_GENERIC_REGISTER) ScSmmCoreRegister,
+ (SC_SMM_GENERIC_UNREGISTER) ScSmmCoreUnRegister,
+ (UINTN) ScSmmPeriodicTimerDispatchGetNextShorterInterval
+ }
+ },
+ }
+};
+
+CONTEXT_FUNCTIONS mContextFunctions[ScSmmProtocolTypeMax] = {
+ {
+ 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
+ScSmmCoreDispatcher (
+ IN EFI_HANDLE SmmImageHandle,
+ IN CONST VOID *ContextData, OPTIONAL
+ IN OUT VOID *CommunicationBuffer, OPTIONAL
+ IN OUT UINTN *SourceSize OPTIONAL
+ );
+
+
+/**
+ Initializes the SC 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
+InitializeScSmmDispatcher (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ //
+ // Read ACPI Base Address
+ //
+ AcpiBaseAddr = (UINT16) PcdGet16 (PcdScAcpiIoPortBaseAddress);
+ ASSERT (AcpiBaseAddr != 0);
+
+ //
+ // Init required protocol for SC Sw Dispatch protocol.
+ //
+ ScSwDispatchInit ();
+
+ //
+ // Register a callback function to handle subsequent SMIs. This callback
+ // will be called by SmmCoreDispatcher.
+ //
+ Status = gSmst->SmiHandlerRegister (ScSmmCoreDispatcher, NULL, &mPrivateData.SmiHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize Callback DataBase
+ //
+ InitializeListHead (&mPrivateData.CallbackDataBase);
+ ScSmmPublishDispatchProtocols ();
+
+ //
+ // Enable SMIs on the SC now that we have a callback
+ //
+ ScSmmInitHardware ();
+
+ 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 (
+ IN 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 SC_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
+ScSmmCoreRegister (
+ IN SC_SMM_GENERIC_PROTOCOL *This,
+ IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
+ IN SC_SMM_CONTEXT *DispatchContext,
+ OUT EFI_HANDLE *DispatchHandle
+ )
+{
+ EFI_STATUS Status;
+
+ DATABASE_RECORD *Record;
+ SC_SMM_QUALIFIED_PROTOCOL *Qualified;
+ SC_SMM_SOURCE_DESC NullSourceDesc = NULL_SOURCE_DESC_INITIALIZER;
+ UINTN Index;
+ UINT8 GpiSmiBitOffset;
+ UINT32 GpiSmiEnRegAddress;
+ UINT32 GpiSmiStsRegAddress;
+
+ Index = 0;
+ //
+ // Create database record and add to database
+ //
+ if (gSmst == NULL) {
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ 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 (SC_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 (SC_SMM_SOURCE_DESC));
+ Record->ClearSource = NULL;
+ //
+ // use default clear source function
+ //
+ break;
+
+ case GpiType:
+ Index = (UINTN) Record->ChildContext.Gpi.GpiNum;
+ Status = GpioGetPadAndSmiRegs (
+ (UINT32) Index,
+ &GpiSmiBitOffset,
+ &GpiSmiEnRegAddress,
+ &GpiSmiStsRegAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
+ CopyMem (
+ (VOID *) &(Record->SrcDesc),
+ (VOID *) &(SC_GPI_SOURCE_DESC_TEMPLATE),
+ sizeof (SC_SMM_SOURCE_DESC)
+ );
+ Record->SrcDesc.En[0].Reg.Data.raw = GpiSmiEnRegAddress; // GPI SMI Enable register
+ Record->SrcDesc.En[0].Bit = GpiSmiBitOffset; // Bit position for selected pad
+ Record->SrcDesc.Sts[0].Reg.Data.raw = GpiSmiStsRegAddress; // GPI SMI Status register
+ Record->SrcDesc.Sts[0].Bit = GpiSmiBitOffset; // Bit position for selected pad
+ 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);
+ CopyMem (
+ (VOID *) &(Record->SrcDesc),
+ (VOID *) &(ICHN_SOURCE_DESCS[Record->ChildContext.Ichn.Type]),
+ sizeof (SC_SMM_SOURCE_DESC)
+ );
+ Record->ClearSource = ScSmmIchnClearSource;
+ 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 (SC_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 (SC_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 = ScSmmPeriodicTimerClearSource;
+ 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
+ //
+ ScSmmClearSource (&Record->SrcDesc);
+ } else {
+ //
+ // This source requires special handling to clear
+ //
+ Record->ClearSource (&Record->SrcDesc);
+ }
+
+ ScSmmEnableSource (&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);
+ 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.
+ @retval EFI_SUCCESS The function has been successfully unregistered child SMI source.
+
+**/
+EFI_STATUS
+ScSmmCoreUnRegister (
+ IN SC_SMM_GENERIC_PROTOCOL *This,
+ IN EFI_HANDLE *DispatchHandle
+ )
+{
+ DATABASE_RECORD *RecordToDelete;
+
+ 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 SMM image handle
+ @param[in] ContextData Not used
+ @param[in, out] CommunicationBuffer Not used
+ @param[in, out] SourceSize Not used
+
+ @retval EFI_SUCCESS Function successfully completed
+
+**/
+EFI_STATUS
+EFIAPI
+ScSmmCoreDispatcher (
+ 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;
+ SC_SMM_CONTEXT Context;
+ VOID *CommBuffer;
+ UINTN CommBufferSize;
+ EFI_STATUS Status;
+ SC_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 = ScSmmSetAndCheckEos ();
+ }
+ } 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 (SC_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
+ //
+ ScSmmClearSource (&ActiveSource);
+ } else {
+ //
+ // This source requires special handling to clear
+ //
+ RecordInDb->ClearSource (&ActiveSource);
+ }
+ //
+ // Also, try to clear EOS
+ //
+ EosSet = ScSmmSetAndCheckEos ();
+ //
+ // Queue is empty, reset the search
+ //
+ break;
+ }
+ }
+ }
+ }
+ ScBeforeExitSmi ();
+ if (SxChildWasDispatched) {
+ ScSmmSxGoToSleep ();
+ }
+
+ return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmGpi.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmGpi.c
new file mode 100644
index 0000000000..195288edf2
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmGpi.c
@@ -0,0 +1,45 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Gpi dispatch protocol.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.h"
+
+//
+//
+// Structure for GPI SMI is a template which needs to have
+// GPI Smi bit offset and Smi Status & Enable registers updated (accordingly
+// to choosen group and pad number) after adding it to SMM Callback database
+//
+CONST SC_SMM_SOURCE_DESC SC_GPI_SOURCE_DESC_TEMPLATE = {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ GPIO_ADDR_TYPE, 0x0
+ },
+ S_GPIO_GP_SMI_EN, 0x0,
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ GPIO_ADDR_TYPE, 0x0
+ },
+ S_GPIO_GP_SMI_STS, 0x0,
+ },
+ }
+};
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmHelpers.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmHelpers.c
new file mode 100644
index 0000000000..8e504032dd
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmHelpers.c
@@ -0,0 +1,314 @@
+/** @file
+ Helper functions for SC SMM dispatcher.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.h"
+
+//
+// #define BIT_ZERO 0x00000001
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 BIT_ZERO = 0x00000001;
+
+//
+// SUPPORT / HELPER FUNCTIONS (SC version-independent)
+//
+/**
+ Compare 2 SMM source descriptors' enable settings.
+
+ @param[in] Src1 Pointer to the SC SMI source description table 1
+ @param[in] Src2 Pointer to the SC 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 SC_SMM_SOURCE_DESC *Src1,
+ CONST IN SC_SMM_SOURCE_DESC *Src2
+ )
+{
+ BOOLEAN IsEqual;
+ UINTN DescIndex;
+
+ IsEqual = TRUE;
+ for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
+ //
+ // 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[DescIndex].Bit != Src2->En[DescIndex].Bit ||
+ Src1->En[DescIndex].Reg.Type != Src2->En[DescIndex].Reg.Type ||
+ Src1->En[DescIndex].Reg.Data.raw != Src2->En[DescIndex].Reg.Data.raw
+ ) {
+ IsEqual = FALSE;
+ break;
+ //
+ // out of for loop
+ //
+ }
+ }
+
+ return IsEqual;
+}
+
+
+/**
+ Compare 2 SMM source descriptors' statuses.
+
+ @param[in] Src1 Pointer to the SC SMI source description table 1
+ @param[in] Src2 Pointer to the SC 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 (
+ IN CONST SC_SMM_SOURCE_DESC *Src1,
+ IN CONST SC_SMM_SOURCE_DESC *Src2
+ )
+{
+ BOOLEAN IsEqual;
+ UINTN DescIndex;
+
+ IsEqual = TRUE;
+ for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
+ //
+ // 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[DescIndex].Bit != Src2->Sts[DescIndex].Bit ||
+ Src1->Sts[DescIndex].Reg.Type != Src2->Sts[DescIndex].Reg.Type ||
+ Src1->Sts[DescIndex].Reg.Data.raw != Src2->Sts[DescIndex].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 SC SMI source description table 1
+ @param[in] Src2 Pointer to the SC 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 (
+ IN CONST SC_SMM_SOURCE_DESC *Src1,
+ IN CONST SC_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 SC SMI source description table
+
+ @retval TRUE It is active.
+ @retval FALSE It is inactive.
+
+**/
+BOOLEAN
+SourceIsActive (
+ const IN SC_SMM_SOURCE_DESC *Src
+ )
+{
+ BOOLEAN IsActive;
+ UINTN loopvar;
+ BOOLEAN SciEn;
+
+ IsActive = TRUE;
+ SciEn = ScSmmGetSciEn ();
+
+ if ((Src->Flags & SC_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 SC SMI source description table
+
+**/
+VOID
+ScSmmEnableSource (
+ IN CONST SC_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ UINTN DescIndex;
+
+ //
+ // Set enables to 1 by writing a 1
+ //
+ for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
+ if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {
+ WriteBitDesc (&SrcDesc->En[DescIndex], 1, FALSE);
+ }
+ }
+ //
+ // Clear statuses to 0 by writing a 1
+ //
+ for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
+ if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
+ WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
+ }
+ }
+}
+
+
+/**
+ Disable the SMI source event by clear the SMI enable bit
+
+ @param[in] SrcDesc Pointer to the SC SMI source description table
+
+**/
+VOID
+ScSmmDisableSource (
+ IN CONST SC_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ UINTN DescIndex;
+
+ for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
+ if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {
+ WriteBitDesc (&SrcDesc->En[DescIndex], 0, FALSE);
+ }
+ }
+}
+
+
+/**
+ Clear the SMI status bit by set the source bit of SMI status register
+
+ @param[in] SrcDesc Pointer to the SC SMI source description table
+
+**/
+VOID
+ScSmmClearSource (
+ IN CONST SC_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ UINTN DescIndex;
+
+ for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
+ if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
+ WriteBitDesc (&SrcDesc->Sts[DescIndex], 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 SC SMI source description table
+
+**/
+VOID
+ScSmmClearSourceAndBlock (
+ IN CONST SC_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ UINTN DescIndex;
+ BOOLEAN IsSet;
+
+ for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
+ if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
+ //
+ // Write the bit
+ //
+ WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
+
+ //
+ // Don't return until the bit actually clears.
+ //
+ IsSet = TRUE;
+ while (IsSet) {
+ IsSet = ReadBitDesc (&SrcDesc->Sts[DescIndex]);
+ //
+ // IsSet will eventually clear -- or else we'll have
+ // an infinite loop.
+ //
+ }
+ }
+ }
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmHelpers.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmHelpers.h
new file mode 100644
index 0000000000..7b1467577d
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmHelpers.h
@@ -0,0 +1,146 @@
+/** @file
+ Helper functions for SC SMM
+
+ Copyright (c) 2012 - 2016, 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 SC_SMM_HELPERS_H
+#define SC_SMM_HELPERS_H
+
+#include "ScSmm.h"
+#include "ScxSmmHelpers.h"
+
+//
+// SUPPORT / HELPER FUNCTIONS (SC version-independent)
+//
+/**
+ Publish SMI Dispatch protocols.
+
+**/
+VOID
+ScSmmPublishDispatchProtocols (
+ VOID
+ );
+
+/**
+ Compare 2 SMM source descriptors' enable settings.
+
+ @param[in] Src1 Pointer to the SC SMI source description table 1
+ @param[in] Src2 Pointer to the SC 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 SC_SMM_SOURCE_DESC *Src1,
+ CONST IN SC_SMM_SOURCE_DESC *Src2
+ );
+
+/**
+ Compare 2 SMM source descriptors' statuses.
+
+ @param[in] Src1 Pointer to the SC SMI source description table 1
+ @param[in] Src2 Pointer to the SC 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 (
+ IN CONST SC_SMM_SOURCE_DESC *Src1,
+ IN CONST SC_SMM_SOURCE_DESC *Src2
+ );
+
+/**
+ Compare 2 SMM source descriptors, based on Enable settings and Status settings of them.
+
+ @param[in] Src1 Pointer to the SC SMI source description table 1
+ @param[in] Src2 Pointer to the SC 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 (
+ IN CONST SC_SMM_SOURCE_DESC *Src1,
+ IN CONST SC_SMM_SOURCE_DESC *Src2
+ );
+
+/**
+ Check if an SMM source is active.
+
+ @param[in] Src Pointer to the SC SMI source description table
+
+ @retval TRUE It is active.
+ @retval FALSE It is inactive.
+
+**/
+BOOLEAN
+SourceIsActive (
+ IN CONST SC_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 SC SMI source description table
+
+**/
+VOID
+ScSmmEnableSource (
+ IN CONST SC_SMM_SOURCE_DESC *SrcDesc
+ );
+
+/**
+ Disable the SMI source event by clear the SMI enable bit
+
+ @param[in] SrcDesc Pointer to the SC SMI source description table
+
+**/
+VOID
+ScSmmDisableSource (
+ IN CONST SC_SMM_SOURCE_DESC *SrcDesc
+ );
+
+/**
+ Clear the SMI status bit by set the source bit of SMI status register
+
+ @param[in] SrcDesc Pointer to the SC SMI source description table
+
+**/
+VOID
+ScSmmClearSource (
+ IN CONST SC_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 SC SMI source description table
+
+**/
+VOID
+ScSmmClearSourceAndBlock (
+ IN CONST SC_SMM_SOURCE_DESC *SrcDesc
+ );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmIchn.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmIchn.c
new file mode 100644
index 0000000000..aeb3b1538a
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmIchn.c
@@ -0,0 +1,515 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Ichn dispatch protocol.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.h"
+#include "PlatformBaseAddresses.h"
+
+SC_SMM_SOURCE_DESC ICHN_SOURCE_DESCS[NUM_ICHN_TYPES] = {
+ ///
+ /// IchnMch
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnPme
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnRtcAlarm
+ ///
+ {
+ SC_SMM_SCI_EN_DEPENDENT,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_ACPI_PM1_EN
+ },
+ S_ACPI_PM1_EN,
+ N_ACPI_PM1_EN_RTC
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_ACPI_PM1_STS
+ },
+ S_ACPI_PM1_STS,
+ N_ACPI_PM1_STS_RTC
+ }
+ }
+ },
+
+ ///
+ /// IchnRingIndicate
+ ///
+ {
+ SC_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.
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnSerialIrq
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_STS
+ },
+ S_SMI_STS,
+ N_SMI_STS_SERIRQ
+ }
+ }
+ },
+
+ ///
+ /// IchnY2KRollover
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnTcoTimeout
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_EN
+ },
+ S_SMI_EN,
+ N_SMI_EN_TCO
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_STS
+ },
+ S_SMI_STS,
+ N_SMI_STS_TCO
+ }
+ }
+ },
+
+ ///
+ /// IchnOsTco
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnNmi
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_EN
+ },
+ S_SMI_EN,
+ N_SMI_EN_TCO
+ },
+
+ {
+ {
+ PCR_ADDR_TYPE,
+ SC_PCR_ADDRESS (0xD0, R_PCR_ITSS_NMICSTS)
+ },
+ S_PCR_ITSS_NMICSTS,
+ N_PCR_ITSS_NMI2SMIEN
+ }
+ },
+
+ {
+ {
+ {
+ PCR_ADDR_TYPE,
+ SC_PCR_ADDRESS (0xD0, R_PCR_ITSS_NMICSTS)
+ },
+ S_PCR_ITSS_NMICSTS,
+ N_PCR_ITSS_NMI2SMISTS
+ }
+ }
+ },
+
+ ///
+ /// IchnIntruderDetect
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnBiosWp
+ ///
+#ifdef PCIESC_SUPPORT
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_EN
+ },
+ S_SMI_EN,
+ N_SMI_EN_SPI_SSMI
+ },
+
+ {
+ {
+ PCIE_ADDR_TYPE,
+ {
+ (DEFAULT_PCI_BUS_NUMBER_SC << 24) |
+ (PCI_DEVICE_NUMBER_SPI << 16) |
+ (PCI_FUNCTION_NUMBER_SPI << 8) |
+ R_SPI_BCR
+ }
+ },
+ S_SPI_BCR,
+ N_SPI_BCR_BLE
+ }
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_STS
+ },
+ S_SMI_STS,
+ N_SMI_STS_SPI_SSMI
+ }
+ }
+ },
+#else
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+#endif
+
+ ///
+ /// IchnMcSmi
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnPmeB0
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnThrmSts
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnIntelUsb2
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// 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,
+ ///
+ /// SC I/O Trap register 3 monitor,
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// SC I/O Trap register 2 monitor
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// SC I/O Trap register 1 monitor
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+ ///
+ /// SC I/O Trap register 0 monitor
+ ///
+ NULL_SOURCE_DESC_INITIALIZER,
+};
+
+
+SC_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
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ NULL_BIT_DESC_INITIALIZER,
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ NULL_BIT_DESC_INITIALIZER
+ }
+ },
+
+ ///
+ /// IchnExTmrOverflow
+ ///
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_ACPI_PM1_EN
+ },
+ S_ACPI_PM1_EN,
+ N_ACPI_PM1_EN_TMROF
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_ACPI_PM1_STS
+ },
+ S_ACPI_PM1_STS,
+ N_ACPI_PM1_STS_TMROF
+ }
+ }
+ },
+};
+
+
+/**
+ Clear the SMI status bit after the SMI handling is done
+
+ @param[in] SrcDesc Pointer to the SC SMI source description table
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+ScSmmIchnClearSource (
+ IN SC_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ ScSmmClearSource (SrcDesc);
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmPeriodicTimer.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmPeriodicTimer.c
new file mode 100644
index 0000000000..a7d69fa7e3
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmPeriodicTimer.c
@@ -0,0 +1,574 @@
+/** @file
+ File to contain all the hardware specific stuff for the Periodical Timer dispatch protocol.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.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];
+
+SC_SMM_SOURCE_DESC mTIMER_SOURCE_DESCS[NUM_TIMERS] = {
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_EN
+ },
+ S_SMI_EN,
+ N_SMI_EN_PERIODIC
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_STS
+ },
+ S_SMI_STS,
+ N_SMI_STS_PERIODIC
+ }
+ }
+ },
+
+ {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_EN
+ },
+ S_SMI_EN,
+ N_SMI_EN_SWSMI_TMR
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_STS
+ },
+ S_SMI_STS,
+ N_SMI_STS_SWSMI_TMR
+ }
+ }
+ }
+};
+
+
+VOID
+ScSmmPeriodicTimerProgramTimers (
+ 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 SC_SMM_CONTEXT *DispatchContext
+ )
+{
+ UINTN loopvar;
+
+ //
+ // Determine which timer this child is using
+ //
+ for (loopvar = 0; loopvar < NUM_INTERVALS; loopvar++) {
+ if (((DispatchContext->PeriodicTimer.SmiTickInterval == 0) &&
+ (DispatchContext->PeriodicTimer.Period >= mSmmPeriodicTimerIntervals[loopvar].Interval)) ||
+ (DispatchContext->PeriodicTimer.SmiTickInterval == mSmmPeriodicTimerIntervals[loopvar].Interval)) {
+ return &mSmmPeriodicTimerIntervals[loopvar];
+ }
+ }
+ //
+ // If this assertion fires, then either:
+ // (1) the context contains an invalid interval
+ // (2) the timer interval table is corrupt
+ //
+ ASSERT (FALSE);
+
+ return NULL;
+}
+
+
+/**
+ Figure out which timer the child is requesting and
+ send back the source description
+
+ @param[in] DispatchContext The pointer to the Dispatch Context instances
+ @param[out] SrcDesc The pointer to the source description
+
+ @retval None
+
+**/
+VOID
+MapPeriodicTimerToSrcDesc (
+ IN SC_SMM_CONTEXT *DispatchContext,
+ OUT SC_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 (SC_SMM_SOURCE_DESC)
+ );
+
+ //
+ // Program the value of the interval into hardware
+ //
+ ScSmmPeriodicTimerProgramTimers ();
+}
+
+
+/**
+ Update the elapsed time from the Interval data of DATABASE_RECORD
+
+ @param[in] Record The pointer to the DATABASE_RECORD.
+ @param[out] HwContext The Context to be updated.
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+PeriodicTimerGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT SC_SMM_CONTEXT *HwContext
+ )
+{
+ TIMER_INTERVAL *TimerInterval;
+
+ ASSERT (Record->ProtocolType == PeriodicTimerType);
+
+ TimerInterval = ContextToTimerInterval (&Record->ChildContext);
+ if (TimerInterval == NULL) {
+ return;
+ }
+
+ //
+ // Ignore the hardware context. It's not required for this protocol.
+ // Instead, just increment the child's context.
+ // Update the elapsed time w/ the data from our tables
+ //
+ Record->MiscData.ElapsedTime += (UINTN) TimerInterval->Interval;
+ *HwContext = Record->ChildContext;
+}
+
+
+/**
+ Check whether Periodic Timer of two contexts match
+
+ @param[in] Context1 Context 1 that includes Periodic Timer 1
+ @param[in] Context2 Context 2 that includes Periodic Timer 2
+
+ @retval FALSE Periodic Timer match
+ @retval TRUE Periodic Timer don't match
+
+**/
+BOOLEAN
+EFIAPI
+PeriodicTimerCmpContext (
+ IN SC_SMM_CONTEXT *HwContext,
+ IN SC_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
+ScSmmPeriodicTimerProgramTimers (
+ VOID
+ )
+{
+ UINT8 GenPmCon1;
+ UINT8 GenPmCon2;
+ SUPPORTED_TIMER Timer;
+ DATABASE_RECORD *RecordInDb;
+ LIST_ENTRY *LinkInDb;
+ UINT32 PmcBase;
+ TIMER_INTERVAL *TimerInterval;
+
+ PmcBase = PMC_BASE_ADDRESS;
+ //
+ // 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 ();
+ return;
+ }
+
+ 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_PMC_GEN_PMCON_2);
+
+ GenPmCon2 &= ~B_PMC_GEN_PMCON_PER_SMI_SEL;
+ switch (mTimers[PERIODIC_TIMER].MinReqInterval) {
+ case TIME_64s:
+ GenPmCon2 |= V_PMC_GEN_PMCON_PER_SMI_64S;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;
+ break;
+
+ case TIME_32s:
+ GenPmCon2 |= V_PMC_GEN_PMCON_PER_SMI_32S;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;
+ break;
+
+ case TIME_16s:
+ GenPmCon2 |= V_PMC_GEN_PMCON_PER_SMI_16S;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;
+ break;
+
+ case TIME_8s:
+ GenPmCon2 |= V_PMC_GEN_PMCON_PER_SMI_8S;
+ mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ MmioWrite8 (PmcBase + R_PMC_GEN_PMCON_2, GenPmCon2);
+
+ //
+ // Restart the timer here, just need to clear the SMI
+ //
+ ScSmmClearSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
+ } else {
+ ScSmmDisableSource (&mTIMER_SOURCE_DESCS[PERIODIC_TIMER]);
+ }
+
+ if (mTimers[SWSMI_TIMER].NumChildren > 0) {
+ //
+ // ICH9, ICH10 and SC share the same bit positions for SW SMI Rate settings
+ //
+ GenPmCon1 = MmioRead8 (PmcBase + R_PMC_GEN_PMCON_1);
+ GenPmCon1 &= ~B_PMC_GEN_PMCON_SWSMI_RTSL;
+ switch (mTimers[SWSMI_TIMER].MinReqInterval) {
+ case TIME_64ms:
+ GenPmCon1 |= V_PMC_GEN_PMCON_SWSMI_RTSL_64MS;
+ mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_64ms;
+ break;
+
+ case TIME_32ms:
+ GenPmCon1 |= V_PMC_GEN_PMCON_SWSMI_RTSL_32MS;
+ mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_32ms;
+ break;
+
+ case TIME_16ms:
+ GenPmCon1 |= V_PMC_GEN_PMCON_SWSMI_RTSL_16MS;
+ mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_16ms;
+ break;
+
+ case TIME_1_5ms:
+ GenPmCon1 |= V_PMC_GEN_PMCON_SWSMI_RTSL_1_5MS;
+ mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_1_5ms;
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ MmioWrite8 (PmcBase + R_PMC_GEN_PMCON_1, GenPmCon1);
+
+ //
+ // Restart the timer here, need to disable, clear, then enable to restart this timer
+ //
+ ScSmmDisableSource (&mTIMER_SOURCE_DESCS[SWSMI_TIMER]);
+ ScSmmClearSource (&mTIMER_SOURCE_DESCS[SWSMI_TIMER]);
+ ScSmmEnableSource (&mTIMER_SOURCE_DESCS[SWSMI_TIMER]);
+ } else {
+ ScSmmDisableSource (&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
+ScSmmPeriodicTimerDispatchGetNextShorterInterval (
+ 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 SC_SMM_SOURCE_DESC instance.
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+ScSmmPeriodicTimerClearSource (
+ IN SC_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ ScSmmPeriodicTimerProgramTimers ();
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmPowerButton.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmPowerButton.c
new file mode 100644
index 0000000000..497ca74a1b
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmPowerButton.c
@@ -0,0 +1,95 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Power Button dispatch protocol.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.h"
+
+CONST SC_SMM_SOURCE_DESC POWER_BUTTON_SOURCE_DESC = {
+ SC_SMM_SCI_EN_DEPENDENT,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_ACPI_PM1_EN
+ },
+ S_ACPI_PM1_EN,
+ N_ACPI_PM1_EN_PWRBTN
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_ACPI_PM1_STS
+ },
+ S_ACPI_PM1_STS,
+ N_ACPI_PM1_STS_PWRBTN
+ }
+ }
+};
+
+
+/**
+ Get the power button status.
+
+ @param[in] Record The pointer to the DATABASE_RECORD.
+ @param[out] Context Calling context from the hardware, will be updated with the current power button status.
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+PowerButtonGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT SC_SMM_CONTEXT *Context
+ )
+{
+ UINT16 GenPmCon2;
+ UINT32 PmcBase;
+
+ PmcBase = PMC_BASE_ADDRESS;
+
+ GenPmCon2 = MmioRead16 (PmcBase + R_PMC_GEN_PMCON_2);
+
+ if ((GenPmCon2 & B_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 SC_SMM_CONTEXT *Context1,
+ IN SC_SMM_CONTEXT *Context2
+ )
+{
+ return (BOOLEAN) (Context1->PowerButton.Phase == Context2->PowerButton.Phase);
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmSw.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmSw.c
new file mode 100644
index 0000000000..dab2309fc2
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmSw.c
@@ -0,0 +1,172 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Sw dispatch protocol.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.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 mScSwCommBuffer;
+EFI_SMM_CPU_PROTOCOL *mSmmCpuProtocol;
+
+CONST SC_SMM_SOURCE_DESC SW_SOURCE_DESC = {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_EN
+ },
+ S_SMI_EN,
+ N_SMI_EN_APMC
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_STS
+ },
+ S_SMI_STS,
+ N_SMI_STS_APM
+ }
+ }
+};
+
+
+/**
+ Get the Software Smi value
+
+ @param[in] Record No use
+ @param[in] Context The context that includes Software Smi value to be filled
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+SwGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT SC_SMM_CONTEXT *Context
+ )
+{
+ UINT8 ApmCnt;
+
+ ApmCnt = IoRead8 ((UINTN) R_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 SC_SMM_CONTEXT *Context1,
+ IN SC_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);
+
+ mScSwCommBuffer.CommandPort = IoRead8 (R_APM_CNT);
+ mScSwCommBuffer.DataPort = IoRead8 (R_APM_STS);
+
+ //
+ // Try to find which CPU trigger SWSMI
+ //
+ mScSwCommBuffer.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_APM_CNT) {
+ //
+ // Find matched CPU.
+ //
+ mScSwCommBuffer.SwSmiCpuIndex = Index;
+ break;
+ }
+ }
+
+ //
+ // Return the CommBuffer
+ //
+ *CommBuffer = (VOID *) &mScSwCommBuffer;
+ *CommBufferSize = sizeof (EFI_SMM_SW_CONTEXT);
+}
+
+
+/**
+ Init required protocol for Sc Sw Dispatch protocol.
+
+**/
+VOID
+ScSwDispatchInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ //
+ // Locate PI SMM CPU protocol
+ //
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, (VOID **) &mSmmCpuProtocol);
+ ASSERT_EFI_ERROR (Status);
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmSx.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmSx.c
new file mode 100644
index 0000000000..e1aa7fdcde
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmSx.c
@@ -0,0 +1,262 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm Sx dispatch protocol.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.h"
+
+#ifndef PROGRESS_CODE_S3_SUSPEND_END
+#define PROGRESS_CODE_S3_SUSPEND_END (EFI_SOFTWARE_SMM_DRIVER | (EFI_OEM_SPECIFIC | 0x00000001))
+#endif
+
+const SC_SMM_SOURCE_DESC SX_SOURCE_DESC = {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_EN
+ },
+ S_SMI_EN,
+ N_SMI_EN_ON_SLP_EN
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_STS
+ },
+ S_SMI_STS,
+ N_SMI_STS_ON_SLP_EN
+ }
+ }
+};
+
+
+/**
+ Get the Sleep type
+
+ @param[in] Record No use
+ @param[out] Context The context that includes SLP_TYP bits to be filled
+
+ @retval None
+
+**/
+VOID
+EFIAPI
+SxGetContext (
+ IN DATABASE_RECORD *Record,
+ OUT SC_SMM_CONTEXT *Context
+ )
+{
+ UINT32 Pm1Cnt;
+
+ Pm1Cnt = IoRead32 ((UINTN) (AcpiBaseAddr + R_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_ACPI_PM1_CNT_SLP_TYP) {
+ case V_ACPI_PM1_CNT_S0:
+ Context->Sx.Type = SxS0;
+ break;
+
+ case V_ACPI_PM1_CNT_S1:
+ Context->Sx.Type = SxS1;
+ break;
+
+ case V_ACPI_PM1_CNT_S3:
+ Context->Sx.Type = SxS3;
+ break;
+
+ case V_ACPI_PM1_CNT_S4:
+ Context->Sx.Type = SxS4;
+ break;
+
+ case V_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 SC_SMM_CONTEXT *Context1,
+ IN SC_SMM_CONTEXT *Context2
+ )
+{
+ return (BOOLEAN) (Context1->Sx.Type == Context2->Sx.Type);
+}
+
+typedef struct {
+ UINT8 Device;
+ UINT8 Function;
+} USB_CONTROLLER;
+
+
+/**
+ Additional xHCI Controller Configurations Prior to Entering S3/S4/S5
+
+ @param[in] None
+
+ @retval None
+
+**/
+VOID
+XhciSxWorkaround (
+ VOID
+ )
+{
+ UINT32 PmcBase;
+ UINTN XhciPciMmBase;
+
+ PmcBase = PMC_BASE_ADDRESS;
+
+ //
+ // Check if XHCI controller is enabled
+ //
+ if ((MmioRead32 (PmcBase + R_PMC_FUNC_DIS) & (UINT32) B_PMC_FUNC_DIS_USB_XHCI) != 0) {
+ return;
+ }
+ XhciPciMmBase = MmPciAddress (
+ 0,
+ DEFAULT_PCI_BUS_NUMBER_SC,
+ PCI_DEVICE_NUMBER_XHCI,
+ PCI_FUNCTION_NUMBER_XHCI,
+ 0
+ );
+ //
+ // Set "PME Enable" bit of PWR_CNTL_STS register, D20:F0:74h[8] = 1h
+ //
+ MmioOr16 ((XhciPciMmBase + R_XHCI_PWR_CNTL_STS), (UINT16) (B_XHCI_PWR_CNTL_STS_PME_EN));
+}
+
+
+/**
+ When we get an SMI that indicates that we are transitioning to a sleep state,
+ we need to actually transition to that state. We do this by disabling the
+ "SMI on sleep enable" feature, which generates an SMI when the operating system
+ tries to put the system to sleep, and then physically putting the system to sleep.
+
+ @param[in] None
+
+ @retval None
+
+**/
+VOID
+ScSmmSxGoToSleep (
+ 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
+ //
+ ScSmmClearSource (&SX_SOURCE_DESC);
+ ScSmmDisableSource (&SX_SOURCE_DESC);
+
+ //
+ // Get Power Management 1 Control Register Value
+ //
+ Pm1Cnt = IoRead32 ((UINTN) (AcpiBaseAddr + R_ACPI_PM1_CNT));
+
+ if (((Pm1Cnt & B_ACPI_PM1_CNT_SLP_TYP) == V_ACPI_PM1_CNT_S3) ||
+ ((Pm1Cnt & B_ACPI_PM1_CNT_SLP_TYP) == V_ACPI_PM1_CNT_S4) ||
+ ((Pm1Cnt & B_ACPI_PM1_CNT_SLP_TYP) == V_ACPI_PM1_CNT_S5)) {
+ XhciSxWorkaround ();
+ }
+ if (((Pm1Cnt & B_ACPI_PM1_CNT_SLP_TYP) == V_ACPI_PM1_CNT_S3) ||
+ ((Pm1Cnt & B_ACPI_PM1_CNT_SLP_TYP) == V_ACPI_PM1_CNT_S4) ||
+ ((Pm1Cnt & B_ACPI_PM1_CNT_SLP_TYP) == V_ACPI_PM1_CNT_S5)) {
+ }
+ //
+ // Record S3 suspend performance data
+ //
+ if ((Pm1Cnt & B_ACPI_PM1_CNT_SLP_TYP) == V_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_ACPI_PM1_CNT_SLP_EN;
+ IoWrite32 ((UINTN) (AcpiBaseAddr + R_ACPI_PM1_CNT), Pm1Cnt);
+
+ //
+ // Should only proceed if wake event is generated.
+ //
+ if ((Pm1Cnt & B_ACPI_PM1_CNT_SLP_TYP) == V_ACPI_PM1_CNT_S1) {
+ while (((IoRead16 ((UINTN) (AcpiBaseAddr + R_ACPI_PM1_STS))) & B_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) (AcpiBaseAddr + R_ACPI_PM1_CNT));
+
+ if ((Pm1Cnt & B_ACPI_PM1_CNT_SCI_EN) == 0) {
+ //
+ // An ACPI OS isn't present, clear the sleep information
+ //
+ Pm1Cnt &= ~B_ACPI_PM1_CNT_SLP_TYP;
+ Pm1Cnt |= V_ACPI_PM1_CNT_S0;
+
+ IoWrite32 ((UINTN) (AcpiBaseAddr + R_ACPI_PM1_CNT), Pm1Cnt);
+ }
+
+ ScSmmClearSource (&SX_SOURCE_DESC);
+ ScSmmEnableSource (&SX_SOURCE_DESC);
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmUsb.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmUsb.c
new file mode 100644
index 0000000000..ea512121ef
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScSmmUsb.c
@@ -0,0 +1,230 @@
+/** @file
+ File to contain all the hardware specific stuff for the Smm USB dispatch protocol.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.h"
+#include <Protocol/PciRootBridgeIo.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED SC_SMM_SOURCE_DESC mUSB1_LEGACY = {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_EN
+ },
+ S_SMI_EN,
+ N_SMI_EN_LEGACY_USB
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_STS
+ },
+ S_SMI_STS,
+ N_SMI_STS_LEGACY_USB
+ }
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED SC_SMM_SOURCE_DESC mUSB3_LEGACY = {
+ SC_SMM_NO_FLAGS,
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_EN
+ },
+ S_SMI_EN,
+ N_SMI_EN_LEGACY_USB3
+ },
+ NULL_BIT_DESC_INITIALIZER
+ },
+
+ {
+ {
+ {
+ ACPI_ADDR_TYPE,
+ R_SMI_STS
+ },
+ S_SMI_STS,
+ N_SMI_STS_LEGACY_USB3
+ }
+ }
+};
+
+typedef enum {
+ ScUsbControllerLpc0 = 0,
+ ScUsbControllerXhci,
+ ScUsbControllerTypeMax
+} SC_USB_CONTROLLER_TYPE;
+
+typedef struct {
+ UINT8 Function;
+ UINT8 Device;
+ SC_USB_CONTROLLER_TYPE UsbConType;
+} USB_CONTROLLER;
+
+GLOBAL_REMOVE_IF_UNREFERENCED USB_CONTROLLER mUsbControllersMap[] = {
+ {
+ PCI_FUNCTION_NUMBER_PCH_LPC,
+ PCI_DEVICE_NUMBER_PCH_LPC,
+ ScUsbControllerLpc0
+ },
+
+ {
+ PCI_FUNCTION_NUMBER_XHCI,
+ PCI_DEVICE_NUMBER_XHCI,
+ ScUsbControllerXhci
+ }
+};
+
+
+/**
+ 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
+ @retval EFI_UNSUPPORTED Invalid device Path table or can't find any match USB device path
+ SC_USB_CONTROLLER_TYPE The USB controller type of the input
+ device path
+
+**/
+EFI_STATUS
+DevicePathToSupportedController (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT SC_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[out] SrcDesc The source description that corresponds to the given context.
+
+ @retval None
+
+**/
+VOID
+MapUsbToSrcDesc (
+ IN SC_SMM_CONTEXT *Context,
+ OUT SC_SMM_SOURCE_DESC *SrcDesc
+ )
+{
+ SC_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 ScUsbControllerLpc0:
+ CopyMem ((VOID *) SrcDesc, (VOID *) (&mUSB1_LEGACY), sizeof (SC_SMM_SOURCE_DESC));
+ break;
+
+ case ScUsbControllerXhci:
+ CopyMem ((VOID *) SrcDesc, (VOID *) (&mUSB3_LEGACY), sizeof (SC_SMM_SOURCE_DESC));
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ break;
+
+ case UsbWake:
+ ASSERT (FALSE);
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScxSmmHelpers.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScxSmmHelpers.c
new file mode 100644
index 0000000000..ef8144901b
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScxSmmHelpers.c
@@ -0,0 +1,806 @@
+/** @file
+ This driver is responsible for the registration of child drivers
+ and the abstraction of the SC SMI sources.
+
+ Copyright (c) 2012 - 2016, 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 "ScSmmHelpers.h"
+
+//
+// Help handle porting bit shifts to IA-64.
+//
+#define BIT_ZERO 0x00000001
+
+/**
+ Publish SMI Dispatch protocols.
+
+**/
+VOID
+ScSmmPublishDispatchProtocols (
+ VOID
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ UINTN Index;
+ //
+ // Install protocol interfaces.
+ //
+ for (Index = 0; Index < ScSmmProtocolTypeMax; 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
+ScSmmInitHardware (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Clear all SMIs
+ //
+ ScSmmClearSmi ();
+
+ Status = ScSmmEnableGlobalSmiBit ();
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enables the SC 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
+ScSmmEnableGlobalSmiBit (
+ VOID
+ )
+{
+ UINT32 SmiEn;
+
+ SmiEn = IoRead32 ((UINTN) (AcpiBaseAddr + R_SMI_EN));
+
+ //
+ // Set the "global smi enable" bit
+ //
+ SmiEn |= B_SMI_EN_GBL_SMI;
+ IoWrite32 ((UINTN) (AcpiBaseAddr + R_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
+ScSmmClearSmi (
+ VOID
+ )
+{
+ BOOLEAN EosSet;
+ BOOLEAN SciEn;
+ UINT32 Pm1Cnt;
+ UINT16 Pm1Sts;
+ UINT32 Gpe0aStsLow;
+ UINT32 SmiSts;
+ UINT32 TcoSts;
+
+ //
+ // Determine whether an ACPI OS is present (via the SCI_EN bit)
+ //
+ Pm1Cnt = IoRead32 ((UINTN) (AcpiBaseAddr + R_ACPI_PM1_CNT));
+ SciEn = (BOOLEAN) ((Pm1Cnt & B_ACPI_PM1_CNT_SCI_EN) == B_ACPI_PM1_CNT_SCI_EN);
+ if (!SciEn) {
+ //
+ // Clear any SMIs that double as SCIs (when SCI_EN==0)
+ //
+ Pm1Sts = IoRead16 ((UINTN) (AcpiBaseAddr + R_ACPI_PM1_STS));
+ Gpe0aStsLow = IoRead32 ((UINTN) (AcpiBaseAddr + R_ACPI_GPE0a_STS));
+
+ Pm1Sts |=
+ (
+ B_ACPI_PM1_STS_WAK |
+#ifdef PCIESC_SUPPORT
+ B_ACPI_PM1_STS_WAK_PCIE0 |
+#endif
+ B_ACPI_PM1_STS_PRBTNOR |
+ B_ACPI_PM1_STS_RTC |
+ B_ACPI_PM1_STS_PWRBTN |
+ B_ACPI_PM1_STS_GBL |
+#ifdef PCIESC_SUPPORT
+ B_ACPI_PM1_STS_WAK_PCIE3 |
+ B_ACPI_PM1_STS_WAK_PCIE2 |
+ B_ACPI_PM1_STS_WAK_PCIE1 |
+#endif
+ B_ACPI_PM1_STS_TMROF
+ );
+
+ Gpe0aStsLow |=
+ (
+ B_ACPI_GPE0a_STS_PME_B0 |
+ B_ACPI_GPE0a_STS_BATLOW |
+ B_ACPI_GPE0a_STS_PCI_EXP |
+ B_ACPI_GPE0a_STS_GUNIT_SCI |
+ B_ACPI_GPE0a_STS_PUNIT_SCI |
+ B_ACPI_GPE0a_STS_SWGPE |
+ B_ACPI_GPE0a_STS_HOT_PLUG
+ );
+
+ IoWrite16 ((UINTN) (AcpiBaseAddr + R_ACPI_PM1_STS), (UINT16) Pm1Sts);
+ IoWrite32 ((UINTN) (AcpiBaseAddr + R_ACPI_GPE0a_STS), (UINT32) Gpe0aStsLow);
+ }
+
+ //
+ // Clear all SMIs that are unaffected by SCI_EN
+ //
+ SmiSts = IoRead32 ((UINTN) (AcpiBaseAddr + R_SMI_STS));
+ TcoSts = IoRead32 ((UINTN) (AcpiBaseAddr + R_TCO_STS));
+
+ SmiSts |=
+ (
+ B_SMI_STS_PERIODIC |
+ B_SMI_STS_TCO |
+ B_SMI_STS_SWSMI_TMR |
+ B_SMI_STS_APM |
+ B_SMI_STS_ON_SLP_EN |
+ B_SMI_STS_BIOS
+ );
+
+ TcoSts |=
+ (
+ B_TCO_STS_SECOND_TO |
+ B_TCO_STS_TIMEOUT
+ );
+
+ GpioClearAllGpiSmiSts ();
+ IoWrite32 ((UINTN) (AcpiBaseAddr + R_SMI_STS), SmiSts);
+
+ //
+ // Try to clear the EOS bit. ASSERT on an error
+ //
+ EosSet = ScSmmSetAndCheckEos ();
+ 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
+ScSmmSetAndCheckEos (
+ VOID
+ )
+{
+ UINT32 SmiEn;
+
+ SmiEn = IoRead32 ((UINTN) (AcpiBaseAddr + R_SMI_EN));
+
+ //
+ // Reset the SC to generate subsequent SMIs
+ //
+ SmiEn |= B_SMI_EN_EOS;
+ IoWrite32 ((UINTN) (AcpiBaseAddr + R_SMI_EN), SmiEn);
+
+ //
+ // Double check that the assert worked
+ //
+ SmiEn = IoRead32 ((UINTN) (AcpiBaseAddr + R_SMI_EN));
+
+ //
+ // Return TRUE if EOS is set correctly
+ //
+ if ((SmiEn & B_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
+ScSmmGetSciEn (
+ VOID
+ )
+{
+ BOOLEAN SciEn;
+ UINT32 Pm1Cnt;
+
+ //
+ // Determine whether an ACPI OS is present (via the SCI_EN bit)
+ //
+ Pm1Cnt = IoRead32 ((UINTN) (AcpiBaseAddr + R_ACPI_PM1_CNT));
+ SciEn = (BOOLEAN) ((Pm1Cnt & B_ACPI_PM1_CNT_SCI_EN) == B_ACPI_PM1_CNT_SCI_EN);
+
+ return SciEn;
+}
+
+
+/**
+ Read a specifying bit with the register
+ These may or may not need to change w/ the SC 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 (
+ IN CONST SC_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 ((AcpiBaseAddr != 0x0));
+
+ 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,
+ AcpiBaseAddr + 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:
+ case GPIO_ADDR_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
+ case PCR_ADDR_TYPE:
+ //
+ // Read the register, and it with the bit to read
+ //
+ switch (BitDesc->SizeInBytes) {
+ case 1:
+ PchPcrRead8 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8 *) &Register);
+ break;
+
+ case 2:
+ PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16 *) &Register);
+ break;
+
+ case 4:
+ PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32 *) &Register);
+ break;
+
+ default:
+ //
+ // Unsupported or invalid register size
+ //
+ ASSERT (FALSE);
+ break;
+ }
+
+ Register = Register & (LShiftU64 (BIT0, BitDesc->Bit));
+ if (Register) {
+ BitWasOne = TRUE;
+ } else {
+ BitWasOne = FALSE;
+ }
+ break;
+ default:
+ //
+ // This address type is not yet implemented
+ //
+ ASSERT (FALSE);
+ break;
+ }
+
+ return BitWasOne;
+}
+
+
+/**
+ Write a specifying bit with the register
+
+ @param[in] BitDesc The struct that includes register address, size in byte and bit number
+ @param[in] ValueToWrite The value to be wrote
+ @param[in] WriteClear If the rest bits of the register is write clear
+
+ @retval None
+
+**/
+VOID
+WriteBitDesc (
+ IN CONST SC_SMM_BIT_DESC *BitDesc,
+ IN CONST BOOLEAN ValueToWrite,
+ IN 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 ((AcpiBaseAddr != 0x0));
+
+ 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,
+ AcpiBaseAddr + RegisterOffset,
+ 1,
+ &Register
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Register &= AndVal;
+ Register |= OrVal;
+
+ Status = gSmst->SmmIo.Io.Write (
+ &gSmst->SmmIo,
+ RegSize,
+ AcpiBaseAddr + RegisterOffset,
+ 1,
+ &Register
+ );
+ ASSERT_EFI_ERROR (Status);
+ break;
+
+ case MEMORY_MAPPED_IO_ADDRESS_TYPE:
+ case GPIO_ADDR_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
+ case PCR_ADDR_TYPE:
+ //
+ // Read the register, or it with the bit to set, then write it back.
+ //
+ switch (BitDesc->SizeInBytes) {
+ case 1:
+ PchPcrAndThenOr8 ((SC_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8) AndVal, (UINT8) OrVal);
+ break;
+
+ case 2:
+ PchPcrAndThenOr16 ((SC_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16) AndVal, (UINT16) OrVal);
+ break;
+
+ case 4:
+ PchPcrAndThenOr32 ((SC_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid, (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32) AndVal, (UINT32) OrVal);
+ break;
+
+ default:
+ //
+ // Unsupported or invalid register size
+ //
+ ASSERT (FALSE);
+ break;
+ }
+ break;
+ default:
+ //
+ // This address type is not yet implemented
+ //
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+
+/**
+ Specific programming done before exiting SMI
+
+**/
+VOID
+ScBeforeExitSmi (
+ )
+{
+
+ if (BxtStepping () >= BxtPB0) {
+ if ((AsmReadMsr64(0x8b) >> 32) >= 8) {
+ UINT32 SpiBar0 = 0;
+
+ SpiBar0 = (MmioRead32 (MmPciAddress (0, DEFAULT_PCI_BUS_NUMBER_SC, PCI_DEVICE_NUMBER_SPI, PCI_FUNCTION_NUMBER_SPI, R_SPI_BASE))) & B_SPI_BASE_BAR;
+ SpiBar0 |= BIT0; // Set MSR valid
+ AsmWriteMsr32 (0x124, SpiBar0);
+ }
+ }
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScxSmmHelpers.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScxSmmHelpers.h
new file mode 100644
index 0000000000..3deec44cf1
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/ScSmiDispatcher/Smm/ScxSmmHelpers.h
@@ -0,0 +1,128 @@
+/** @file
+ This driver is responsible for the registration of child drivers
+ and the abstraction of the SC SMI sources.
+
+ Copyright (c) 2012 - 2016, 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 _SC_SMM_HELPERS_H_
+#define _SC_SMM_HELPERS_H_
+
+#include "ScSmm.h"
+#include <Library/ScPlatformLib.h>
+#include <Library/SteppingLib.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
+ScSmmInitHardware (
+ VOID
+ );
+
+/**
+ Enables the SC 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
+ScSmmEnableGlobalSmiBit (
+ 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
+ScSmmClearSmi (
+ 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
+ScSmmSetAndCheckEos (
+ 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
+ScSmmGetSciEn (
+ 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 (
+ IN CONST SC_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 (
+ IN CONST SC_SMM_BIT_DESC *BitDesc,
+ IN CONST BOOLEAN ValueToWrite,
+ IN CONST BOOLEAN WriteClear
+ );
+
+/**
+ Specific programming done before exiting SMI
+
+**/
+VOID
+ScBeforeExitSmi (
+ );
+
+#endif
+