[edk2] [Patch][edk2-platforms/devel-MinnowBoard3] Add SPI modules.

zwei4 posted 1 patch 7 years, 2 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/edk2 tags/patchew/20170213024851.38240-1-david.wei@intel.com
.../SouthCluster/Include/Library/ScSpiCommonLib.h  | 361 ++++++++
.../SouthCluster/Include/Protocol/Spi.h            | 359 ++++++++
.../BaseScSpiCommonLib/BaseScSpiCommonLib.inf      |  40 +
.../Library/BaseScSpiCommonLib/SpiCommon.c         | 994 +++++++++++++++++++++
.../SouthCluster/Spi/RuntimeDxe/ScSpi.c            | 313 +++++++
.../SouthCluster/Spi/RuntimeDxe/ScSpi.h            |  50 ++
.../SouthCluster/Spi/RuntimeDxe/ScSpiRuntime.inf   |  60 ++
.../BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.c      | 249 ++++++
.../BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.h      |  33 +
.../BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpiSmm.inf |  49 +
10 files changed, 2508 insertions(+)
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Library/ScSpiCommonLib.h
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Protocol/Spi.h
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/BaseScSpiCommonLib.inf
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/SpiCommon.c
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.c
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.h
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpiRuntime.inf
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.c
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.h
create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpiSmm.inf
[edk2] [Patch][edk2-platforms/devel-MinnowBoard3] Add SPI modules.
Posted by zwei4 7 years, 2 months ago
From: lushifex <shifeix.a.lu@intel.com>

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: lushifex <shifeix.a.lu@intel.com>
Signed-off-by: David Wei <david.wei@intel.com>
---
 .../SouthCluster/Include/Library/ScSpiCommonLib.h  | 361 ++++++++
 .../SouthCluster/Include/Protocol/Spi.h            | 359 ++++++++
 .../BaseScSpiCommonLib/BaseScSpiCommonLib.inf      |  40 +
 .../Library/BaseScSpiCommonLib/SpiCommon.c         | 994 +++++++++++++++++++++
 .../SouthCluster/Spi/RuntimeDxe/ScSpi.c            | 313 +++++++
 .../SouthCluster/Spi/RuntimeDxe/ScSpi.h            |  50 ++
 .../SouthCluster/Spi/RuntimeDxe/ScSpiRuntime.inf   |  60 ++
 .../BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.c      | 249 ++++++
 .../BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.h      |  33 +
 .../BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpiSmm.inf |  49 +
 10 files changed, 2508 insertions(+)
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Library/ScSpiCommonLib.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Protocol/Spi.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/BaseScSpiCommonLib.inf
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/SpiCommon.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpiRuntime.inf
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpiSmm.inf

diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Library/ScSpiCommonLib.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Library/ScSpiCommonLib.h
new file mode 100644
index 0000000..3587bab
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Library/ScSpiCommonLib.h
@@ -0,0 +1,361 @@
+/** @file
+  Header file for the SC SPI Common Driver.
+
+  Copyright (c) 2008 - 2017, 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_SPI_COMMON_LIB_H_
+#define _SC_SPI_COMMON_LIB_H_
+
+///
+/// Maximum time allowed while waiting the SPI cycle to complete
+/// Wait Time = 6 seconds = 6000000 microseconds
+/// Wait Period = 10 microseconds
+///
+#define WAIT_TIME   6000000     ///< Wait Time = 6 seconds = 6000000 microseconds
+#define WAIT_PERIOD 10          ///< Wait Period = 10 microseconds
+
+///
+/// Flash cycle Type
+///
+typedef enum {
+  FlashCycleRead,
+  FlashCycleWrite,
+  FlashCycleErase,
+  FlashCycleReadSfdp,
+  FlashCycleReadJedecId,
+  FlashCycleWriteStatus,
+  FlashCycleReadStatus,
+  FlashCycleMax
+} FLASH_CYCLE_TYPE;
+
+///
+/// Flash Component Number
+///
+typedef enum {
+  FlashComponent0,
+  FlashComponent1,
+  FlashComponentMax
+} FLASH_COMPONENT_NUM;
+
+///
+/// Private data structure definitions for the driver
+///
+#define SC_SPI_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('P', 'S', 'P', 'I')
+
+typedef struct {
+  UINTN                 Signature;
+  EFI_HANDLE            Handle;
+  SC_SPI_PROTOCOL       SpiProtocol;
+  UINT16                PchAcpiBase;
+  UINTN                 PchSpiBase;
+  UINT16                RegionPermission;
+  UINT32                SfdpVscc0Value;
+  UINT32                SfdpVscc1Value;
+  UINT32                StrapBaseAddress;
+  UINT8                 NumberOfComponents;
+  UINT32                Component1StartAddr;
+} SPI_INSTANCE;
+
+#define SPI_INSTANCE_FROM_SPIPROTOCOL(a)  CR (a, SPI_INSTANCE, SpiProtocol, SC_SPI_PRIVATE_DATA_SIGNATURE)
+
+///
+/// Function prototypes used by the SPI protocol.
+///
+/**
+  Initialize an SPI protocol instance.
+
+  @param[in] SpiInstance             Pointer to SpiInstance to initialize
+
+  @retval    EFI_SUCCESS             The protocol instance was properly initialized
+  @retval    EFI_UNSUPPORTED         The SC is not supported by this module
+
+**/
+EFI_STATUS
+SpiProtocolConstructor (
+  IN     SPI_INSTANCE       *SpiInstance
+  );
+
+/**
+  This function is a hook for Spi to disable BIOS Write Protect.
+
+  @retval   EFI_SUCCESS             The protocol instance was properly initialized
+  @retval   EFI_ACCESS_DENIED       The BIOS Region can only be updated in SMM phase
+
+**/
+EFI_STATUS
+EFIAPI
+DisableBiosWriteProtect (
+  VOID
+  );
+
+/**
+  This function is a hook for Spi to enable BIOS Write Protect.
+
+**/
+VOID
+EFIAPI
+EnableBiosWriteProtect (
+  VOID
+  );
+
+/**
+  Acquire SC spi mmio address.
+
+  @param[in] SpiInstance          Pointer to SpiInstance to initialize
+
+  @retval    UINT32               Return SPI MMIO address
+
+**/
+UINT32
+AcquireSpiBar0 (
+  IN  SPI_INSTANCE                *SpiInstance
+  );
+
+/**
+  Release SC spi mmio address.
+
+  @param[in] SpiInstance          Pointer to SpiInstance to initialize
+
+**/
+VOID
+ReleaseSpiBar0 (
+  IN  SPI_INSTANCE                *SpiInstance
+  );
+
+/**
+  Read data from the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  FlashRegionType         The Flash Region type for flash cycle which is listed in the Descriptor.
+  @param[in]  Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in]  ByteCount               Number of bytes in the data portion of the SPI cycle.
+  @param[out] Buffer                  The Pointer to caller-allocated buffer containing the data received.
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashRead (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *Buffer
+  );
+
+/**
+  Write data to the flash part.
+
+  @param[in] This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in] FlashRegionType         The Flash Region type for flash cycle which is listed in the Descriptor.
+  @param[in] Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in] ByteCount               Number of bytes in the data portion of the SPI cycle.
+  @param[in] Buffer                  Pointer to caller-allocated buffer containing the data sent during the SPI cycle.
+
+  @retval    EFI_SUCCESS             Command succeed.
+  @retval    EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval    EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashWrite (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount,
+  IN     UINT8              *Buffer
+  );
+
+/**
+  Erase some area on the flash part.
+
+  @param[in] This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in] FlashRegionType         The Flash Region type for flash cycle which is listed in the Descriptor.
+  @param[in] Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in] ByteCount               Number of bytes in the data portion of the SPI cycle.
+
+  @retval    EFI_SUCCESS             Command succeed.
+  @retval    EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval    EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashErase (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount
+  );
+
+/**
+  Read SFDP data from the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  ComponentNumber         The Component Number for chip select
+  @param[in]  ByteCount               Number of bytes in SFDP data portion of the SPI cycle, the max number is 64
+  @param[out] SfdpData                The Pointer to caller-allocated buffer containing the SFDP data received
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashReadSfdp (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     UINT8              ComponentNumber,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *SfdpData
+  );
+
+/**
+  Read Jedec Id from the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  ComponentNumber         The Component Number for chip select
+  @param[in]  ByteCount               Number of bytes in JedecId data portion of the SPI cycle, the data size is 3 typically
+  @param[out] JedecId                 The Pointer to caller-allocated buffer containing JEDEC ID received
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashReadJedecId (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT8              ComponentNumber,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *JedecId
+  );
+
+/**
+  Write the status register in the flash part.
+
+  @param[in] This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in] ByteCount               Number of bytes in Status data portion of the SPI cycle, the data size is 1 typically
+  @param[in] StatusValue             The Pointer to caller-allocated buffer containing the value of Status register writing
+
+  @retval    EFI_SUCCESS             Command succeed.
+  @retval    EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval    EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashWriteStatus (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT32             ByteCount,
+  IN     UINT8              *StatusValue
+  );
+
+/**
+  Read status register in the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  ByteCount               Number of bytes in Status data portion of the SPI cycle, the data size is 1 typically
+  @param[out] StatusValue             The Pointer to caller-allocated buffer containing the value of Status register received.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashReadStatus (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *StatusValue
+  );
+
+/**
+  Read SC Soft Strap Values.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  SoftStrapAddr           SC Soft Strap address offset from FPSBA.
+  @param[in]  ByteCount               Number of bytes in SoftStrap data portion of the SPI cycle
+  @param[out] SoftStrapValue          The Pointer to caller-allocated buffer containing SC Soft Strap Value.
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolReadPchSoftStrap (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT32             SoftStrapAddr,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *SoftStrapValue
+  );
+
+/**
+  This function sends the programmed SPI command to the slave device.
+
+  @param[in]      This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]      SpiRegionType           The SPI Region type for flash cycle which is listed in the Descriptor
+  @param[in]      FlashCycleType          The Flash SPI cycle type list in HSFC (Hardware Sequencing Flash Control Register) register
+  @param[in]      Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in]      ByteCount               Number of bytes in the data portion of the SPI cycle.
+  @param[in, out] Buffer                  Pointer to caller-allocated buffer containing the data received or sent during the SPI cycle.
+
+  @retval         EFI_SUCCESS             SPI command completes successfully.
+  @retval         EFI_DEVICE_ERROR        Device error, the command aborts abnormally.
+  @retval         EFI_ACCESS_DENIED       Some unrecognized command encountered in hardware sequencing mode
+  @retval         EFI_INVALID_PARAMETER   The parameters specified are not valid.
+
+**/
+EFI_STATUS
+SendSpiCmd (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     FLASH_CYCLE_TYPE   FlashCycleType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount,
+  IN OUT UINT8              *Buffer
+  );
+
+/**
+  Wait execution cycle to complete on the SPI interface.
+
+  @param[in] This                 The SPI protocol instance
+  @param[in] PchSpiBar0           Spi MMIO base address
+  @param[in] ErrorCheck           TRUE if the SpiCycle needs to do the error check
+
+  @retval    TRUE                 SPI cycle completed on the interface.
+  @retval    FALSE                Time out while waiting the SPI cycle to complete.
+                                  It's not safe to program the next command on the SPI interface.
+
+**/
+BOOLEAN
+WaitForSpiCycleComplete (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT32             PchSpiBar0,
+  IN     BOOLEAN            ErrorCheck
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Protocol/Spi.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Protocol/Spi.h
new file mode 100644
index 0000000..b761ad2
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Include/Protocol/Spi.h
@@ -0,0 +1,359 @@
+/** @file
+  This file defines the EFI SPI Protocol which implements the
+  Intel(R) ICH SPI Host Controller Compatibility Interface.
+
+  Copyright (c) 2012 - 2017, 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_SPI_PROTOCOL_H_
+#define _SC_SPI_PROTOCOL_H_
+
+//
+// Extern the GUID for protocol users.
+//
+extern EFI_GUID                       gScSpiProtocolGuid;
+extern EFI_GUID                       gScSmmSpiProtocolGuid;
+
+//
+// Forward reference for ANSI C compatibility
+//
+typedef struct _SC_SPI_PROTOCOL  SC_SPI_PROTOCOL;
+
+//
+// SPI protocol data structures and definitions
+//
+
+///
+/// Flash Region Type
+///
+typedef enum {
+  FlashRegionDescriptor,
+  FlashRegionBios,
+  FlashRegionMe,
+  FlashRegionGbE,
+  FlashRegionPlatformData,
+  FlashRegionAll,
+  FlashRegionMax
+} FLASH_REGION_TYPE;
+
+
+///
+/// SPI protocol data structures and definitions
+///
+///
+/// Number of Prefix Opcodes allowed on the SPI interface
+///
+#define SPI_NUM_PREFIX_OPCODE 2
+
+///
+/// Number of Opcodes in the Opcode Menu
+///
+#define SPI_NUM_OPCODE  8
+
+///
+/// Opcode Type
+///   EnumSpiOpcodeCommand: Command without address
+///   EnumSpiOpcodeRead: Read with address
+///   EnumSpiOpcodeWrite: Write with address
+///
+typedef enum {
+  EnumSpiOpcodeReadNoAddr,
+  EnumSpiOpcodeWriteNoAddr,
+  EnumSpiOpcodeRead,
+  EnumSpiOpcodeWrite,
+  EnumSpiOpcodeMax
+} SPI_OPCODE_TYPE;
+
+typedef enum {
+  EnumSpiCycle20MHz,
+  EnumSpiCycle33MHz,
+  EnumSpiCycle66MHz,  /// Not supported by BXT
+  EnumSpiCycle50MHz,
+  EnumSpiCycleMax
+} SPI_CYCLE_FREQUENCY;
+
+///
+/// Hardware Sequencing required operations (as listed in Broxton EDS "Hardware
+/// Sequencing Commands and Opcode Requirements"
+///
+typedef enum {
+  EnumSpiOperationWriteStatus,
+  EnumSpiOperationProgramData_1_Byte,
+  EnumSpiOperationProgramData_64_Byte,
+  EnumSpiOperationReadData,
+  EnumSpiOperationWriteDisable,
+  EnumSpiOperationReadStatus,
+  EnumSpiOperationWriteEnable,
+  EnumSpiOperationFastRead,
+  EnumSpiOperationEnableWriteStatus,
+  EnumSpiOperationErase_256_Byte,
+  EnumSpiOperationErase_4K_Byte,
+  EnumSpiOperationErase_8K_Byte,
+  EnumSpiOperationErase_64K_Byte,
+  EnumSpiOperationFullChipErase,
+  EnumSpiOperationJedecId,
+  EnumSpiOperationDualOutputFastRead,
+  EnumSpiOperationDiscoveryParameters,
+  EnumSpiOperationOther,
+  EnumSpiOperationMax
+} SPI_OPERATION;
+
+///
+/// SPI Command Configuration
+///   Frequency       The expected frequency to be used (value to be programmed to the SSFC
+///                   Register)
+///   Operation       Which Hardware Sequencing required operation this opcode respoinds to.
+///                   The required operations are listed in EDS Table 5-55: "Hardware
+///                   Sequencing Commands and Opcode Requirements"
+///                   If the opcode does not corresponds to any operation listed, use
+///                   EnumSpiOperationOther, and provides TYPE and Code for it in
+///                   SpecialOpcodeEntry.
+///
+typedef struct _SPI_OPCODE_MENU_ENTRY {
+  SPI_OPCODE_TYPE     Type;
+  UINT8               Code;
+  SPI_CYCLE_FREQUENCY Frequency;
+  SPI_OPERATION       Operation;
+} SPI_OPCODE_MENU_ENTRY;
+
+//
+// Initialization data table loaded to the SPI host controller
+//    VendorId        Vendor ID of the SPI device
+//    DeviceId0       Device ID0 of the SPI device
+//    DeviceId1       Device ID1 of the SPI device
+//    PrefixOpcode    Prefix opcodes which are loaded into the SPI host controller
+//    OpcodeMenu      Opcodes which are loaded into the SPI host controller Opcode Menu
+//    BiosStartOffset The offset of the start of the BIOS image relative to the flash device.
+//                    Please note this is a Flash Linear Address, NOT a memory space address.
+//                    This value is platform specific and depends on the system flash map.
+//                    This value is only used on non Descriptor mode.
+//    BiosSize        The the BIOS Image size in flash. This value is platform specific
+//                    and depends on the system flash map. Please note BIOS Image size may
+//                    be smaller than BIOS Region size (in Descriptor Mode) or the flash size
+//                    (in Non Descriptor Mode), and in this case, BIOS Image is supposed to be
+//                    placed at the top end of the BIOS Region (in Descriptor Mode) or the flash
+//                    (in Non Descriptor Mode)
+//
+typedef struct _SPI_INIT_TABLE {
+  UINT8                 VendorId;
+  UINT8                 DeviceId0;
+  UINT8                 DeviceId1;
+  UINT8                 PrefixOpcode[SPI_NUM_PREFIX_OPCODE];
+  SPI_OPCODE_MENU_ENTRY OpcodeMenu[SPI_NUM_OPCODE];
+  UINTN                 BiosStartOffset;
+  UINTN                 BiosSize;
+} SPI_INIT_TABLE;
+
+//
+// Protocol member functions
+//
+/**
+  Read data from the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  FlashRegionType         The Flash Region type for flash cycle which is listed in the Descriptor.
+  @param[in]  Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in]  ByteCount               Number of bytes in the data portion of the SPI cycle.
+  @param[out] Buffer                  The Pointer to caller-allocated buffer containing the dada received.
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_SPI_FLASH_READ) (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *Buffer
+  );
+
+/**
+  Write data to the flash part.
+
+  @param[in] This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in] FlashRegionType         The Flash Region type for flash cycle which is listed in the Descriptor.
+  @param[in] Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in] ByteCount               Number of bytes in the data portion of the SPI cycle.
+  @param[in] Buffer                  Pointer to caller-allocated buffer containing the data sent during the SPI cycle.
+
+  @retval    EFI_SUCCESS             Command succeed.
+  @retval    EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval    EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_SPI_FLASH_WRITE) (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount,
+  IN     UINT8              *Buffer
+  );
+
+/**
+  Erase some area on the flash part.
+
+  @param[in] This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in] FlashRegionType         The Flash Region type for flash cycle which is listed in the Descriptor.
+  @param[in] Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in] ByteCount               Number of bytes in the data portion of the SPI cycle.
+
+  @retval    EFI_SUCCESS             Command succeed.
+  @retval    EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval    EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_SPI_FLASH_ERASE) (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount
+  );
+
+/**
+  Read SFDP data from the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  ComponentNumber         The Componen Number for chip select
+  @param[in]  ByteCount               Number of bytes in SFDP data portion of the SPI cycle, the max number is 64
+  @param[out] SfdpData                The Pointer to caller-allocated buffer containing the SFDP data received
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_SPI_FLASH_READ_SFDP) (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     UINT8              ComponentNumber,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *SfdpData
+  );
+
+/**
+  Read Jedec Id from the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  ComponentNumber         The Componen Number for chip select
+  @param[in]  ByteCount               Number of bytes in JedecId data portion of the SPI cycle, the data size is 3 typically
+  @param[out] JedecId                 The Pointer to caller-allocated buffer containing JEDEC ID received
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_SPI_FLASH_READ_JEDEC_ID) (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     UINT8              ComponentNumber,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *JedecId
+  );
+
+/**
+  Write the status register in the flash part.
+
+  @param[in] This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in] ByteCount               Number of bytes in Status data portion of the SPI cycle, the data size is 1 typically
+  @param[in] StatusValue             The Pointer to caller-allocated buffer containing the value of Status register writing
+
+  @retval    EFI_SUCCESS             Command succeed.
+  @retval    EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval    EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_SPI_FLASH_WRITE_STATUS) (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     UINT32             ByteCount,
+  IN     UINT8              *StatusValue
+  );
+
+/**
+  Read status register in the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  ByteCount               Number of bytes in Status data portion of the SPI cycle, the data size is 1 typically
+  @param[out] StatusValue             The Pointer to caller-allocated buffer containing the value of Status register received.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_SPI_FLASH_READ_STATUS) (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *StatusValue
+  );
+
+/**
+  Read PCH Soft Strap Values.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  SoftStrapAddr           PCH Soft Strap address offset from FPSBA.
+  @param[in]  ByteCount               Number of bytes in SoftStrap data portion of the SPI cycle
+  @param[out] SoftStrapValue          The Pointer to caller-allocated buffer containing PCH Soft Strap Value.
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *SC_SPI_READ_PCH_SOFTSTRAP) (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     UINT32             SoftStrapAddr,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *SoftStrapValue
+  );
+
+/**
+  The SC SPI protocol implement the South Cluster SPI Host Controller Interface
+  for DXE, SMM, and PEI environments, respectively.
+
+  These protocols/PPI allows a platform module to perform SPI operations through the
+  Intel PCH SPI Host Controller Interface.
+
+**/
+struct _SC_SPI_PROTOCOL {
+  SC_SPI_FLASH_READ                FlashRead;          ///< Read data from the flash part.
+  SC_SPI_FLASH_WRITE               FlashWrite;         ///< Write data to the flash part.
+  SC_SPI_FLASH_ERASE               FlashErase;         ///< Erase some area on the flash part.
+  SC_SPI_FLASH_READ_SFDP           FlashReadSfdp;      ///< Read SFDP data from the flash part.
+  SC_SPI_FLASH_READ_JEDEC_ID       FlashReadJedecId;   ///< Read Jedec Id from the flash part.
+  SC_SPI_FLASH_WRITE_STATUS        FlashWriteStatus;   ///< Write the status register in the flash part.
+  SC_SPI_FLASH_READ_STATUS         FlashReadStatus;    ///< Read status register in the flash part.
+  SC_SPI_READ_PCH_SOFTSTRAP        ReadPchSoftStrap;   ///< Read PCH Soft Strap Values
+};
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/BaseScSpiCommonLib.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/BaseScSpiCommonLib.inf
new file mode 100644
index 0000000..97aec77
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/BaseScSpiCommonLib.inf
@@ -0,0 +1,40 @@
+## @file
+#  Library for ScSpiCommon
+#
+#  Copyright (c) 2014 - 2017, 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                      = ScSpiCommonLib
+  FILE_GUID                      = A37CB67E-7D85-45B3-B07E-BF65BDB603E8
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = ScSpiCommonLib
+
+[Sources]
+  SpiCommon.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+  BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[LibraryClasses]
+  IoLib
+  DebugLib
+  PcdLib
+  ScPlatformLib
+
+[Pcd]
+  gEfiBxtTokenSpaceGuid.PcdScAcpiIoPortBaseAddress  ## CONSUMES
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/SpiCommon.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/SpiCommon.c
new file mode 100644
index 0000000..97a13fa
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Library/BaseScSpiCommonLib/SpiCommon.c
@@ -0,0 +1,994 @@
+/** @file
+  SC SPI Common Driver implements the SPI Host Controller Compatibility Interface.
+
+  Copyright (c) 2008 - 2017, 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 <Uefi/UefiBaseType.h>
+#include <IndustryStandard/Pci30.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MmPciLib.h>
+#include <Protocol/Spi.h>
+#include <ScAccess.h>
+#include <Library/ScSpiCommonLib.h>
+
+/**
+  Initialize an SPI protocol instance.
+
+  @param[in] SpiInstance          Pointer to SpiInstance to initialize
+
+  @retval    EFI_SUCCESS          The protocol instance was properly initialized
+  @retval    EFI_UNSUPPORTED      The SC is not supported by this module
+
+**/
+EFI_STATUS
+SpiProtocolConstructor (
+  IN     SPI_INSTANCE       *SpiInstance
+  )
+{
+  UINT32          ScSpiBar0;
+  UINT8           Comp0Density;
+
+  //
+  // Initialize the SPI protocol instance
+  //
+  SpiInstance->Signature                    = SC_SPI_PRIVATE_DATA_SIGNATURE;
+  SpiInstance->Handle                       = NULL;
+  SpiInstance->SpiProtocol.FlashRead        = SpiProtocolFlashRead;
+  SpiInstance->SpiProtocol.FlashWrite       = SpiProtocolFlashWrite;
+  SpiInstance->SpiProtocol.FlashErase       = SpiProtocolFlashErase;
+  SpiInstance->SpiProtocol.FlashReadSfdp    = SpiProtocolFlashReadSfdp;
+  SpiInstance->SpiProtocol.FlashReadJedecId = SpiProtocolFlashReadJedecId;
+  SpiInstance->SpiProtocol.FlashWriteStatus = SpiProtocolFlashWriteStatus;
+  SpiInstance->SpiProtocol.FlashReadStatus  = SpiProtocolFlashReadStatus;
+  SpiInstance->SpiProtocol.ReadPchSoftStrap = SpiProtocolReadPchSoftStrap;
+
+  SpiInstance->PchSpiBase = MmPciBase (
+                              DEFAULT_PCI_BUS_NUMBER_SC,
+                              PCI_DEVICE_NUMBER_SPI,
+                              PCI_FUNCTION_NUMBER_SPI
+                              );
+
+  SpiInstance->PchAcpiBase = (UINT16) PcdGet16 (PcdScAcpiIoPortBaseAddress);
+  ASSERT (SpiInstance->PchAcpiBase != 0);
+
+  ScSpiBar0 = MmioRead32 (SpiInstance->PchSpiBase + R_SPI_BASE) & ~(B_SPI_BAR0_MASK);
+  if (ScSpiBar0 == 0) {
+    DEBUG ((DEBUG_ERROR, "ERROR : ScSpiBar0 is invalid!\n"));
+    ASSERT (FALSE);
+  }
+
+  MmioOr32 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+
+  SpiInstance->RegionPermission = MmioRead16 (ScSpiBar0 + R_SPI_FRAP);
+  DEBUG ((DEBUG_INFO, "Flash RegionPermission : %0x\n", SpiInstance->RegionPermission));
+
+  SpiInstance->SfdpVscc0Value = MmioRead32 (ScSpiBar0 + R_SPI_LVSCC);
+  DEBUG ((DEBUG_INFO, "Component 0 SFDP VSCC value : %0x\n", SpiInstance->SfdpVscc0Value));
+  SpiInstance->SfdpVscc1Value = MmioRead32 (ScSpiBar0 + R_SPI_UVSCC);
+  DEBUG ((DEBUG_INFO, "Component 1 SFDP VSCC value : %0x\n", SpiInstance->SfdpVscc1Value));
+
+  //
+  // Select to Flash Map 0 Register to get the number of flash Component
+  //
+  MmioAndThenOr32 (
+    ScSpiBar0 + R_SPI_FDOC,
+    (UINT32) (~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)),
+    (UINT32) (V_SPI_FDOC_FDSS_FSDM | R_SPI_FDBAR_FLASH_MAP0)
+    );
+
+  //
+  // Copy Zero based Number Of Components
+  //
+  SpiInstance->NumberOfComponents = (UINT8) ((MmioRead16 (ScSpiBar0 + R_SPI_FDOD) & B_SPI_FDBAR_NC) >> N_SPI_FDBAR_NC);
+  DEBUG ((DEBUG_INFO, "Component Number : %0x\n", SpiInstance->NumberOfComponents + 1));
+
+  MmioAndThenOr32 (
+    ScSpiBar0 + R_SPI_FDOC,
+    (UINT32) (~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)),
+    (UINT32) (V_SPI_FDOC_FDSS_COMP | R_SPI_FCBA_FLCOMP)
+    );
+
+  //
+  // Copy Component 0 Density
+  //
+  Comp0Density = (UINT8) MmioRead32 (ScSpiBar0 + R_SPI_FDOD) & B_SPI_FLCOMP_COMP1_MASK;
+  SpiInstance->Component1StartAddr = (UINT32) (V_SPI_FLCOMP_COMP1_512KB << Comp0Density);
+  DEBUG ((DEBUG_INFO, "Component 1 StartAddr : %0x\n", SpiInstance->Component1StartAddr));
+
+  //
+  // Select FLASH_MAP1 to get Flash SC Strap Base Address
+  //
+  MmioAndThenOr32 (
+    (ScSpiBar0 + R_SPI_FDOC),
+    (UINT32) (~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)),
+    (UINT32) (V_SPI_FDOC_FDSS_FSDM | R_SPI_FDBAR_FLASH_MAP1)
+    );
+
+  SpiInstance->StrapBaseAddress = MmioRead32 (ScSpiBar0 + R_SPI_FDOD) & B_SPI_FDBAR_FPSBA;
+
+  //
+  // Align FPSBA with address bits for the SC Strap portion of flash descriptor
+  //
+  SpiInstance->StrapBaseAddress &= B_SPI_FDBAR_FPSBA;
+  DEBUG ((DEBUG_INFO, "StrapBaseAddress : %0x\n", SpiInstance->StrapBaseAddress));
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Delay for at least the request number of microseconds for Runtime usage.
+
+  @param[in] ABase                Acpi base address
+  @param[in] Microseconds         Number of microseconds to delay.
+
+  @retval    None
+**/
+VOID
+EFIAPI
+PchPmTimerStallRuntimeSafe (
+  IN  UINT16  ABase,
+  IN  UINTN   Microseconds
+  )
+{
+  UINTN   Ticks;
+  UINTN   Counts;
+  UINTN   CurrentTick;
+  UINTN   OriginalTick;
+  UINTN   RemainingTick;
+
+#ifdef SLE_FLAG
+  Microseconds = 0;
+#endif
+  if (Microseconds == 0) {
+    return;
+  }
+
+  OriginalTick   = IoRead32 ((UINTN) (ABase + R_ACPI_PM1_TMR)) & B_ACPI_PM1_TMR_VAL;
+  CurrentTick    = OriginalTick;
+
+  //
+  // The timer frequency is 3.579545 MHz, so 1 ms corresponds 3.58 clocks
+  //
+  Ticks = Microseconds * 358 / 100 + OriginalTick + 1;
+
+  //
+  // The loops needed by timer overflow
+  //
+  Counts = Ticks / V_ACPI_PM1_TMR_MAX_VAL;
+
+  //
+  // Remaining clocks within one loop
+  //
+  RemainingTick = Ticks % V_ACPI_PM1_TMR_MAX_VAL;
+
+  //
+  // not intend to use TMROF_STS bit of register PM1_STS, because this adds extra
+  // one I/O operation, and maybe generate SMI
+  //
+  while ((Counts != 0) || (RemainingTick > CurrentTick)) {
+    CurrentTick = IoRead32 ((UINTN) (ABase + R_ACPI_PM1_TMR)) & B_ACPI_PM1_TMR_VAL;
+    //
+    // Check if timer overflow
+    //
+    if ((CurrentTick < OriginalTick)) {
+      if (Counts != 0) {
+        Counts--;
+      } else {
+        //
+        // If timer overflow and Counts equal to 0, that means we already stalled more than
+        // RemainingTick, break the loop here
+        //
+        break;
+      }
+    }
+
+    OriginalTick = CurrentTick;
+  }
+}
+
+
+/**
+  Read data from the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  FlashRegionType         The Flash Region type for flash cycle which is listed in the Descriptor.
+  @param[in]  Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in]  ByteCount               Number of bytes in the data portion of the SPI cycle.
+  @param[out] Buffer                  The Pointer to caller-allocated buffer containing the data received.
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashRead (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *Buffer
+  )
+{
+  EFI_STATUS        Status;
+
+  //
+  // Sends the command to the SPI interface to execute.
+  //
+  Status = SendSpiCmd (
+             This,
+             FlashRegionType,
+             FlashCycleRead,
+             Address,
+             ByteCount,
+             Buffer
+             );
+  return Status;
+}
+
+
+/**
+  Write data to the flash part.
+
+  @param[in] This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in] FlashRegionType         The Flash Region type for flash cycle which is listed in the Descriptor.
+  @param[in] Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in] ByteCount               Number of bytes in the data portion of the SPI cycle.
+  @param[in] Buffer                  Pointer to caller-allocated buffer containing the data sent during the SPI cycle.
+
+  @retval    EFI_SUCCESS             Command succeed.
+  @retval    EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval    EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashWrite (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount,
+  IN     UINT8              *Buffer
+  )
+{
+  EFI_STATUS        Status;
+
+  //
+  // Sends the command to the SPI interface to execute.
+  //
+  Status = SendSpiCmd (
+             This,
+             FlashRegionType,
+             FlashCycleWrite,
+             Address,
+             ByteCount,
+             Buffer
+             );
+  return Status;
+}
+
+
+/**
+  Erase some area on the flash part.
+
+  @param[in] This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in] FlashRegionType         The Flash Region type for flash cycle which is listed in the Descriptor.
+  @param[in] Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in] ByteCount               Number of bytes in the data portion of the SPI cycle.
+
+  @retval    EFI_SUCCESS             Command succeed.
+  @retval    EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval    EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashErase (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount
+  )
+{
+  EFI_STATUS        Status;
+
+  //
+  // Sends the command to the SPI interface to execute.
+  //
+  Status = SendSpiCmd (
+             This,
+             FlashRegionType,
+             FlashCycleErase,
+             Address,
+             ByteCount,
+             NULL
+             );
+  return Status;
+}
+
+
+/**
+  Read SFDP data from the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  ComponentNumber         The Component Number for chip select
+  @param[in]  ByteCount               Number of bytes in SFDP data portion of the SPI cycle, the max number is 64
+  @param[out] SfdpData                The Pointer to caller-allocated buffer containing the SFDP data received
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashReadSfdp (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT8              ComponentNumber,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *SfdpData
+  )
+{
+  SPI_INSTANCE      *SpiInstance;
+  EFI_STATUS        Status;
+  UINT32            Address;
+
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+  Status            = EFI_SUCCESS;
+
+  if ((ByteCount > 64) || (ComponentNumber > SpiInstance->NumberOfComponents)) {
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Address = 0;
+  if (ComponentNumber == FlashComponent1) {
+    Address = SpiInstance->Component1StartAddr;
+  }
+
+  //
+  // Sends the command to the SPI interface to execute.
+  //
+  Status = SendSpiCmd (
+             This,
+             0,
+             FlashCycleReadSfdp,
+             Address,
+             ByteCount,
+             SfdpData
+             );
+
+  return Status;
+}
+
+
+/**
+  Read Jedec Id from the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  ComponentNumber         The Component Number for chip select
+  @param[in]  ByteCount               Number of bytes in JedecId data portion of the SPI cycle, the data size is 3 typically
+  @param[out] JedecId                 The Pointer to caller-allocated buffer containing JEDEC ID received
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashReadJedecId (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT8              ComponentNumber,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *JedecId
+  )
+{
+  SPI_INSTANCE      *SpiInstance;
+  EFI_STATUS        Status;
+  UINT32            Address;
+
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+  Status            = EFI_SUCCESS;
+
+  if (ComponentNumber > SpiInstance->NumberOfComponents) {
+    ASSERT (FALSE);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Address = 0;
+  if (ComponentNumber == FlashComponent1) {
+    Address = SpiInstance->Component1StartAddr;
+  }
+
+  //
+  // Sends the command to the SPI interface to execute.
+  //
+  Status = SendSpiCmd (
+             This,
+             0,
+             FlashCycleReadJedecId,
+             Address,
+             ByteCount,
+             JedecId
+             );
+
+  return Status;
+}
+
+
+/**
+  Write the status register in the flash part.
+
+  @param[in] This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in] ByteCount               Number of bytes in Status data portion of the SPI cycle, the data size is 1 typically
+  @param[in] StatusValue             The Pointer to caller-allocated buffer containing the value of Status register writing
+
+  @retval    EFI_SUCCESS             Command succeed.
+  @retval    EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval    EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashWriteStatus (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT32             ByteCount,
+  IN     UINT8              *StatusValue
+  )
+{
+  EFI_STATUS        Status;
+
+  //
+  // Sends the command to the SPI interface to execute.
+  //
+  Status = SendSpiCmd (
+             This,
+             0,
+             FlashCycleWriteStatus,
+             0,
+             ByteCount,
+             StatusValue
+             );
+
+  return Status;
+}
+
+
+/**
+  Read status register in the flash part.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  ByteCount               Number of bytes in Status data portion of the SPI cycle, the data size is 1 typically
+  @param[out] StatusValue             The Pointer to caller-allocated buffer containing the value of Status register received.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolFlashReadStatus (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *StatusValue
+  )
+{
+  EFI_STATUS        Status;
+
+  //
+  // Sends the command to the SPI interface to execute.
+  //
+  Status = SendSpiCmd (
+             This,
+             0,
+             FlashCycleReadStatus,
+             0,
+             ByteCount,
+             StatusValue
+             );
+
+  return Status;
+}
+
+
+/**
+  Read SC Soft Strap Values.
+
+  @param[in]  This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]  SoftStrapAddr           SC Soft Strap address offset from FPSBA.
+  @param[in]  ByteCount               Number of bytes in SoftStrap data portion of the SPI cycle
+  @param[out] SoftStrapValue          The Pointer to caller-allocated buffer containing SC Soft Strap Value.
+                                      It is the caller's responsibility to make sure Buffer is large enough for the total number of bytes read.
+
+  @retval     EFI_SUCCESS             Command succeed.
+  @retval     EFI_INVALID_PARAMETER   The parameters specified are not valid.
+  @retval     EFI_DEVICE_ERROR        Device error, command aborts abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+SpiProtocolReadPchSoftStrap (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     UINT32             SoftStrapAddr,
+  IN     UINT32             ByteCount,
+  OUT    UINT8              *SoftStrapValue
+  )
+{
+  SPI_INSTANCE      *SpiInstance;
+  UINT32            StrapFlashAddr;
+  EFI_STATUS        Status;
+
+  SpiInstance     = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+
+  ASSERT (SpiInstance->StrapBaseAddress != 0);
+
+  //
+  // SC Strap Flash Address = FPSBA + RamAddr
+  //
+  StrapFlashAddr = SpiInstance->StrapBaseAddress + SoftStrapAddr;
+
+  //
+  // Read SC Soft straps from using execute command
+  //
+  Status = SendSpiCmd (
+             This,
+             FlashRegionDescriptor,
+             FlashCycleRead,
+             StrapFlashAddr,
+             ByteCount,
+             SoftStrapValue
+             );
+
+  return Status;
+}
+
+
+/**
+  This function sends the programmed SPI command to the slave device.
+
+  @param[in]      This                    Pointer to the SC_SPI_PROTOCOL instance.
+  @param[in]      SpiRegionType           The SPI Region type for flash cycle which is listed in the Descriptor
+  @param[in]      FlashCycleType          The Flash SPI cycle type list in HSFC (Hardware Sequencing Flash Control Register) register
+  @param[in]      Address                 The Flash Linear Address must fall within a region for which BIOS has access permissions.
+  @param[in]      ByteCount               Number of bytes in the data portion of the SPI cycle.
+  @param[in, out] Buffer                  Pointer to caller-allocated buffer containing the data received or sent during the SPI cycle.
+
+  @retval         EFI_SUCCESS             SPI command completes successfully.
+  @retval         EFI_DEVICE_ERROR        Device error, the command aborts abnormally.
+  @retval         EFI_ACCESS_DENIED       Some unrecognized command encountered in hardware sequencing mode
+  @retval         EFI_INVALID_PARAMETER   The parameters specified are not valid.
+
+**/
+EFI_STATUS
+SendSpiCmd (
+  IN     SC_SPI_PROTOCOL    *This,
+  IN     FLASH_REGION_TYPE  FlashRegionType,
+  IN     FLASH_CYCLE_TYPE   FlashCycleType,
+  IN     UINT32             Address,
+  IN     UINT32             ByteCount,
+  IN OUT UINT8              *Buffer
+  )
+{
+  EFI_STATUS      Status;
+  UINT32          Index;
+  SPI_INSTANCE    *SpiInstance;
+  UINTN           SpiBaseAddress;
+  UINT32          ScSpiBar0;
+  UINT32          LimitAddress;
+  UINT32          HardwareSpiAddr;
+  UINT16          PermissionBit;
+  UINT32          SpiDataCount;
+  UINT32          FlashCycle;
+  UINT8           BiosCtlSave;
+  UINT32          SmiEnSave;
+  UINT16          ABase;
+
+  Status            = EFI_SUCCESS;
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+  SpiBaseAddress    = SpiInstance->PchSpiBase;
+  ScSpiBar0         = AcquireSpiBar0 (SpiInstance);
+  SpiBaseAddress    = SpiInstance->PchSpiBase;
+  ABase             = SpiInstance->PchAcpiBase;
+
+  DEBUG ((EFI_D_ERROR, "SendSpiCmd Start. \n"));
+
+  //
+  // Disable SMIs to make sure normal mode flash access is not interrupted by an SMI
+  // whose SMI handler accesses flash (e.g. for error logging)
+  //
+  // *** NOTE: if the SMI_LOCK bit is set (i.e., PMC PCI Offset A0h [4]='1'),
+  // clearing B_GBL_SMI_EN will not have effect. In this situation, some other
+  // synchronization methods must be applied here or in the consumer of the
+  // SendSpiCmd. An example method is disabling the specific SMI sources
+  // whose SMI handlers access flash before flash cycle and re-enabling the SMI
+  // sources after the flash cycle .
+  //
+  SmiEnSave   = IoRead32 ((UINTN) (ABase + R_SMI_EN));
+  IoWrite32 ((UINTN) (ABase + R_SMI_EN), SmiEnSave & (UINT32) (~B_SMI_EN_GBL_SMI));
+  BiosCtlSave = MmioRead8 (SpiBaseAddress + R_SPI_BCR) & B_SPI_BCR_SRC;
+
+  //
+  // If it's write cycle, disable Prefetching, Caching and disable BIOS Write Protect
+  //
+  if ((FlashCycleType == FlashCycleWrite) ||
+      (FlashCycleType == FlashCycleErase)) {
+    DEBUG ((EFI_D_ERROR, "DisableBiosWriteProtect Start. \n"));
+    Status = DisableBiosWriteProtect ();
+    DEBUG ((EFI_D_ERROR, "DisableBiosWriteProtect End. Status = 0x%x\n", Status));
+
+    if (EFI_ERROR (Status)) {
+      goto SendSpiCmdEnd;
+    }
+    MmioAndThenOr32 (
+      SpiBaseAddress + R_SPI_BCR,
+      (UINT32) (~B_SPI_BCR_SRC),
+      (UINT32) (V_SPI_BCR_SRC_PREF_DIS_CACHE_DIS <<  B_SPI_BCR_SRC)
+      );
+  }
+
+  //
+  // Make sure it's safe to program the command.
+  //
+  if (!WaitForSpiCycleComplete (This, ScSpiBar0, FALSE)) {
+    Status = EFI_DEVICE_ERROR;
+    goto SendSpiCmdEnd;
+  }
+
+  HardwareSpiAddr = Address;
+  if ((FlashCycleType == FlashCycleRead) ||
+      (FlashCycleType == FlashCycleWrite) ||
+      (FlashCycleType == FlashCycleErase)) {
+    switch (FlashRegionType) {
+      case FlashRegionDescriptor:
+        if (FlashCycleType == FlashCycleRead) {
+          PermissionBit = B_SPI_FRAP_BRRA_FLASHD;
+        } else {
+          PermissionBit = B_SPI_FRAP_BRRA_FLASHD;
+        }
+        HardwareSpiAddr += (MmioRead32 (ScSpiBar0 + R_SPI_FREG0_FLASHD) &
+                            B_SPI_FREG0_BASE_MASK) << N_SPI_FREG0_BASE;
+        LimitAddress = (MmioRead32 (ScSpiBar0 + R_SPI_FREG0_FLASHD) &
+                        B_SPI_FREG0_LIMIT_MASK) >> N_SPI_FREG0_LIMIT;
+        break;
+      case FlashRegionBios:
+        if (FlashCycleType == FlashCycleRead) {
+          PermissionBit = B_SPI_FRAP_BRRA_BIOS;
+        } else {
+          PermissionBit = B_SPI_FRAP_BRRA_BIOS;
+        }
+        HardwareSpiAddr += (MmioRead32 (ScSpiBar0 + R_SPI_FREG1_BIOS) &
+                            B_SPI_FREG1_BASE_MASK) << N_SPI_FREG1_BASE;
+        LimitAddress = (MmioRead32 (ScSpiBar0 + R_SPI_FREG1_BIOS) &
+                        B_SPI_FREG1_LIMIT_MASK) >> N_SPI_FREG1_LIMIT;
+        break;
+      case FlashRegionMe:
+        if (FlashCycleType == FlashCycleRead) {
+          PermissionBit = B_SPI_FRAP_BRRA_SEC;
+        } else {
+          PermissionBit = B_SPI_FRAP_BRWA_SEC;
+        }
+        HardwareSpiAddr += (MmioRead32 (ScSpiBar0 + R_SPI_FREG2_SEC) &
+                            B_SPI_FREG2_BASE_MASK) << N_SPI_FREG2_BASE;
+        LimitAddress = (MmioRead32 (ScSpiBar0 + R_SPI_FREG2_SEC) &
+                        B_SPI_FREG2_LIMIT_MASK) >> N_SPI_FREG2_LIMIT;
+        break;
+      case FlashRegionGbE:
+        if (FlashCycleType == FlashCycleRead) {
+          PermissionBit = B_SPI_FRAP_BRRA_GBE;
+        } else {
+          PermissionBit = B_SPI_FRAP_BRWA_GBE;
+        }
+        HardwareSpiAddr += (MmioRead32 (ScSpiBar0 + R_SPI_FREG3_GBE) &
+                            B_SPI_FREG3_BASE_MASK) << N_SPI_FREG3_BASE;
+        LimitAddress = (MmioRead32 (ScSpiBar0 + R_SPI_FREG3_GBE) &
+                        B_SPI_FREG3_LIMIT_MASK) >> N_SPI_FREG3_LIMIT;
+        break;
+      case FlashRegionPlatformData:
+        if (FlashCycleType == FlashCycleRead) {
+          PermissionBit = B_SPI_FRAP_BRRA_PLATFORM;
+        } else {
+          PermissionBit = B_SPI_FRAP_BRWA_PLATFORM;
+        }
+        HardwareSpiAddr += (MmioRead32 (ScSpiBar0 + R_SPI_FREG4_PLATFORM_DATA) &
+                            B_SPI_FREG4_BASE_MASK) << N_SPI_FREG4_BASE;
+        LimitAddress = (MmioRead32 (ScSpiBar0 + R_SPI_FREG4_PLATFORM_DATA) &
+                        B_SPI_FREG4_LIMIT_MASK) >> N_SPI_FREG4_LIMIT;
+        break;
+      case FlashRegionAll:
+        //
+        // FlashRegionAll indicates address is relative to flash device (i.e., address is Flash Linear Address)
+        // No error checking for this case
+        //
+        LimitAddress = 0;
+        PermissionBit = 0;
+        break;
+      default:
+        Status = EFI_UNSUPPORTED;
+        goto SendSpiCmdEnd;
+    }
+    if ((LimitAddress != 0) && (Address > LimitAddress)) {
+      Status = EFI_INVALID_PARAMETER;
+      goto SendSpiCmdEnd;
+    }
+
+    //
+    // If the operation is read, but the region attribute is not read allowed, return error.
+    // If the operation is write, but the region attribute is not write allowed, return error.
+    //
+    if ((PermissionBit != 0) && ((SpiInstance->RegionPermission & PermissionBit) == 0)) {
+      Status = EFI_ACCESS_DENIED;
+      DEBUG ((EFI_D_ERROR, " if ((PermissionBit != 0) && ((SpiInstance->RegionPermission & PermissionBit) == 0)) {  Status = EFI_ACCESS_DENIED \n"));
+      goto SendSpiCmdEnd;
+    }
+  }
+
+  //
+  // Check for SC SPI hardware sequencing required commands
+  //
+  FlashCycle = 0;
+  switch (FlashCycleType) {
+    case FlashCycleRead:
+      FlashCycle = (UINT32) (V_SPI_HSFS_CYCLE_READ << N_SPI_HSFS_CYCLE);
+      break;
+    case FlashCycleWrite:
+      FlashCycle = (UINT32) (V_SPI_HSFS_CYCLE_WRITE << N_SPI_HSFS_CYCLE);
+      break;
+    case FlashCycleErase:
+      if (((ByteCount % SIZE_4KB) != 0) ||
+          ((HardwareSpiAddr % SIZE_4KB) != 0)) {
+        ASSERT (FALSE);
+        Status = EFI_INVALID_PARAMETER;
+        goto SendSpiCmdEnd;
+      }
+      break;
+    case FlashCycleReadSfdp:
+      FlashCycle = (UINT32) (V_SPI_HSFS_CYCLE_READ_SFDP << N_SPI_HSFS_CYCLE);
+      break;
+    case FlashCycleReadJedecId:
+      FlashCycle = (UINT32) (V_SPI_HSFS_CYCLE_READ_JEDEC_ID << N_SPI_HSFS_CYCLE);
+      break;
+    case FlashCycleWriteStatus:
+      FlashCycle = (UINT32) (V_SPI_HSFS_CYCLE_WRITE_STATUS << N_SPI_HSFS_CYCLE);
+      break;
+    case FlashCycleReadStatus:
+      FlashCycle = (UINT32) (V_SPI_HSFS_CYCLE_READ_STATUS << N_SPI_HSFS_CYCLE);
+      break;
+    default:
+      //
+      // Unrecognized Operation
+      //
+      ASSERT (FALSE);
+      Status = EFI_INVALID_PARAMETER;
+      goto SendSpiCmdEnd;
+      break;
+  }
+
+  do {
+    SpiDataCount = ByteCount;
+    if ((FlashCycleType == FlashCycleRead) || (FlashCycleType == FlashCycleWrite)) {
+      //
+      // Trim at 256 byte boundary per operation,
+      // - SC SPI controller requires trimming at 4KB boundary
+      // - Some SPI chips require trimming at 256 byte boundary for write operation
+      // - Trimming has limited performance impact as we can read / write at most 64 byte
+      //   per operation
+      //
+      if (HardwareSpiAddr + ByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 - 1))) {
+        SpiDataCount = (((UINT32) (HardwareSpiAddr) + BIT8) &~(BIT8 - 1)) - (UINT32) (HardwareSpiAddr);
+      }
+      //
+      // Calculate the number of bytes to shift in/out during the SPI data cycle.
+      // Valid settings for the number of bytes during each data portion of the
+      // SC SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64
+      //
+      if (SpiDataCount >= 64) {
+        SpiDataCount = 64;
+      } else if ((SpiDataCount &~0x07) != 0) {
+        SpiDataCount = SpiDataCount &~0x07;
+      }
+    }
+    if (FlashCycleType == FlashCycleErase) {
+      if (((ByteCount / SIZE_64KB) != 0) &&
+          ((ByteCount % SIZE_64KB) == 0) &&
+          ((HardwareSpiAddr % SIZE_64KB) == 0)) {
+        if (HardwareSpiAddr < SpiInstance->Component1StartAddr) {
+          //
+          // Check whether Component0 support 64k Erase
+          //
+          if ((SpiInstance->SfdpVscc0Value & B_SPI_LVSCC_EO_64K) != 0) {
+            SpiDataCount = SIZE_64KB;
+          } else {
+            SpiDataCount = SIZE_4KB;
+          }
+        } else {
+          //
+          // Check whether Component1 support 64k Erase
+          //
+          if ((SpiInstance->SfdpVscc1Value & B_SPI_LVSCC_EO_64K) != 0) {
+            SpiDataCount = SIZE_64KB;
+          } else {
+            SpiDataCount = SIZE_4KB;
+          }
+        }
+      } else {
+        SpiDataCount = SIZE_4KB;
+      }
+      if (SpiDataCount == SIZE_4KB) {
+        FlashCycle = (UINT32) (V_SPI_HSFS_CYCLE_4K_ERASE << N_SPI_HSFS_CYCLE);
+      } else {
+        FlashCycle = (UINT32) (V_SPI_HSFS_CYCLE_64K_ERASE << N_SPI_HSFS_CYCLE);
+      }
+    }
+    //
+    // If it's write cycle, load data into the SPI data buffer.
+    //
+    if ((FlashCycleType == FlashCycleWrite) || (FlashCycleType == FlashCycleWriteStatus)) {
+      if ((SpiDataCount & 0x07) != 0) {
+        //
+        // Use Byte write if Data Count is 0, 1, 2, 3, 4, 5, 6, 7
+        //
+        for (Index = 0; Index < SpiDataCount; Index++) {
+          MmioWrite8 (ScSpiBar0 + R_SPI_FDATA00 + Index, Buffer[Index]);
+        }
+      } else {
+        //
+        // Use Dword write if Data Count is 8, 16, 24, 32, 40, 48, 56, 64
+        //
+        for (Index = 0; Index < SpiDataCount; Index += sizeof (UINT32)) {
+          MmioWrite32 (ScSpiBar0 + R_SPI_FDATA00 + Index, *(UINT32 *) (Buffer + Index));
+        }
+      }
+    }
+
+    //
+    // Set the Flash Address
+    //
+    MmioWrite32 (
+      (ScSpiBar0 + R_SPI_FADDR),
+      (UINT32) (HardwareSpiAddr & B_SPI_FADDR_MASK)
+      );
+
+    //
+    // Set Data count, Flash cycle, and Set Go bit to start a cycle
+    //
+    MmioAndThenOr32 (
+      ScSpiBar0 + R_SPI_HSFS,
+      (UINT32) (~(B_SPI_HSFS_FDBC_MASK | B_SPI_HSFS_CYCLE_MASK)),
+      (UINT32) (((SpiDataCount - 1) << N_SPI_HSFS_FDBC) | FlashCycle | B_SPI_HSFS_CYCLE_FGO)
+      );
+
+    //
+    // end of command execution
+    //
+    // Wait the SPI cycle to complete.
+    //
+    if (!WaitForSpiCycleComplete (This, ScSpiBar0, TRUE)) {
+      ASSERT (FALSE);
+      Status = EFI_DEVICE_ERROR;
+      goto SendSpiCmdEnd;
+    }
+
+    //
+    // If it's read cycle, load data into the caller's buffer.
+    //
+    if ((FlashCycleType == FlashCycleRead) ||
+        (FlashCycleType == FlashCycleReadSfdp) ||
+        (FlashCycleType == FlashCycleReadJedecId) ||
+        (FlashCycleType == FlashCycleReadStatus)) {
+      if ((SpiDataCount & 0x07) != 0) {
+        //
+        // Use Byte read if Data Count is 0, 1, 2, 3, 4, 5, 6, 7
+        //
+        for (Index = 0; Index < SpiDataCount; Index++) {
+          Buffer[Index] = MmioRead8 (ScSpiBar0 + R_SPI_FDATA00 + Index);
+        }
+      } else {
+        //
+        // Use Dword read if Data Count is 8, 16, 24, 32, 40, 48, 56, 64
+        //
+        for (Index = 0; Index < SpiDataCount; Index += sizeof (UINT32)) {
+          *(UINT32 *) (Buffer + Index) = MmioRead32 (ScSpiBar0 + R_SPI_FDATA00 + Index);
+        }
+      }
+    }
+
+    HardwareSpiAddr += SpiDataCount;
+    Buffer += SpiDataCount;
+    ByteCount -= SpiDataCount;
+  } while (ByteCount > 0);
+
+SendSpiCmdEnd:
+  DEBUG ((EFI_D_ERROR, "SendSpiCmd End. Status = 0x%x\n", Status));
+
+  //
+  // Restore the settings for SPI Prefetching and Caching and enable BIOS Write Protect.
+  //
+  if ((FlashCycleType == FlashCycleWrite) ||
+      (FlashCycleType == FlashCycleErase)) {
+    EnableBiosWriteProtect ();
+    MmioAndThenOr8 (
+      SpiBaseAddress + R_SPI_BCR,
+      (UINT8) ~B_SPI_BCR_SRC,
+      BiosCtlSave
+      );
+  }
+
+  //
+  // Restore SMIs.
+  //
+  IoWrite32 ((UINTN) (ABase + R_SMI_EN), SmiEnSave);
+  ReleaseSpiBar0 (SpiInstance);
+
+  return Status;
+}
+
+
+/**
+  Wait execution cycle to complete on the SPI interface.
+
+  @param[in] This                 The SPI protocol instance
+  @param[in] ScSpiBar0            Spi MMIO base address
+  @param[in] ErrorCheck           TRUE if the SpiCycle needs to do the error check
+
+  @retval    TRUE                 SPI cycle completed on the interface.
+  @retval    FALSE                Time out while waiting the SPI cycle to complete.
+                                  It's not safe to program the next command on the SPI interface.
+
+**/
+BOOLEAN
+WaitForSpiCycleComplete (
+  IN     SC_SPI_PROTOCOL   *This,
+  IN     UINT32             ScSpiBar0,
+  IN     BOOLEAN            ErrorCheck
+  )
+{
+  UINT64        WaitTicks;
+  UINT64        WaitCount;
+  UINT32        Data32;
+  SPI_INSTANCE  *SpiInstance;
+
+  SpiInstance       = SPI_INSTANCE_FROM_SPIPROTOCOL (This);
+
+  //
+  // Convert the wait period allowed into to tick count
+  //
+  WaitCount = WAIT_TIME / WAIT_PERIOD;
+
+  //
+  // Wait for the SPI cycle to complete.
+  //
+  for (WaitTicks = 0; WaitTicks < WaitCount; WaitTicks++) {
+    Data32 = MmioRead32 (ScSpiBar0 + R_SPI_HSFS);
+    if ((Data32 & B_SPI_HSFS_SCIP) == 0) {
+      MmioWrite32 (ScSpiBar0 + R_SPI_HSFS, B_SPI_HSFS_FCERR | B_SPI_HSFS_FDONE);
+      if ( ((Data32 & B_SPI_HSFS_FCERR) != 0) && (ErrorCheck == TRUE)) {
+        return FALSE;
+      } else {
+        return TRUE;
+      }
+    }
+    PchPmTimerStallRuntimeSafe (SpiInstance->PchAcpiBase, WAIT_PERIOD);
+  }
+
+  return FALSE;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.c
new file mode 100644
index 0000000..f2a15ea
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.c
@@ -0,0 +1,313 @@
+/** @file
+  SC SPI Runtime Driver implements the SPI Host Controller Compatibility Interface.
+
+  Copyright (c) 2004 - 2017, 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 "ScSpi.h"
+
+///
+/// Global variables
+///
+GLOBAL_REMOVE_IF_UNREFERENCED SPI_INSTANCE                  *mSpiInstance;
+
+///
+/// PchSpiBar0PhysicalAddr keeps the reserved MMIO range assiged to SPI from PEI.
+/// It won't be updated no matter the SPI MMIO is reallocated by BIOS PCI enum.
+/// And it's used to override the SPI BAR0 register in runtime environment,
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32                        mPchSpiBar0PhysicalAddr;
+
+///
+/// PchSpiBar0VirtualAddr keeps the virtual address of PchSpiBar0PhysicalAddr.
+/// And it's used to provide the SPI BAR0 virtual address mapping to PchSpiBar0PhysicalAddr
+/// in runtime environment.
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32                        mPchSpiBar0VirtualAddr;
+GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN                       mRuntimeFlag;
+
+//
+// Function implementations
+//
+/**
+  Fixup internal data pointers so that the services can be called in virtual mode.
+
+  @param[in] Event                The event registered.
+  @param[in] Context              Event context. Not used in this event handler.
+
+**/
+VOID
+EFIAPI
+PchSpiVirtualAddressChangeEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  mRuntimeFlag = TRUE;
+
+  EfiConvertPointer (0x0, (VOID **) &mPchSpiBar0VirtualAddr);
+  EfiConvertPointer (0x0, (VOID **) &(mSpiInstance->PchSpiBase));
+  EfiConvertPointer (0x0, (VOID **) &(mSpiInstance->SpiProtocol.FlashRead));
+  EfiConvertPointer (0x0, (VOID **) &(mSpiInstance->SpiProtocol.FlashWrite));
+  EfiConvertPointer (0x0, (VOID **) &(mSpiInstance->SpiProtocol.FlashErase));
+  EfiConvertPointer (0x0, (VOID **) &(mSpiInstance->SpiProtocol.FlashReadSfdp));
+  EfiConvertPointer (0x0, (VOID **) &(mSpiInstance->SpiProtocol.FlashReadJedecId));
+  EfiConvertPointer (0x0, (VOID **) &(mSpiInstance->SpiProtocol.FlashWriteStatus));
+  EfiConvertPointer (0x0, (VOID **) &(mSpiInstance->SpiProtocol.FlashReadStatus));
+  EfiConvertPointer (0x0, (VOID **) &(mSpiInstance->SpiProtocol.ReadPchSoftStrap));
+  EfiConvertPointer (0x0, (VOID **) &mSpiInstance);
+}
+
+
+/**
+  SPI Runtime DXE Module Entry Point.
+
+  Introduction:
+    The SPI Runtime DXE module provide a standard way for other modules to use the PCH SPI Interface in DXE/Runtime.
+
+  Pre:
+    If SPI Runtime DXE driver is run before Status Code Runtime Protocol is installed
+    and there is the need to use Status code in the driver, it will be necessary
+    to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to the dependency file.
+
+  Result:
+    The SPI Runtime DXE driver produces SC_SPI_PROTOCOL.
+
+  Integration Check List:
+    This driver supports Descriptor Mode only.
+    This driver supports Hardware Sequence only.
+
+  @param[in] ImageHandle             Image handle of this driver.
+  @param[in] SystemTable             Global system service table.
+
+  @retval    EFI_SUCCESS             Initialization complete.
+  @retval    EFI_UNSUPPORTED         The chipset is unsupported by this driver.
+  @retval    EFI_OUT_OF_RESOURCES    Do not have enough resources to initialize the driver.
+  @retval    EFI_DEVICE_ERROR        Device error, driver exits abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallScSpi (
+  IN EFI_HANDLE            ImageHandle,
+  IN EFI_SYSTEM_TABLE      *SystemTable
+  )
+{
+  EFI_STATUS                      Status;
+  UINT64                          BaseAddress;
+  UINT64                          Length;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR SpiPciMemorySpaceDescriptor;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR SpiBar0MemorySpaceDescriptor;
+  UINT64                          Attributes;
+  EFI_EVENT                       AddressChangeEvent;
+
+  DEBUG ((DEBUG_INFO, "InstallScSpi() Start\n"));
+
+  //
+  // Allocate Runtime memory for the SPI protocol instance.
+  //
+  mSpiInstance = AllocateRuntimeZeroPool (sizeof (SPI_INSTANCE));
+  if (mSpiInstance == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Initialize the SPI protocol instance
+  //
+  Status = SpiProtocolConstructor (mSpiInstance);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  mPchSpiBar0PhysicalAddr     = SC_SPI_BASE_ADDRESS;
+  mPchSpiBar0VirtualAddr      = mPchSpiBar0PhysicalAddr;
+
+  //
+  // Install the PCH_SPI_PROTOCOL interface
+  //
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &(mSpiInstance->Handle),
+                  &gScSpiProtocolGuid,
+                  &(mSpiInstance->SpiProtocol),
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    FreePool (mSpiInstance);
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Create Address Change event
+  //
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  PchSpiVirtualAddressChangeEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &AddressChangeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Set SPI space in GCD to be RUNTIME so that the range will be supported in
+  // virtual address mode in EFI aware OS runtime.
+  // It will assert if SPI Memory Space is not allocated
+  // The caller is responsible for the existence and allocation of the SPi Memory Spaces
+  //
+  //
+  //  SPI memory space
+  //
+  BaseAddress = (EFI_PHYSICAL_ADDRESS) mSpiInstance->PchSpiBase;
+  Length      = 0x1000;
+
+  Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &SpiPciMemorySpaceDescriptor);
+  ASSERT_EFI_ERROR (Status);
+
+  Attributes  = SpiPciMemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;
+  Status      = gDS->SetMemorySpaceAttributes (
+                       BaseAddress,
+                       Length,
+                       Attributes
+                       );
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  //  SPI MMIO memory space
+  //
+  BaseAddress = (EFI_PHYSICAL_ADDRESS) mPchSpiBar0PhysicalAddr;
+  Length      = 0x1000;
+
+  Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &SpiBar0MemorySpaceDescriptor);
+  ASSERT_EFI_ERROR (Status);
+
+  Attributes  = SpiBar0MemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME;
+  Status      = gDS->SetMemorySpaceAttributes (
+                       BaseAddress,
+                       Length,
+                       Attributes
+                       );
+  ASSERT_EFI_ERROR (Status);
+  DEBUG ((DEBUG_INFO, "InstallScSpi() End\n"));
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Acquire SC SPI MMIO address.
+  It is not expected for this BAR0 to change because the SPI device is hidden
+  from the OS for SKL PCH LP/H B stepping and above (refer to section 3.5.1),
+  but if it is ever different from the preallocated address, reassign it back.
+
+  @param[in] SpiInstance          Pointer to SpiInstance to initialize
+
+  @retval    UINT32               Return SPI MMIO address
+
+**/
+UINT32
+AcquireSpiBar0 (
+  IN  SPI_INSTANCE                *SpiInstance
+  )
+{
+  UINT32                          SpiBar0;
+
+  //
+  // Save original SPI MMIO address
+  //
+  SpiBar0 = MmioRead32 (SpiInstance->PchSpiBase + R_SPI_BASE) & ~(B_SPI_BAR0_MASK);
+
+  if (SpiBar0 != mPchSpiBar0PhysicalAddr) {
+    //
+    // Temporary disable MSE, and override with SPI reserved MMIO address, then enable MSE.
+    //
+    MmioAnd8 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE);
+    MmioWrite32 (SpiInstance->PchSpiBase + R_SPI_BASE, mPchSpiBar0PhysicalAddr);
+    MmioOr8 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+  }
+
+  if (mRuntimeFlag) {
+    return mPchSpiBar0VirtualAddr;
+  } else {
+    return mPchSpiBar0PhysicalAddr;
+  }
+}
+
+
+/**
+  Release SC spi mmio address. Do nothing.
+
+  @param[in] SpiInstance          Pointer to SpiInstance to initialize
+
+**/
+VOID
+ReleaseSpiBar0 (
+  IN     SPI_INSTANCE       *SpiInstance
+  )
+{
+}
+
+
+/**
+  This function is a hook for Spi to disable BIOS Write Protect.
+
+  @retval EFI_SUCCESS             The protocol instance was properly initialized
+  @retval EFI_ACCESS_DENIED       The BIOS Region can only be updated in SMM phase
+
+**/
+EFI_STATUS
+EFIAPI
+DisableBiosWriteProtect (
+  VOID
+  )
+{
+  UINTN                           SpiBaseAddress;
+
+  SpiBaseAddress = mSpiInstance->PchSpiBase;
+  if ((MmioRead8 (SpiBaseAddress + R_SPI_BCR) & B_SPI_BCR_EISS) != 0) {
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // Enable the access to the BIOS space for both read and write cycles
+  //
+  MmioOr8 (
+    SpiBaseAddress + R_SPI_BCR,
+    (UINT8) (B_SPI_BCR_BIOSWE)
+    );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  This function is a hook for Spi to enable BIOS Write Protect.
+
+**/
+VOID
+EFIAPI
+EnableBiosWriteProtect (
+  VOID
+  )
+{
+  UINTN                           SpiBaseAddress;
+
+  SpiBaseAddress = mSpiInstance->PchSpiBase;
+
+  //
+  // Disable the access to the BIOS space for write cycles
+  //
+  MmioAnd8 (
+    SpiBaseAddress + R_SPI_BCR,
+    (UINT8) (~B_SPI_BCR_BIOSWE)
+    );
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.h
new file mode 100644
index 0000000..ad2cb45
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpi.h
@@ -0,0 +1,50 @@
+/** @file
+  Header file for the SC SPI Runtime Driver.
+
+  Copyright (c) 2004 - 2017, 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_SPI_RT_H_
+#define _SC_SPI_RT_H_
+
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Guid/EventGroup.h>
+#include <ScAccess.h>
+#include <Protocol/Spi.h>
+#include <Library/ScSpiCommonLib.h>
+#include <IndustryStandard/Pci30.h>
+
+//
+// Function prototypes used by the SPI protocol.
+//
+/**
+  Fixup internal data pointers so that the services can be called in virtual mode.
+
+  @param[in] Event                The event registered.
+  @param[in] Context              Event context. Not used in this event handler.
+
+**/
+VOID
+EFIAPI
+PchSpiVirtualAddressChangeEvent (
+  IN EFI_EVENT              Event,
+  IN VOID                   *Context
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpiRuntime.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpiRuntime.inf
new file mode 100644
index 0000000..ea8f42a
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/RuntimeDxe/ScSpiRuntime.inf
@@ -0,0 +1,60 @@
+## @file
+#  Component description file for SPI Runtime driver.
+#
+#  Copyright (c) 2004 - 2017, 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                      = ScSpiRuntime
+  FILE_GUID                      = C194C6EA-B68C-4981-B64B-9BD271474B20
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InstallScSpi
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 EBC
+
+[Sources]
+  ScSpi.h
+  ScSpi.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+  BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[LibraryClasses]
+  UefiRuntimeServicesTableLib
+  UefiRuntimeLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  DxeServicesTableLib
+  UefiLib
+  DebugLib
+  MemoryAllocationLib
+  IoLib
+  MmPciLib
+  ScSpiCommonLib
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid ## UNDEFINED
+
+[Protocols]
+  gScSpiProtocolGuid ## PRODUCES
+
+[Depex]
+  gEfiStatusCodeRuntimeProtocolGuid AND
+  TRUE
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.c
new file mode 100644
index 0000000..1a84f6f
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.c
@@ -0,0 +1,249 @@
+/** @file
+  SC SPI SMM Driver implements the SPI Host Controller Compatibility Interface.
+
+  Copyright (c) 2012 - 2017, 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 "ScSpi.h"
+
+///
+/// Global variables
+///
+GLOBAL_REMOVE_IF_UNREFERENCED SPI_INSTANCE          *mSpiInstance;
+
+///
+/// mPchSpiResvMmioAddr keeps the reserved MMIO range assiged to SPI.
+/// In SMM it always set back the reserved MMIO address to SPI BAR0 to ensure the MMIO range
+/// won't overlap with SMRAM range, and trusted.
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32                mSpiResvMmioAddr;
+
+/**
+  SPI Runtime SMM Module Entry Point.
+
+  Introduction:
+    The SPI SMM module provide a standard way for other modules to use the PCH SPI Interface in SMM.
+
+  Pre:
+    EFI_SMM_BASE2_PROTOCOL
+    Documented in System Management Mode Core Interface Specification.
+
+  Result:
+    The SPI SMM driver produces PCH_SPI_PROTOCOL with GUID
+    gPchSmmSpiProtocolGuid which is different from SPI RUNTIME driver.
+
+  Integration Check List:
+    This driver supports Descriptor Mode only.
+    This driver supports Hardware Sequence only.
+    When using SMM SPI Protocol to perform flash access in an SMI handler,
+    and the SMI occurrence is asynchronous to normal mode code execution,
+    proper synchronization mechanism must be applied, e.g. disable SMI before
+    the normal mode SendSpiCmd() starts and re-enable SMI after
+    the normal mode SendSpiCmd() completes.
+    @note The implementation of SendSpiCmd() uses GBL_SMI_EN in
+    SMI_EN register (ABase + 30h) to disable and enable SMIs. But this may
+    not be effective as platform may well set the SMI_LOCK bit (i.e., PMC PCI Offset A0h [4]).
+    So the synchronization at caller level is likely needed.
+
+  @param[in] ImageHandle             Image handle of this driver.
+  @param[in] SystemTable             Global system service table.
+
+  @retval    EFI_SUCCESS             Initialization complete.
+  @retval    EFI_UNSUPPORTED         The chipset is unsupported by this driver.
+  @retval    EFI_OUT_OF_RESOURCES    Do not have enough resources to initialize the driver.
+  @retval    EFI_DEVICE_ERROR        Device error, driver exits abnormally.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallScSpi (
+  IN EFI_HANDLE            ImageHandle,
+  IN EFI_SYSTEM_TABLE      *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Init PCH spi reserved MMIO address.
+  //
+  mSpiResvMmioAddr = SC_SPI_BASE_ADDRESS;
+
+  //
+  // Allocate pool for SPI protocol instance
+  //
+  Status = gSmst->SmmAllocatePool (
+                    EfiRuntimeServicesData,
+                    sizeof (SPI_INSTANCE),
+                    (VOID **) &mSpiInstance
+                    );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (mSpiInstance == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  ZeroMem ((VOID *) mSpiInstance, sizeof (SPI_INSTANCE));
+
+  //
+  // Initialize the SPI protocol instance
+  //
+  Status = SpiProtocolConstructor (mSpiInstance);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Install the SMM SC_SPI_PROTOCOL interface
+  //
+  Status = gSmst->SmmInstallProtocolInterface (
+                    &(mSpiInstance->Handle),
+                    &gScSmmSpiProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &(mSpiInstance->SpiProtocol)
+                    );
+  if (EFI_ERROR (Status)) {
+    gSmst->SmmFreePool (mSpiInstance);
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Acquire SC spi mmio address.
+  It is not expected for this BAR0 to change because the SPI device is hidden
+  from the OS for SKL PCH LP/H B stepping and above (refer to section 3.5.1),
+  but if it is ever different from the preallocated address, reassign it back.
+  In SMM, it always override the BAR0 and returns the reserved MMIO range for SPI.
+
+  @param[in] SpiInstance          Pointer to SpiInstance to initialize
+
+  @retval    PchSpiBar0           Return SPI MMIO address
+
+**/
+UINT32
+AcquireSpiBar0 (
+  IN     SPI_INSTANCE       *SpiInstance
+  )
+{
+  UINT32                          SpiBar0;
+
+  //
+  // Save original SPI MMIO address
+  //
+  SpiBar0 = MmioRead32 (SpiInstance->PchSpiBase + R_SPI_BASE) & B_SPI_BASE_BAR;
+
+  if (SpiBar0 != mSpiResvMmioAddr) {
+    //
+    // Temporary disable MSE, and override with SPI reserved MMIO address, then enable MSE.
+    //
+    MmioAnd8 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, (UINT8) ~EFI_PCI_COMMAND_MEMORY_SPACE);
+    MmioWrite32 (SpiInstance->PchSpiBase + R_SPI_BASE, mSpiResvMmioAddr);
+    MmioOr8 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_MEMORY_SPACE);
+  }
+
+  //
+  // SPIBAR0 will be different before and after PCI enum so need to get it from SPI BAR0 reg.
+  //
+  return mSpiResvMmioAddr;
+}
+
+
+/**
+  Release SC spi mmio address. Do nothing.
+
+  @param[in] SpiInstance          Pointer to SpiInstance to initialize
+
+  @retval     None
+
+**/
+VOID
+ReleaseSpiBar0 (
+  IN     SPI_INSTANCE       *SpiInstance
+  )
+{
+}
+
+
+/**
+  This function is a hook for Spi to disable BIOS Write Protect.
+
+  @param[in] None
+
+  @retval    EFI_SUCCESS             The protocol instance was properly initialized
+  @retval    EFI_ACCESS_DENIED       The BIOS Region can only be updated in SMM phase
+
+**/
+EFI_STATUS
+EFIAPI
+DisableBiosWriteProtect (
+  VOID
+  )
+{
+  UINTN     SpiBaseAddress;
+  UINT32    Data32;
+
+  SpiBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_SC,
+                     PCI_DEVICE_NUMBER_SPI,
+                     PCI_FUNCTION_NUMBER_SPI
+                     );
+
+  //
+  // Set BIOSWE bit (SPI PCI Offset DCh [0]) = 1b
+  // Enable the access to the BIOS space for both read and write cycles
+  //
+  MmioOr8 (
+    SpiBaseAddress + R_SPI_BCR,
+    B_SPI_BCR_BIOSWE
+    );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  This function is a hook for Spi to enable BIOS Write Protect.
+
+  @param[in] None
+
+  @retval    None
+
+**/
+VOID
+EFIAPI
+EnableBiosWriteProtect (
+  VOID
+  )
+{
+  UINTN     SpiBaseAddress;
+  UINT32    Data32;
+
+  SpiBaseAddress = MmPciBase (
+                     DEFAULT_PCI_BUS_NUMBER_SC,
+                     PCI_DEVICE_NUMBER_SPI,
+                     PCI_FUNCTION_NUMBER_SPI
+                     );
+
+  //
+  // Clear BIOSWE bit (SPI PCI Offset DCh [0]) = 0b
+  // Disable the access to the BIOS space for write cycles
+  //
+  MmioAnd8 (
+    SpiBaseAddress + R_SPI_BCR,
+    (UINT8) (~N_SPI_BCR_BIOSWE)
+    );
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.h
new file mode 100644
index 0000000..7b27974
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpi.h
@@ -0,0 +1,33 @@
+/** @file
+  Header file for the SC SPI SMM Driver.
+
+  Copyright (c) 2004 - 2017, 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_SPI_SMM_H_
+#define _SC_SPI_SMM_H_
+
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <IndustryStandard/Pci30.h>
+#include <ScAccess.h>
+#include <Protocol/Spi.h>
+#include <Library/ScSpiCommonLib.h>
+#include <Library/MmPciLib.h>
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpiSmm.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpiSmm.inf
new file mode 100644
index 0000000..9c82067
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Spi/Smm/ScSpiSmm.inf
@@ -0,0 +1,49 @@
+## @file
+#  Component description file for SPI SMM driver.
+#
+#  Copyright (c) 2008 - 2017, 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                   = ScSpiSmm
+  FILE_GUID                   = 27F4917B-A707-4aad-9676-26DF168CBF0D
+  MODULE_TYPE                 = DXE_SMM_DRIVER
+  VERSION_STRING              = 1.0
+  PI_SPECIFICATION_VERSION    = 0x0001000A
+  ENTRY_POINT                 = InstallScSpi
+
+[Sources]
+  ScSpi.h
+  ScSpi.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Silicon/BroxtonSiPkg/BroxtonSiPkg.dec
+  Silicon/BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[LibraryClasses]
+  DebugLib
+  IoLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  BaseLib
+  SmmServicesTableLib
+  ScSpiCommonLib
+  MmPciLib
+
+[Protocols]
+  gScSmmSpiProtocolGuid      ## PRODUCES
+
+[Depex]
+  TRUE
+
-- 
2.7.0.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel