[edk2-devel] [PATCH V2 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP

Chang, Abner via groups.io abner.chang=amd.com at groups.io
Tue Aug 1 07:57:23 UTC 2023


From: Abner Chang <abner.chang at amd.com>

BZ#: 4473
SPI NOR Flash JEDEC Serial Flash Discoverable Driver
implementation.

Signed-off-by: Abner Chang <abner.chang at amd.com>
Cc: Hao A Wu <hao.a.wu at intel.com>
Cc: Ray Ni <ray.ni at intel.com>
Cc: Abdul Lateef Attar <abdattar at amd.com>
---
 .../SpiNorFlashJedecSfdpDxe.inf               |   63 +
 .../SpiNorFlashJedecSfdpSmm.inf               |   63 +
 .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h    |  274 +++
 .../SpiNorFlashJedecSfdpInternal.h            |  294 +++
 .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c    | 1114 +++++++++++
 .../SpiNorFlashJedecSfdp.c                    | 1772 +++++++++++++++++
 .../SpiNorFlashJedecSfdpDxe.c                 |  261 +++
 .../SpiNorFlashJedecSfdpSmm.c                 |  234 +++
 .../SpiNorFlashJedecSfdpDxe.uni               |   13 +
 .../SpiNorFlashJedecSfdpExtra.uni             |   11 +
 .../SpiNorFlashJedecSfdpSmm.uni               |   13 +
 11 files changed, 4112 insertions(+)
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni
 create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni

diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
new file mode 100644
index 00000000000..d3c9c5a0641
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
@@ -0,0 +1,63 @@
+## @file
+#  The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+#  DXE driver INF file.
+#
+#  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# @par Revision Reference:
+#   - JEDEC Standard, JESD216F.02
+#     https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+#
+# @par Glossary:
+#   - SFDP - Serial Flash Discoverable Parameters
+#   - PTP  - Parameter Table Pointer
+##
+
+[Defines]
+  INF_VERSION               = 1.25
+  BASE_NAME                 = SpiNorFlashJedecSfdpDxe
+  FILE_GUID                 = 0DC9C2C7-D450-41BA-9CF7-D2090C35A797
+  MODULE_TYPE               = DXE_DRIVER
+  VERSION_STRING            = 0.1
+  PI_SPECIFICATION_VERSION  = 1.10
+  ENTRY_POINT               = SpiNorFlashJedecSfdpDxeEntry
+  MODULE_UNI_FILE           = SpiNorFlashJedecSfdpDxe.uni
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  TimerLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+
+[Sources]
+  SpiNorFlashJedecSfdpDxe.c
+  SpiNorFlash.c
+  SpiNorFlashJedecSfdp.c
+  SpiNorFlashJedecSfdpInternal.h
+  SpiNorFlash.h
+
+[Protocols]
+  gEfiSpiNorFlashProtocolGuid  ## PROCUDES
+
+[FixedPcd]
+  gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
+  gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds
+
+[Guids]
+  gEdk2JedecSfdpSpiDxeDriverGuid
+
+[Depex]
+  gEdk2JedecSfdpSpiDxeDriverGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  SpiNorFlashJedecSfdpExtra.uni
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
new file mode 100644
index 00000000000..e95dd9f3b56
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
@@ -0,0 +1,63 @@
+## @file
+#  The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+#  SMM driver INF file.
+#
+#  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# @par Revision Reference:
+#   - JEDEC Standard, JESD216F.02
+#     https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+#
+# @par Glossary:
+#   - SFDP - Serial Flash Discoverable Parameters
+#   - PTP  - Parameter Table Pointer
+##
+
+[Defines]
+  INF_VERSION               = 1.25
+  BASE_NAME                 = SpiNorFlashJedecSfdpSmm
+  FILE_GUID                 = AC7884C7-35A2-40AC-B9E0-AD67298E3BBA
+  MODULE_TYPE               = DXE_SMM_DRIVER
+  VERSION_STRING            = 0.1
+  PI_SPECIFICATION_VERSION  = 1.10
+  ENTRY_POINT               = SpiNorFlashJedecSfdpSmmEntry
+  MODULE_UNI_FILE           = SpiNorFlashJedecSfdpSmm.uni
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  SmmServicesTableLib
+  TimerLib
+  UefiDriverEntryPoint
+
+[Sources]
+  SpiNorFlashJedecSfdpSmm.c
+  SpiNorFlash.c
+  SpiNorFlashJedecSfdp.c
+  SpiNorFlashJedecSfdpInternal.h
+  SpiNorFlash.h
+
+[Protocols]
+  gEfiSpiSmmNorFlashProtocolGuid ## PROCUDES
+
+[FixedPcd]
+  gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
+  gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds
+
+[Guids]
+  gEdk2JedecSfdpSpiSmmDriverGuid
+
+[Depex]
+  gEdk2JedecSfdpSpiSmmDriverGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  SpiNorFlashJedecSfdpExtra.uni
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h
new file mode 100644
index 00000000000..ca85ab103ab
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h
@@ -0,0 +1,274 @@
+/** @file
+  Definitions of SPI NOR flash operation functions.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SPI_NOR_FLASH_H_
+#define SPI_NOR_FLASH_H_
+
+#include <PiDxe.h>
+#include <Protocol/SpiNorFlash.h>
+#include <Protocol/SpiIo.h>
+#include "SpiNorFlashJedecSfdpInternal.h"
+
+/**
+  Fill Write Buffer with Opcode, Address, Dummy Bytes, and Data
+
+  @param[in]    Opcode      - Opcode for transaction
+  @param[in]    Address     - SPI Offset Start Address
+  @param[in]    WriteBytes  - Number of bytes to write to SPI device
+  @param[in]    WriteBuffer - Buffer containing bytes to write to SPI device
+
+  @retval       Size of Data in Buffer
+**/
+UINT32
+FillWriteBuffer (
+  IN      SPI_NOR_FLASH_INSTANCE  *SpiNorFlashInstance,
+  IN      UINT8                   Opcode,
+  IN      UINT32                  DummyBytes,
+  IN      UINT8                   AddressBytesSupported,
+  IN      BOOLEAN                 UseAddress,
+  IN      UINT32                  Address,
+  IN      UINT32                  WriteBytes,
+  IN      UINT8                   *WriteBuffer
+  );
+
+/**
+  Set Write Enable Latch
+
+  @param[in]  Instance                 SPI NOR instance with all protocols, etc.
+
+  @retval EFI_SUCCESS           SPI Write Enable succeeded
+  @retval EFI_DEVICE_ERROR      SPI Flash part did not respond properly
+**/
+EFI_STATUS
+SetWel (
+  IN      SPI_NOR_FLASH_INSTANCE  *SpiNorFlashInstance
+  );
+
+/**
+  Check for not device write in progress
+
+  @param[in]  Instance  - SPI NOR instance with all protocols, etc.
+
+  @retval EFI_SUCCESS           Device does not have a write in progress
+  @retval EFI_DEVICE_ERROR      SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitNotWip (
+  IN      SPI_NOR_FLASH_INSTANCE  *SpiNorFlashInstance
+  );
+
+/**
+  Check for write enable latch set and not device write in progress
+
+  @param[in]  Instance  - SPI NOR instance with all protocols, etc.
+
+  @retval EFI_SUCCESS           Device does not have a write in progress and
+                                write enable latch is set
+  @retval EFI_DEVICE_ERROR      SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitWelNotWip (
+  IN      SPI_NOR_FLASH_INSTANCE  *SpiNorFlashInstance
+  );
+
+/**
+  Check for not write enable latch set and not device write in progress
+
+  @param[in]  Instance  - SPI NOR instance with all protocols, etc.
+
+  @retval EFI_SUCCESS           Device does not have a write in progress and
+                                write enable latch is not set
+  @retval EFI_DEVICE_ERROR      SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitNotWelNotWip (
+  IN      SPI_NOR_FLASH_INSTANCE  *SpiNorFlashInstance
+  );
+
+/**
+  Read the 3 byte manufacture and device ID from the SPI flash.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine reads the 3 byte manufacture and device ID from the flash part
+  filling the buffer provided.
+
+  @param[in]  This    Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data structure.
+  @param[out] Buffer  Pointer to a 3 byte buffer to receive the manufacture and
+                      device ID.
+
+
+
+  @retval EFI_SUCCESS            The manufacture and device ID was read
+                                 successfully.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+EFIAPI
+GetFlashId (
+  IN  CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  OUT UINT8                             *Buffer
+  );
+
+/**
+  Read data from the SPI flash.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine reads data from the SPI part in the buffer provided.
+
+  @param[in]  This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                             structure.
+  @param[in]  FlashAddress   Address in the flash to start reading
+  @param[in]  LengthInBytes  Read length in bytes
+  @param[out] Buffer         Address of a buffer to receive the data
+
+  @retval EFI_SUCCESS            The data was read successfully.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL, or
+                                 FlashAddress >= This->FlashSize, or
+                                 LengthInBytes > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+ReadData (
+  IN  CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN  UINT32                            FlashAddress,
+  IN  UINT32                            LengthInBytes,
+  OUT UINT8                             *Buffer
+  );
+
+/**
+  Read data from the SPI flash at not fast speed
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine reads data from the SPI part in the buffer provided.
+
+  @param[in]  This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                             structure.
+  @param[in]  FlashAddress   Address in the flash to start reading
+  @param[in]  LengthInBytes  Read length in bytes
+  @param[out] Buffer         Address of a buffer to receive the data
+
+  @retval EFI_SUCCESS            The data was read successfully.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL, or
+                                 FlashAddress >= This->FlashSize, or
+                                 LengthInBytes > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+LfReadData (
+  IN  CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN  UINT32                            FlashAddress,
+  IN  UINT32                            LengthInBytes,
+  OUT UINT8                             *Buffer
+  );
+
+/**
+  Read the flash status register.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine reads the flash part status register.
+
+  @param[in]  This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                             structure.
+  @param[in]  LengthInBytes  Number of status bytes to read.
+  @param[out] FlashStatus    Pointer to a buffer to receive the flash status.
+
+  @retval EFI_SUCCESS  The status register was read successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadStatus (
+  IN  CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN  UINT32                            LengthInBytes,
+  OUT UINT8                             *FlashStatus
+  );
+
+/**
+  Write the flash status register.
+
+  This routine must be called at or below TPL_N OTIFY.
+  This routine writes the flash part status register.
+
+  @param[in] This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                            structure.
+  @param[in] LengthInBytes  Number of status bytes to write.
+  @param[in] FlashStatus    Pointer to a buffer containing the new status.
+
+  @retval EFI_SUCCESS           The status write was successful.
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate the write buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteStatus (
+  IN CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN UINT32                            LengthInBytes,
+  IN UINT8                             *FlashStatus
+  );
+
+/**
+  Write data to the SPI flash.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine breaks up the write operation as necessary to write the data to
+  the SPI part.
+
+  @param[in] This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                            structure.
+  @param[in] FlashAddress   Address in the flash to start writing
+  @param[in] LengthInBytes  Write length in bytes
+  @param[in] Buffer         Address of a buffer containing the data
+
+  @retval EFI_SUCCESS            The data was written successfully.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL, or
+                                 FlashAddress >= This->FlashSize, or
+                                 LengthInBytes > This->FlashSize - FlashAddress
+  @retval EFI_OUT_OF_RESOURCES   Insufficient memory to copy buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteData (
+  IN CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN UINT32                            FlashAddress,
+  IN UINT32                            LengthInBytes,
+  IN UINT8                             *Buffer
+  );
+
+/**
+  Efficiently erases one or more 4KiB regions in the SPI flash.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine uses a combination of 4 KiB and larger blocks to erase the
+  specified area.
+
+  @param[in] This          Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                           structure.
+  @param[in] FlashAddress  Address within a 4 KiB block to start erasing
+  @param[in] BlockCount    Number of 4 KiB blocks to erase
+
+  @retval EFI_SUCCESS            The erase was completed successfully.
+  @retval EFI_INVALID_PARAMETER  FlashAddress >= This->FlashSize, or
+                                 BlockCount * 4 KiB
+                                   > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+Erase (
+  IN CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN UINT32                            FlashAddress,
+  IN UINT32                            BlockCount
+  );
+
+#endif // SPI_NOR_FLASH_H_
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h
new file mode 100644
index 00000000000..6812559b880
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h
@@ -0,0 +1,294 @@
+/** @file
+  SPI NOR flash driver internal definitions.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SPI_NOR_FLASH_INSTANCE_H_
+#define SPI_NOR_FLASH_INSTANCE_H_
+
+#include <PiDxe.h>
+#include <Protocol/SpiNorFlash.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+
+#define SPI_NOR_FLASH_SIGNATURE  SIGNATURE_32 ('s', 'n', 'f', 'm')
+
+#define SPI_NOR_FLASH_FROM_THIS(a) CR (a, SPI_NOR_FLASH_INSTANCE, Protocol, SPI_NOR_FLASH_SIGNATURE)
+
+typedef struct {
+  LIST_ENTRY    NextFastReadCap;     ///< Link list to next Fast read capability
+  UINT8         FastReadInstruction; ///< Fast read instruction.
+  UINT8         ModeClocks;          ///< Fast read clock.
+  UINT8         WaitStates;          ///< Fast read wait dummy clocks
+} SFPD_FAST_READ_CAPBILITY_RECORD;
+
+typedef struct {
+  LIST_ENTRY    NextEraseType;      ///< Link list to next erase type.
+  UINT16        EraseType;          ///< Erase type this flash device supports.
+  UINT8         EraseInstruction;   ///< Erase instruction
+  UINT32        EraseSizeInByte;    ///< The size of byte in 2^EraseSize the erase type command
+                                    ///< can erase.
+  UINT32        EraseTypicalTime;   ///< Time the device typically takes to erase this type
+                                    ///< size.
+  UINT64        EraseTimeout;       ///< Maximum typical erase timeout.
+} SFDP_SUPPORTED_ERASE_TYPE_RECORD;
+
+typedef enum {
+  SearchEraseTypeByType = 1,
+  SearchEraseTypeByCommand,
+  SearchEraseTypeBySize,
+  SearchEraseTypeBySmallestSize,
+  SearchEraseTypeByBiggestSize
+} SFDP_SEARCH_ERASE_TYPE;
+
+typedef struct {
+  LIST_ENTRY                                NextCommand;          ///< Link list to next detection command.
+  UINT32                                    CommandAddress;       ///< Address to issue the command.
+  UINT8                                     CommandInstruction;   ///< Detection command instruction.
+  UINT8                                     LatencyInClock;       ///< Command latency in clocks.
+  SPDF_CONFIGURATION_COMMAND_ADDR_LENGTH    CommandAddressLength; ///< Adddress length of detection command.
+  UINT8                                     ConfigurationBitMask; ///< The interest bit of the byte data retunred
+                                                                  ///< after sending the detection command.
+} SFDP_SECTOR_MAP_DETECTION_RECORD;
+
+typedef struct {
+  LIST_ENTRY    NextRegion;                                      ///< Link list to the next region.
+  UINT32        RegionAddress;                                   ///< Region starting address.
+  UINT32        RegionTotalSize;                                 ///< Region total size in bytes.
+  UINT32        RegionSectors;                                   ///< Sectors in this region.
+  UINT32        SectorSize;                                      ///< Sector size in byte (Minimum blcok erase size)
+  UINT8         SupportedEraseTypeNum;                           ///< Number of erase type supported.
+  UINT8         SupportedEraseType[SFDP_ERASE_TYPES_NUMBER];     ///< Erase types supported.
+  UINT32        EraseTypeBySizeBitmap;                           ///< The bitmap of supoprted srase block sizes.
+                                                                 ///< from big to small.
+} SFDP_SECTOR_REGION_RECORD;
+
+typedef struct {
+  LIST_ENTRY    NextDescriptor;                                  ///< Link list to next flash map descriptor.
+  UINT8         ConfigurationId;                                 ///< The ID of this configuration.
+  UINT8         RegionCount;                                     ///< The regions of this sector map configuration.
+  LIST_ENTRY    RegionList;                                      ///< The linked list of the regions.
+} SFDP_SECTOR_MAP_RECORD;
+
+typedef struct {
+  UINTN                         Signature;
+  EFI_HANDLE                    Handle;
+  EFI_SPI_NOR_FLASH_PROTOCOL    Protocol;
+  EFI_SPI_IO_PROTOCOL           *SpiIo;
+  UINT32                        SfdpBasicFlashByteCount;
+  UINT32                        SfdpSectorMapByteCount;
+  SFDP_BASIC_FLASH_PARAMETER    *SfdpBasicFlash;
+  SFDP_SECTOR_MAP_TABLE         *SfdpFlashSectorMap;
+  UINT8                         *SpiTransactionWriteBuffer;
+  UINT32                        SpiTransactionWriteBufferIndex;
+  //
+  // SFDP information.
+  //
+  SFDP_HEADER                   SfdpHeader;              ///< SFDP header.
+  UINT32                        FlashDeviceSize;         ///< The total size of this flash device.
+  UINT8                         CurrentAddressBytes;     ///< The current address bytes.
+
+  //
+  // This is a linked list in which the Fast Read capability tables
+  // are linked from the low performance transfer to higher performance
+  // transfer. The SPI read would use the first Fast Read entry for
+  // SPI read operation.
+  //
+  LIST_ENTRY                    FastReadTableList;
+
+  LIST_ENTRY                    SupportedEraseTypes;      ///< The linked list of supported erase types.
+  BOOLEAN                       Uniform4KEraseSupported;  ///< The flash device supoprts uniform 4K erase.
+  BOOLEAN                       WriteEnableLatchRequired; ///< Wether Write Enable Latch is supported.
+  UINT8                         WriteEnableLatchCommand;  ///< Write Enable Latch command.
+  //
+  // Below is the linked list of flash device sector
+  // map configuration detection command and map descriptors.
+  //
+  BOOLEAN                       ConfigurationCommandsNeeded; ///< Indicates whether sector map
+                                                             ///< configuration detection is
+                                                             ///< required.
+  LIST_ENTRY                    ConfigurationCommandList;    ///< The linked list of configuration
+                                                             ///< detection command sequence.
+  LIST_ENTRY                    ConfigurationMapList;        ///< The linked list of configuration
+                                                             ///< map descriptors.
+  SFDP_SECTOR_MAP_RECORD        *CurrentSectorMap;           ///< The current activated flash device
+                                                             ///< sector map.
+} SPI_NOR_FLASH_INSTANCE;
+
+/**
+  This routine returns the desired Fast Read mode.
+
+  @param[in]           Instance                 Spi Nor Flash Instance data with pointer to
+                                                EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+  @param[in,out]       FastReadInstruction      Fast Read instruction, the input is
+                                                the default value.
+  @param[in,out]       FastReadOperationClock   Fast Read operation clock, the input is
+                                                the default value.
+  @param[in,out]       FastReadDummyClocks      Fast Read wait state (Dummy clocks), the
+                                                input is the default value.
+  @retval EFI_SUCCESS     The parameters are updated.
+  @retval EFI_NOT_FOUND   No desired Fas Read mode found.
+
+**/
+EFI_STATUS
+GetFastReadParameter (
+  IN     SPI_NOR_FLASH_INSTANCE  *Instance,
+  IN OUT UINT8                   *FastReadInstruction,
+  IN OUT UINT8                   *FastReadOperationClock,
+  IN OUT UINT8                   *FastReadDummyClocks
+  );
+
+/**
+  Read SFDP parameters into buffer
+
+  This routine reads the JEDEC SPI Flash Discoverable Parameters from the SPI
+  chip.
+
+  @param[in]  Instance    Spi Nor Flash Instance data with pointer to
+  EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS            The SPI part size is filled.
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdpBasicParameterTable (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  );
+
+/**
+  Read SFDP Sector Map Parameter into buffer
+
+  This routine reads the JEDEC SPI Flash Discoverable Parameters from the SPI
+  chip.
+
+  @param[in]  Instance           Spi Nor Flash Instance data with pointer to
+                                 EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS            The SPI part size is filled.
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdpSectorMapParameterTable (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  );
+
+/**
+  Return flash device size from SFDP Basic Flash Parameter Table DWORD 2
+
+  @param[in]  Instance    Spi Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and
+                          EFI_SPI_IO_PROTOCOL.
+
+* @retval   UINT32        Flash device size in byte, zero indicates error.
+
+**/
+UINT32
+SfdpGetFlashSize (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  );
+
+/**
+  Read SFDP
+  This routine reads the JEDEC SPI Flash Discoverable Parameters. We just
+  read the necessary tables in this routine.
+
+  @param[in]  Instance    Spi Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS            Header is filled in
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdp (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  );
+
+/**
+  Set EraseBlockBytes in SPI NOR Flash Protocol
+
+  @param[in]  Instance    Spi Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS     The erase block size is returned.
+  @retval Otherwise       Failed to get erase block size.
+
+**/
+EFI_STATUS
+SetSectorEraseBlockSize (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  );
+
+/**
+  Get the erase block attribute for the target address.
+
+  @param[in]      Instance              Spi Nor Flash Instance data with pointer to
+                                        EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+  @param[in]      FlashRegion           The region the flash address belong.
+  @param[in]      FlashAddress          The target flash address.
+  @param[in]      RemainingSize         Remaining size to erase.
+  @param[in, out] BlockSizeToErase      Input  - The block erase size for this continious blocks.
+                                        Output - The determined block size for erasing.
+  @param[in, out] BlockCountToErase     Input  - The expected blocks to erase.
+                                        Output - The determined number of blocks to erase.
+  @param[out]     BlockEraseCommand     The erase command used for this continious blocks.
+
+  @retval EFI_SUCCESS          The erase block attribute is returned.
+  @retval EFI_DEVICE_ERROR     No valid SFDP discovered.
+  @retval EFI_NOT_FOUND        No valud erase block attribute found.
+
+**/
+EFI_STATUS
+GetEraseBlockAttribute (
+  IN     SPI_NOR_FLASH_INSTANCE     *Instance,
+  IN     SFDP_SECTOR_REGION_RECORD  *FlashRegion,
+  IN     UINT32                     FlashAddress,
+  IN     UINT32                     RemainingSize,
+  IN OUT UINT32                     *BlockSizeToErase,
+  IN OUT UINT32                     *BlockCountToErase,
+  OUT    UINT8                      *BlockEraseCommand
+  );
+
+/**
+  Get the erase block attribute for the target address.
+
+  @param[in]   Instance                Spi Nor Flash Instance data with pointer to
+                                       EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+  @param[in]   FlashAddress            The target flash address.
+  @param[out]  FlashRegion             The target flash address.
+
+  @retval EFI_SUCCESS             The region is returned.
+  @retval EFI_INVALID_PARAMETER   FlashAddress is not belong to any region.
+  @retval EFI_INVALID_PARAMETER   Other errors.
+
+**/
+EFI_STATUS
+GetRegionByFlashAddress (
+  IN  SPI_NOR_FLASH_INSTANCE     *Instance,
+  IN  UINT32                     FlashAddress,
+  OUT SFDP_SECTOR_REGION_RECORD  **FlashRegion
+  );
+
+/**
+  Initial SPI_NOR_FLASH_INSTANCE structure.
+
+  @param[in]   Instance                Pointer to SPI_NOR_FLASH_INSTANCE.
+                                       EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS                  SPI_NOR_FLASH_INSTANCE is initialized according to
+                                       SPI NOR Flash SFDP specification.
+  @retval Otherwisw                    Failed to initial SPI_NOR_FLASH_INSTANCE structure.
+
+**/
+EFI_STATUS
+InitialSpiNorFlashSfdpInstance (
+  IN SPI_NOR_FLASH_INSTANCE  *Instance
+  );
+
+#endif // SPI_NOR_FLASH_INSTANCE_H_
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c
new file mode 100644
index 00000000000..5f6724a9324
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c
@@ -0,0 +1,1114 @@
+/** @file
+  SPI NOR Flash operation functions.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Protocol/SpiConfiguration.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiNorFlash.h"
+
+/**
+  Fill Write Buffer with Opcode, Address, Dummy Bytes, and Data
+
+  @param[in]    Opcode      - Opcode for transaction
+  @param[in]    Address     - SPI Offset Start Address
+  @param[in]    WriteBytes  - Number of bytes to write to SPI device
+  @param[in]    WriteBuffer - Buffer containing bytes to write to SPI device
+
+  @retval       Size of Data in Buffer
+**/
+UINT32
+FillWriteBuffer (
+  IN      SPI_NOR_FLASH_INSTANCE  *Instance,
+  IN      UINT8                   Opcode,
+  IN      UINT32                  DummyBytes,
+  IN      UINT8                   AddressBytesSupported,
+  IN      BOOLEAN                 UseAddress,
+  IN      UINT32                  Address,
+  IN      UINT32                  WriteBytes,
+  IN      UINT8                   *WriteBuffer
+  )
+{
+  UINT32  AddressSize;
+  UINT32  BigEndianAddress;
+  UINT32  Index;
+  UINT8   SfdpAddressBytes;
+
+  SfdpAddressBytes = (UINT8)Instance->SfdpBasicFlash->AddressBytes;
+
+  // Copy Opcode into Write Buffer
+  Instance->SpiTransactionWriteBuffer[0] = Opcode;
+  Index                                  = 1;
+  if (UseAddress == TRUE) {
+    if (AddressBytesSupported == SPI_ADDR_3BYTE_ONLY) {
+      if (SfdpAddressBytes != 0) {
+        // Check if the supported address length is already initiated.
+        if ((SfdpAddressBytes != SPI_ADDR_3BYTE_ONLY) && (SfdpAddressBytes != SPI_ADDR_3OR4BYTE)) {
+          DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFDP is: 0x%x\n", __func__, AddressBytesSupported, SfdpAddressBytes));
+          ASSERT (FALSE);
+        }
+      }
+
+      AddressSize = 3;
+    } else if (AddressBytesSupported == SPI_ADDR_4BYTE_ONLY) {
+      if (SfdpAddressBytes != 0) {
+        // Check if the supported address length is already initiated.
+        if ((SfdpAddressBytes != SPI_ADDR_4BYTE_ONLY) && (SfdpAddressBytes != SPI_ADDR_3OR4BYTE)) {
+          DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFDP is: 0x%x\n", __func__, AddressBytesSupported, SfdpAddressBytes));
+          ASSERT (FALSE);
+        }
+      }
+
+      AddressSize = 4;
+    } else if (AddressBytesSupported == SPI_ADDR_3OR4BYTE) {
+      if (SfdpAddressBytes != 0) {
+        // Check if the supported address length is already initiated.
+        if (SfdpAddressBytes != SPI_ADDR_3OR4BYTE) {
+          DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFDP is: 0x%x\n", __func__, AddressBytesSupported, SfdpAddressBytes));
+          ASSERT (FALSE);
+        }
+      }
+
+      if (Instance->Protocol.FlashSize <= SIZE_16MB) {
+        AddressSize = 3;
+      } else {
+        // SPI part is > 16MB use 4-byte addressing.
+        AddressSize = 4;
+      }
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: Invalid Address Bytes\n", __func__));
+      ASSERT (FALSE);
+    }
+
+    BigEndianAddress   = SwapBytes32 ((UINT32)Address);
+    BigEndianAddress >>= ((sizeof (UINT32) - AddressSize) * 8);
+    CopyMem (
+      &Instance->SpiTransactionWriteBuffer[Index],
+      &BigEndianAddress,
+      AddressSize
+      );
+    Index += AddressSize;
+  }
+
+  if (SfdpAddressBytes == SPI_ADDR_3OR4BYTE) {
+    //
+    // TODO:
+    // We may need to enter/exit 4-Byte mode if SPI flash
+    // device is currently operated in 3-Bytes mode.
+    //
+  }
+
+  // Fill DummyBytes
+  if (DummyBytes != 0) {
+    SetMem (
+      &Instance->SpiTransactionWriteBuffer[Index],
+      DummyBytes,
+      0
+      );
+    Index += DummyBytes;
+  }
+
+  // Fill Data
+  if (WriteBytes > 0) {
+    CopyMem (
+      &Instance->SpiTransactionWriteBuffer[Index],
+      WriteBuffer,
+      WriteBytes
+      );
+    Index += WriteBytes;
+  }
+
+  return Index;
+}
+
+/**
+  Internal Read the flash status register.
+
+  This routine reads the flash part status register.
+
+  @param[in]  Instance       SPI_NOR_FLASH_INSTANCE
+                             structure.
+  @param[in]  LengthInBytes  Number of status bytes to read.
+  @param[out] FlashStatus    Pointer to a buffer to receive the flash status.
+
+  @retval EFI_SUCCESS  The status register was read successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalReadStatus (
+  IN                SPI_NOR_FLASH_INSTANCE  *Instance,
+  IN  UINT32                                LengthInBytes,
+  OUT UINT8                                 *FlashStatus
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      TransactionBufferLength;
+
+  // Read Status register
+  TransactionBufferLength = FillWriteBuffer (
+                              Instance,
+                              SPI_FLASH_RDSR,
+                              SPI_FLASH_RDSR_DUMMY,
+                              SPI_FLASH_RDSR_ADDR_BYTES,
+                              FALSE,
+                              0,
+                              0,
+                              NULL
+                              );
+  Status = Instance->SpiIo->Transaction (
+                              Instance->SpiIo,
+                              SPI_TRANSACTION_WRITE_THEN_READ,
+                              FALSE,
+                              0,
+                              1,
+                              8,
+                              TransactionBufferLength,
+                              Instance->SpiTransactionWriteBuffer,
+                              1,
+                              FlashStatus
+                              );
+  ASSERT_EFI_ERROR (Status);
+  return Status;
+}
+
+/**
+  Set Write Enable Latch
+
+  @param[in]  Instance          SPI NOR instance with all protocols, etc.
+
+  @retval EFI_SUCCESS           SPI Write Enable succeeded
+  @retval EFI_DEVICE_ERROR      SPI Flash part did not respond properly
+**/
+EFI_STATUS
+SetWel (
+  IN      SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      TransactionBufferLength;
+
+  TransactionBufferLength = FillWriteBuffer (
+                              Instance,
+                              Instance->WriteEnableLatchCommand,
+                              SPI_FLASH_WREN_DUMMY,
+                              SPI_FLASH_WREN_ADDR_BYTES,
+                              FALSE,
+                              0,
+                              0,
+                              NULL
+                              );
+  Status = Instance->SpiIo->Transaction (
+                              Instance->SpiIo,
+                              SPI_TRANSACTION_WRITE_ONLY,
+                              FALSE,
+                              0,
+                              1,
+                              8,
+                              TransactionBufferLength,
+                              Instance->SpiTransactionWriteBuffer,
+                              0,
+                              NULL
+                              );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Set WEL fail.\n", __func__));
+    ASSERT (FALSE);
+  }
+
+  return Status;
+}
+
+/**
+  Check for not device write in progress
+
+  @param[in]  Instance  - SPI NOR instance with all protocols, etc.
+
+  @retval EFI_SUCCESS           Device does not have a write in progress
+  @retval EFI_DEVICE_ERROR      SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitNotWip (
+  IN      SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       DeviceStatus;
+  UINTN       RetryCount;
+  UINTN       DelayMicroseconds;
+
+  DelayMicroseconds = FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds);
+  RetryCount        = FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount);
+  if (RetryCount == 0) {
+    RetryCount = 1;
+  }
+
+  do {
+    Status = InternalReadStatus (Instance, 1, &DeviceStatus);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: Read status error\n", __func__));
+      ASSERT (FALSE);
+      break;
+    }
+
+    if (  EFI_ERROR (Status)
+       || ((DeviceStatus & SPI_FLASH_SR_WIP) == SPI_FLASH_SR_NOT_WIP))
+    {
+      break;
+    }
+
+    MicroSecondDelay (DelayMicroseconds);
+    RetryCount--;
+  } while (RetryCount > 0);
+
+  if (RetryCount == 0) {
+    DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  return Status;
+}
+
+/**
+  Check for write enable latch set and not device write in progress
+
+  @param[in]  Instance  - SPI NOR instance with all protocols, etc.
+
+  @retval EFI_SUCCESS           Device does not have a write in progress and
+                                write enable latch is set
+  @retval EFI_DEVICE_ERROR      SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitWelNotWip (
+  IN      SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       DeviceStatus;
+  UINTN       RetryCount;
+  UINTN       DelayMicroseconds;
+
+  DelayMicroseconds = FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds);
+  RetryCount        = FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount);
+  if (RetryCount == 0) {
+    RetryCount = 1;
+  }
+
+  do {
+    Status = InternalReadStatus (Instance, 1, &DeviceStatus);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: Fail to read WEL.\n", __func__));
+      ASSERT_EFI_ERROR (Status);
+    }
+
+    if (  EFI_ERROR (Status)
+       || ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL))
+           == SPI_FLASH_SR_WEL))
+    {
+      break;
+    }
+
+    MicroSecondDelay (DelayMicroseconds);
+    RetryCount--;
+  } while (RetryCount > 0);
+
+  if (RetryCount == 0) {
+    DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  return Status;
+}
+
+/**
+  Check for not write enable latch set and not device write in progress
+
+  @param[in]  Instance  - SPI NOR instance with all protocols, etc.
+
+  @retval EFI_SUCCESS           Device does not have a write in progress and
+                                write enable latch is not set
+  @retval EFI_DEVICE_ERROR      SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitNotWelNotWip (
+  IN      SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       DeviceStatus;
+  UINTN       RetryCount;
+  UINTN       DelayMicroseconds;
+
+  DelayMicroseconds = FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds);
+  RetryCount        = FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount);
+  if (RetryCount == 0) {
+    RetryCount = 1;
+  }
+
+  do {
+    Status = InternalReadStatus (Instance, 1, &DeviceStatus);
+    ASSERT_EFI_ERROR (Status);
+    if (  EFI_ERROR (Status)
+       || ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL))
+           == SPI_FLASH_SR_NOT_WIP))
+    {
+      break;
+    }
+
+    MicroSecondDelay (DelayMicroseconds);
+    RetryCount--;
+  } while (RetryCount > 0);
+
+  if (RetryCount == 0) {
+    DEBUG ((DEBUG_ERROR, "SpiNorFlash:%a: Timeout error\n", __func__));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  return Status;
+}
+
+/**
+  Read the 3 byte manufacture and device ID from the SPI flash.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine reads the 3 byte manufacture and device ID from the flash part
+  filling the buffer provided.
+
+  @param[in]  This    Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data structure.
+  @param[out] Buffer  Pointer to a 3 byte buffer to receive the manufacture and
+                      device ID.
+
+  @retval EFI_SUCCESS            The manufacture and device ID was read
+                                 successfully.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+EFIAPI
+GetFlashId (
+  IN  CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  OUT UINT8                             *Buffer
+  )
+{
+  EFI_STATUS              Status;
+  SPI_NOR_FLASH_INSTANCE  *Instance;
+  UINT32                  TransactionBufferLength;
+
+  DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__));
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Instance = SPI_NOR_FLASH_FROM_THIS (This);
+
+  // Check not WIP
+  Status = WaitNotWip (Instance);
+
+  if (!EFI_ERROR (Status)) {
+    TransactionBufferLength = FillWriteBuffer (
+                                Instance,
+                                SPI_FLASH_RDID,
+                                SPI_FLASH_RDID_DUMMY,
+                                SPI_FLASH_RDID_ADDR_BYTES,
+                                FALSE,
+                                0,
+                                0,
+                                NULL
+                                );
+    Status = Instance->SpiIo->Transaction (
+                                Instance->SpiIo,
+                                SPI_TRANSACTION_WRITE_THEN_READ,
+                                FALSE,
+                                0,
+                                1,
+                                8,
+                                TransactionBufferLength,
+                                Instance->SpiTransactionWriteBuffer,
+                                3,
+                                Buffer
+                                );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return Status;
+}
+
+/**
+  Read data from the SPI flash at not fast speed
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine reads data from the SPI part in the buffer provided.
+
+  @param[in]  This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                             structure.
+  @param[in]  FlashAddress   Address in the flash to start reading
+  @param[in]  LengthInBytes  Read length in bytes
+  @param[out] Buffer         Address of a buffer to receive the data
+
+  @retval EFI_SUCCESS            The data was read successfully.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL, or
+                                 FlashAddress >= This->FlashSize, or
+                                 LengthInBytes > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+LfReadData (
+  IN  CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN  UINT32                            FlashAddress,
+  IN  UINT32                            LengthInBytes,
+  OUT UINT8                             *Buffer
+  )
+{
+  EFI_STATUS              Status;
+  SPI_NOR_FLASH_INSTANCE  *Instance;
+  UINT32                  ByteCounter;
+  UINT32                  CurrentAddress;
+  UINT8                   *CurrentBuffer;
+  UINT32                  Length;
+  UINT32                  TransactionBufferLength;
+  UINT32                  MaximumTransferBytes;
+
+  DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__));
+
+  Status = EFI_DEVICE_ERROR;
+  if ((Buffer == NULL) ||
+      (FlashAddress >= This->FlashSize) ||
+      (LengthInBytes > This->FlashSize - FlashAddress))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Instance             = SPI_NOR_FLASH_FROM_THIS (This);
+  MaximumTransferBytes = Instance->SpiIo->MaximumTransferBytes;
+
+  CurrentBuffer = Buffer;
+  Length        = 0;
+  for (ByteCounter = 0; ByteCounter < LengthInBytes;) {
+    CurrentAddress = FlashAddress + ByteCounter;
+    CurrentBuffer  = Buffer + ByteCounter;
+    Length         = LengthInBytes - ByteCounter;
+    // Length must be MaximumTransferBytes or less
+    if (Length > MaximumTransferBytes) {
+      Length = MaximumTransferBytes;
+    }
+
+    // Check not WIP
+    Status = WaitNotWip (Instance);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    TransactionBufferLength = FillWriteBuffer (
+                                Instance,
+                                SPI_FLASH_READ,
+                                SPI_FLASH_READ_DUMMY,
+                                SPI_FLASH_READ_ADDR_BYTES,
+                                TRUE,
+                                CurrentAddress,
+                                0,
+                                NULL
+                                );
+    Status = Instance->SpiIo->Transaction (
+                                Instance->SpiIo,
+                                SPI_TRANSACTION_WRITE_THEN_READ,
+                                FALSE,
+                                0,
+                                1,
+                                8,
+                                TransactionBufferLength,
+                                Instance->SpiTransactionWriteBuffer,
+                                Length,
+                                CurrentBuffer
+                                );
+    ASSERT_EFI_ERROR (Status);
+    ByteCounter += Length;
+  }
+
+  return Status;
+}
+
+/**
+  Read data from the SPI flash.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine reads data from the SPI part in the buffer provided.
+
+  @param[in]  This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                             structure.
+  @param[in]  FlashAddress   Address in the flash to start reading
+  @param[in]  LengthInBytes  Read length in bytes
+  @param[out] Buffer         Address of a buffer to receive the data
+
+  @retval EFI_SUCCESS            The data was read successfully.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL, or
+                                 FlashAddress >= This->FlashSize, or
+                                 LengthInBytes > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+ReadData (
+  IN  CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN  UINT32                            FlashAddress,
+  IN  UINT32                            LengthInBytes,
+  OUT UINT8                             *Buffer
+  )
+{
+  EFI_STATUS              Status;
+  SPI_NOR_FLASH_INSTANCE  *Instance;
+  UINT32                  ByteCounter;
+  UINT32                  CurrentAddress;
+  UINT8                   *CurrentBuffer;
+  UINT32                  Length;
+  UINT32                  TransactionBufferLength;
+  UINT32                  MaximumTransferBytes;
+  UINT8                   FastReadInstruction;
+  UINT8                   FastReadWaitStateDummyClocks;
+  UINT8                   FastReadModeClock;
+
+  DEBUG ((DEBUG_INFO, "%a: Entry, Read address = 0x%08x, Length = 0x%08x\n", __func__, FlashAddress, LengthInBytes));
+
+  Status = EFI_DEVICE_ERROR;
+  if ((Buffer == NULL) ||
+      (FlashAddress >= This->FlashSize) ||
+      (LengthInBytes > This->FlashSize - FlashAddress))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Instance             = SPI_NOR_FLASH_FROM_THIS (This);
+  MaximumTransferBytes = Instance->SpiIo->MaximumTransferBytes;
+
+  //
+  // Initial the default read operation parameters.
+  //
+  FastReadInstruction          = SPI_FLASH_FAST_READ;
+  FastReadWaitStateDummyClocks = SPI_FLASH_FAST_READ_DUMMY * 8;
+  FastReadModeClock            = 0;
+  //
+  // Override by the Fast Read capabiity table.
+  //
+  // Get the first supported fast read comamnd.
+  // This will be the standard fast read command (0x0b),
+  // which is the first fast read command added to the
+  // supported list.
+  // TODO: The mechanism to choose the advanced fast read
+  //       is not determined yet in this version of
+  //       SpiNorFlash driver.
+  Status = GetFastReadParameter (
+             Instance,
+             &FastReadInstruction,
+             &FastReadModeClock,
+             &FastReadWaitStateDummyClocks
+             );
+  if (!EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_VERBOSE, "  Use below Fast Read mode:\n"));
+  } else {
+    DEBUG ((DEBUG_VERBOSE, "  Use the default Fast Read mode:\n"));
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "    Instruction                        : 0x%x\n", FastReadInstruction));
+  DEBUG ((DEBUG_VERBOSE, "    Mode Clock                         : 0x%x\n", FastReadModeClock));
+  DEBUG ((DEBUG_VERBOSE, "    Wait States (Dummy Clocks) in clock: 0x%x\n", FastReadWaitStateDummyClocks));
+  DEBUG ((DEBUG_VERBOSE, "     Supported erase address bytes by device: 0x%02x.\n", Instance->SfdpBasicFlash->AddressBytes));
+  DEBUG ((DEBUG_VERBOSE, "        (00: 3-Byte, 01: 3 or 4-Byte. 10: 4-Byte)\n"));
+
+  CurrentBuffer = Buffer;
+  Length        = 0;
+  for (ByteCounter = 0; ByteCounter < LengthInBytes;) {
+    CurrentAddress = FlashAddress + ByteCounter;
+    CurrentBuffer  = Buffer + ByteCounter;
+    Length         = LengthInBytes - ByteCounter;
+    // Length must be MaximumTransferBytes or less
+    if (Length > MaximumTransferBytes) {
+      Length = MaximumTransferBytes;
+    }
+
+    // Check not WIP
+    Status = WaitNotWip (Instance);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    TransactionBufferLength = FillWriteBuffer (
+                                Instance,
+                                FastReadInstruction,
+                                FastReadWaitStateDummyClocks / 8,
+                                (UINT8)Instance->SfdpBasicFlash->AddressBytes,
+                                TRUE,
+                                CurrentAddress,
+                                0,
+                                NULL
+                                );
+    Status = Instance->SpiIo->Transaction (
+                                Instance->SpiIo,
+                                SPI_TRANSACTION_WRITE_THEN_READ,
+                                FALSE,
+                                0,
+                                1,
+                                8,
+                                TransactionBufferLength,
+                                Instance->SpiTransactionWriteBuffer,
+                                Length,
+                                CurrentBuffer
+                                );
+    ASSERT_EFI_ERROR (Status);
+    ByteCounter += Length;
+  }
+
+  return Status;
+}
+
+/**
+  Read the flash status register.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine reads the flash part status register.
+
+  @param[in]  This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                             structure.
+  @param[in]  LengthInBytes  Number of status bytes to read.
+  @param[out] FlashStatus    Pointer to a buffer to receive the flash status.
+
+  @retval EFI_SUCCESS  The status register was read successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadStatus (
+  IN  CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN  UINT32                            LengthInBytes,
+  OUT UINT8                             *FlashStatus
+  )
+{
+  EFI_STATUS              Status;
+  SPI_NOR_FLASH_INSTANCE  *Instance;
+
+  if (LengthInBytes != 1) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Instance = SPI_NOR_FLASH_FROM_THIS (This);
+
+  Status = InternalReadStatus (Instance, LengthInBytes, FlashStatus);
+
+  return Status;
+}
+
+/**
+  Write the flash status register.
+
+  This routine must be called at or below TPL_N OTIFY.
+  This routine writes the flash part status register.
+
+  @param[in] This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                            structure.
+  @param[in] LengthInBytes  Number of status bytes to write.
+  @param[in] FlashStatus    Pointer to a buffer containing the new status.
+
+  @retval EFI_SUCCESS           The status write was successful.
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate the write buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteStatus (
+  IN CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN UINT32                            LengthInBytes,
+  IN UINT8                             *FlashStatus
+  )
+{
+  EFI_STATUS              Status;
+  SPI_NOR_FLASH_INSTANCE  *Instance;
+  UINT32                  TransactionBufferLength;
+
+  if (LengthInBytes != 1) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Instance = SPI_NOR_FLASH_FROM_THIS (This);
+
+  // Check not WIP
+  Status = WaitNotWip (Instance);
+
+  // Set Write Enable
+  if (!EFI_ERROR (Status)) {
+    if (Instance->WriteEnableLatchRequired) {
+      Status = SetWel (Instance);
+      DEBUG ((DEBUG_ERROR, "%a: set Write Enable Error.\n", __func__));
+      ASSERT_EFI_ERROR (Status);
+      // Check not WIP & WEL enabled
+      Status = WaitWelNotWip (Instance);
+    }
+
+    // Write the Status Register
+    if (!EFI_ERROR (Status)) {
+      TransactionBufferLength = FillWriteBuffer (
+                                  Instance,
+                                  SPI_FLASH_WRSR,
+                                  SPI_FLASH_WRSR_DUMMY,
+                                  SPI_FLASH_WRSR_ADDR_BYTES,
+                                  FALSE,
+                                  0,
+                                  0,
+                                  NULL
+                                  );
+      Status = Instance->SpiIo->Transaction (
+                                  Instance->SpiIo,
+                                  SPI_TRANSACTION_WRITE_ONLY,
+                                  FALSE,
+                                  0,
+                                  1,
+                                  8,
+                                  TransactionBufferLength,
+                                  Instance->SpiTransactionWriteBuffer,
+                                  0,
+                                  NULL
+                                  );
+      ASSERT_EFI_ERROR (Status);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Write data to the SPI flash.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine breaks up the write operation as necessary to write the data to
+  the SPI part.
+
+  @param[in] This           Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                            structure.
+  @param[in] FlashAddress   Address in the flash to start writing
+  @param[in] LengthInBytes  Write length in bytes
+  @param[in] Buffer         Address of a buffer containing the data
+
+  @retval EFI_SUCCESS            The data was written successfully.
+  @retval EFI_INVALID_PARAMETER  Buffer is NULL, or
+                                 FlashAddress >= This->FlashSize, or
+                                 LengthInBytes > This->FlashSize - FlashAddress
+  @retval EFI_OUT_OF_RESOURCES   Insufficient memory to copy buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteData (
+  IN CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN UINT32                            FlashAddress,
+  IN UINT32                            LengthInBytes,
+  IN UINT8                             *Buffer
+  )
+{
+  EFI_STATUS              Status;
+  SPI_NOR_FLASH_INSTANCE  *Instance;
+  UINT32                  ByteCounter;
+  UINT32                  CurrentAddress;
+  UINT32                  Length;
+  UINT32                  BytesUntilBoundary;
+  UINT8                   *CurrentBuffer;
+  UINT32                  TransactionBufferLength;
+  UINT32                  MaximumTransferBytes;
+  UINT32                  SpiFlashPageSize;
+
+  DEBUG ((DEBUG_INFO, "%a: Entry: Write address = 0x%08x, Length = 0x%08x\n", __func__, FlashAddress, LengthInBytes));
+
+  Status = EFI_DEVICE_ERROR;
+  if ((Buffer == NULL) ||
+      (LengthInBytes == 0) ||
+      (FlashAddress >= This->FlashSize) ||
+      (LengthInBytes > This->FlashSize - FlashAddress))
+  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Instance             = SPI_NOR_FLASH_FROM_THIS (This);
+  MaximumTransferBytes = Instance->SpiIo->MaximumTransferBytes;
+  if (Instance->SfdpBasicFlashByteCount >= 11 * 4) {
+    // JESD216C spec DWORD 11
+    SpiFlashPageSize = 1 << Instance->SfdpBasicFlash->PageSize;
+  } else {
+    SpiFlashPageSize = 256;
+  }
+
+  CurrentBuffer = Buffer;
+  Length        = 0;
+  for (ByteCounter = 0; ByteCounter < LengthInBytes;) {
+    CurrentAddress = FlashAddress + ByteCounter;
+    CurrentBuffer  = Buffer + ByteCounter;
+    Length         = LengthInBytes - ByteCounter;
+    // Length must be MaximumTransferBytes or less
+    if (Length > MaximumTransferBytes) {
+      Length = MaximumTransferBytes;
+    }
+
+    // Cannot cross SpiFlashPageSize boundary
+    BytesUntilBoundary = SpiFlashPageSize
+                         - (CurrentAddress % SpiFlashPageSize);
+    if ((BytesUntilBoundary != 0) && (Length > BytesUntilBoundary)) {
+      Length = BytesUntilBoundary;
+    }
+
+    // Check not WIP
+    Status = WaitNotWip (Instance);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    if (Instance->WriteEnableLatchRequired) {
+      // Set Write Enable
+      Status = SetWel (Instance);
+      ASSERT_EFI_ERROR (Status);
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+
+      // Check not WIP & WEL enabled
+      Status = WaitWelNotWip (Instance);
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+    }
+
+    //  Write Data
+    TransactionBufferLength = FillWriteBuffer (
+                                Instance,
+                                SPI_FLASH_PP,
+                                SPI_FLASH_PP_DUMMY,
+                                SPI_FLASH_PP_ADDR_BYTES,
+                                TRUE,
+                                CurrentAddress,
+                                Length,
+                                CurrentBuffer
+                                );
+    Status = Instance->SpiIo->Transaction (
+                                Instance->SpiIo,
+                                SPI_TRANSACTION_WRITE_ONLY,
+                                FALSE,
+                                0,
+                                1,
+                                8,
+                                TransactionBufferLength,
+                                Instance->SpiTransactionWriteBuffer,
+                                0,
+                                NULL
+                                );
+    ASSERT_EFI_ERROR (Status);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    if (Instance->WriteEnableLatchRequired) {
+      // Check not WIP & not WEL
+      Status = WaitNotWelNotWip (Instance);
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+    } else {
+      Status = WaitNotWip (Instance);
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+    }
+
+    ByteCounter += Length;
+  }
+
+  return Status;
+}
+
+/**
+  Efficiently erases blocks in the SPI flash.
+
+  This routine must be called at or below TPL_NOTIFY.
+  This routine may use the combination of variable earse sizes to erase the
+  specified area accroding to the flash region.
+
+  @param[in] This          Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+                           structure.
+  @param[in] FlashAddress  Address to start erasing
+  @param[in] BlockCount    Number of blocks to erase. The block size is indicated
+                           in EraseBlockBytes in EFI_SPI_NOR_FLASH_PROTOCOL.
+
+  @retval EFI_SUCCESS            The erase was completed successfully.
+  @retval EFI_DEVICE_ERROR       The flash devices has problems.
+  @retval EFI_INVALID_PARAMETER  The given FlashAddress and/or BlockCount
+                                 is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+Erase (
+  IN CONST EFI_SPI_NOR_FLASH_PROTOCOL  *This,
+  IN UINT32                            FlashAddress,
+  IN UINT32                            BlockCount
+  )
+{
+  EFI_STATUS                 Status;
+  SPI_NOR_FLASH_INSTANCE     *Instance;
+  UINT8                      Opcode;
+  UINT32                     Dummy;
+  UINT32                     ByteCounter;
+  UINT32                     EraseLength;
+  UINT32                     TotalEraseLength;
+  UINT32                     CurrentAddress;
+  UINT32                     TransactionBufferLength;
+  UINT32                     BlockCountToErase;
+  UINT32                     BlockSizeToErase;
+  UINT8                      BlockEraseCommand;
+  SFDP_SECTOR_REGION_RECORD  *FlashRegion;
+
+  DEBUG ((DEBUG_INFO, "%a: Entry: Erase address = 0x%08x, Block count = 0x%x\n", __func__, FlashAddress, BlockCount));
+
+  Status   = EFI_DEVICE_ERROR;
+  Instance = SPI_NOR_FLASH_FROM_THIS (This);
+
+  // Get the region of this flash address.
+  Status = GetRegionByFlashAddress (Instance, FlashAddress, &FlashRegion);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "  Failed to get the flash region of this flash address.\n"));
+    ASSERT (FALSE);
+    return Status;
+  }
+
+  CurrentAddress    = FlashAddress;
+  BlockCountToErase = BlockCount;
+  BlockSizeToErase  = FlashRegion->SectorSize; // This is also the minimum block erase size.
+  TotalEraseLength  = BlockCountToErase * FlashRegion->SectorSize;
+  if ((FlashAddress + TotalEraseLength) > (FlashRegion->RegionAddress + FlashRegion->RegionTotalSize)) {
+    DEBUG ((DEBUG_ERROR, "  The blocks to erase exceeds the region boundary.\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "  Region starting address: 0x%08x.\n", FlashRegion->RegionAddress));
+  DEBUG ((DEBUG_VERBOSE, "  Region size            : 0x%08x.\n", FlashRegion->RegionTotalSize));
+  DEBUG ((DEBUG_VERBOSE, "  Region sector size     : 0x%08x.\n", FlashRegion->SectorSize));
+  DEBUG ((DEBUG_VERBOSE, "  Supported erase address bytes by device: 0x%02x.\n", Instance->SfdpBasicFlash->AddressBytes));
+  DEBUG ((DEBUG_VERBOSE, "    (00: 3-Byte, 01: 3 or 4-Byte. 10: 4-Byte)\n"));
+
+  // Loop until all blocks are erased.
+  ByteCounter = 0;
+  while (ByteCounter < TotalEraseLength) {
+    CurrentAddress = FlashAddress + ByteCounter;
+
+    // Is this the whole device erase.
+    if (TotalEraseLength == This->FlashSize) {
+      Opcode      = SPI_FLASH_CE;
+      Dummy       = SPI_FLASH_CE_DUMMY;
+      EraseLength = TotalEraseLength;
+      DEBUG ((DEBUG_VERBOSE, "  This is the chip erase.\n"));
+    } else {
+      //
+      // Get the erase block attributes.
+      //
+      Status = GetEraseBlockAttribute (
+                 Instance,
+                 FlashRegion,
+                 CurrentAddress,
+                 TotalEraseLength - ByteCounter,
+                 &BlockSizeToErase,
+                 &BlockCountToErase,
+                 &BlockEraseCommand
+                 );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "  Failed to get erase block attribute.\n"));
+        ASSERT (FALSE);
+      }
+
+      Opcode      = BlockEraseCommand;
+      Dummy       = SPI_FLASH_BE_DUMMY;
+      EraseLength = BlockCountToErase * BlockSizeToErase;
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "  Erase command 0x%02x at adddress 0x%08x for length 0x%08x.\n",
+        BlockEraseCommand,
+        CurrentAddress,
+        EraseLength
+        ));
+    }
+
+    //
+    // Process the erase command.
+    //
+
+    // Check not WIP
+    Status = WaitNotWip (Instance);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    if (Instance->WriteEnableLatchRequired) {
+      // Set Write Enable
+      Status = SetWel (Instance);
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+
+      // Check not WIP & WEL enabled
+      Status = WaitWelNotWip (Instance);
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+    }
+
+    // Erase Block
+    TransactionBufferLength = FillWriteBuffer (
+                                Instance,
+                                Opcode,
+                                Dummy,
+                                (UINT8)Instance->SfdpBasicFlash->AddressBytes,
+                                TRUE,
+                                CurrentAddress,
+                                0,
+                                NULL
+                                );
+    Status = Instance->SpiIo->Transaction (
+                                Instance->SpiIo,
+                                SPI_TRANSACTION_WRITE_ONLY,
+                                FALSE,
+                                0,
+                                1,
+                                8,
+                                TransactionBufferLength,
+                                Instance->SpiTransactionWriteBuffer,
+                                0,
+                                NULL
+                                );
+    ASSERT_EFI_ERROR (Status);
+    if (EFI_ERROR (Status)) {
+      break;
+    } else {
+      DEBUG ((DEBUG_VERBOSE, "Erase command sucessfully.\n"));
+    }
+
+    if (Instance->WriteEnableLatchRequired) {
+      // Check not WIP & not WEL
+      Status = WaitNotWelNotWip (Instance);
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+    } else {
+      Status = WaitNotWip (Instance);
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+    }
+
+    ByteCounter += EraseLength;
+  }
+
+  return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c
new file mode 100644
index 00000000000..00ba0a62a51
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c
@@ -0,0 +1,1772 @@
+/** @file
+  SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+  common functions.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Revision Reference:
+    - JEDEC Standard, JESD216F.02
+      https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+
+  @par Glossary:
+    - SFDP - Serial Flash Discoverable Parameters
+    - PTP  - Parameter Table Pointer
+**/
+
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/SpiConfiguration.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiNorFlash.h"
+#include "SpiNorFlashJedecSfdpInternal.h"
+
+/**
+  Build up the Fast Read capability entry and link it to
+  the linked list.
+
+  @param[in]  Instance              SPI Nor Flash Instance data with pointer to
+                                    EFI_SPI_NOR_FLASH_PROTOCOL and
+                                    EFI_SPI_IO_PROTOCOL.
+  @param[in]  FastReadInstruction   The string of fast read instruction.
+  @param[in]  FastReadModeClk       The string of fast read mode clock.
+  @param[in]  FastReadDummyClk      The string of fast read dummy clock.
+
+**/
+VOID
+CreateSpiFastReadTableEntry (
+  IN SPI_NOR_FLASH_INSTANCE  *Instance,
+  IN UINT32                  FastReadInstruction,
+  IN UINT32                  FastReadModeClk,
+  IN UINT32                  FastReadDummyClk
+  )
+{
+  SFPD_FAST_READ_CAPBILITY_RECORD  *CapabilityEntry;
+
+  CapabilityEntry = AllocateZeroPool (sizeof (SFPD_FAST_READ_CAPBILITY_RECORD));
+  if (CapabilityEntry == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to create fast read table\n", __func__));
+    ASSERT (FALSE);
+    return;
+  }
+
+  InitializeListHead (&CapabilityEntry->NextFastReadCap);
+  CapabilityEntry->FastReadInstruction = (UINT8)FastReadInstruction;
+  CapabilityEntry->ModeClocks          = (UINT8)FastReadModeClk;
+  CapabilityEntry->WaitStates          = (UINT8)FastReadDummyClk;
+  InsertTailList (&Instance->FastReadTableList, &CapabilityEntry->NextFastReadCap);
+  DEBUG ((DEBUG_VERBOSE, "%a: Create and link table.\n", __func__));
+  DEBUG ((DEBUG_VERBOSE, "  Instruction               : 0x%x\n", FastReadInstruction));
+  DEBUG ((DEBUG_VERBOSE, "  Mode bits                 : 0x%x\n", FastReadModeClk));
+  DEBUG ((DEBUG_VERBOSE, "  Wait States (Dummy Clocks): 0x%x\n", FastReadDummyClk));
+}
+
+/**
+  Calculate erase type typical time.
+
+  @param[in]  SfdpEraseTypicalTime      Erase type typical time indicated in
+                                        Basic Flash Parameter Table.
+                                        EraseTypicalTime [0:4] - Count
+                                        EraseTypicalTime [5:6] - Unit
+                                                                  00b: 1ms
+                                                                  01b: 16ms
+                                                                  10b: 128ms
+                                                                  11b: 1s
+  @param[in]  SfdpEraseTimeMultiplier   Multiplier from erase typical time.
+  @param[out] EraseTypicalTime          Pointer to receive Erase typical time in milliseconds.
+  @param[out] EraseTimeout              Pointer to receive Erase timeout in milliseconds.
+
+  @retval Erase time in milliseconds.
+**/
+VOID
+CalculateEraseTiming (
+  IN  UINT32  SfdpEraseTypicalTime,
+  IN  UINT32  SfdpEraseTimeMultiplier,
+  OUT UINT32  *EraseTypicalTime,
+  OUT UINT64  *EraseTimeout
+  )
+{
+  UINT32  UnitInMs;
+
+  UnitInMs = (SfdpEraseTypicalTime & ERASE_TYPICAL_TIME_UNITS_MASK) >> ERASE_TYPICAL_TIME_BIT_POSITION;
+  switch (UnitInMs) {
+    case ERASE_TYPICAL_TIME_UNIT_1_MS_BITMAP:
+      UnitInMs = ERASE_TYPICAL_TIME_UNIT_1_MS;
+      break;
+
+    case ERASE_TYPICAL_TIME_UNIT_16_MS_BITMAP:
+      UnitInMs = ERASE_TYPICAL_TIME_UNIT_16_MS;
+      break;
+
+    case ERASE_TYPICAL_TIME_UNIT_128_MS_BITMAP:
+      UnitInMs = ERASE_TYPICAL_TIME_UNIT_128_MS;
+      break;
+
+    case ERASE_TYPICAL_TIME_UNIT_1000_MS_BITMAP:
+      UnitInMs = ERASE_TYPICAL_TIME_UNIT_1000_MS;
+      break;
+    default:
+      DEBUG ((DEBUG_ERROR, "%a: Unsupported Erase Typical time.\n", __func__));
+      ASSERT (FALSE);
+  }
+
+  *EraseTypicalTime = UnitInMs * ((SfdpEraseTypicalTime & ERASE_TYPICAL_TIME_COUNT_MASK) + 1);
+  *EraseTimeout     = 2 * (SfdpEraseTimeMultiplier + 1) * *EraseTypicalTime;
+  return;
+}
+
+/**
+  Print out the erase type information.
+
+  @param[in]  SupportedEraseType    Pointer to SFDP_SUPPORTED_ERASE_TYPE_RECORD.
+**/
+VOID
+DebugPrintEraseType (
+  IN SFDP_SUPPORTED_ERASE_TYPE_RECORD  *SupportedEraseType
+  )
+{
+  DEBUG ((DEBUG_VERBOSE, "  Erase Type %d\n", SupportedEraseType->EraseType));
+  DEBUG ((DEBUG_VERBOSE, "  Erase Type instruction: 0x%x\n", SupportedEraseType->EraseInstruction));
+  DEBUG ((DEBUG_VERBOSE, "  Erase size: 0x%x bytes\n", SupportedEraseType->EraseSizeInByte));
+  DEBUG ((DEBUG_VERBOSE, "  Erase time: %d Milliseconds\n", SupportedEraseType->EraseTypicalTime));
+  DEBUG ((DEBUG_VERBOSE, "  Erase timeout:  %d Milliseconds:\n", SupportedEraseType->EraseTimeout));
+}
+
+/**
+  Insert supported erase type entry.
+
+  @param[in]  Instance              SPI Nor Flash Instance data with pointer to
+                                    EFI_SPI_NOR_FLASH_PROTOCOL and
+                                    EFI_SPI_IO_PROTOCOL.
+  @param[in]  SupportedEraseType    Pointer to SFDP_SUPPORTED_ERASE_TYPE_RECORD.
+**/
+VOID
+CreateEraseTypeEntry (
+  IN  SPI_NOR_FLASH_INSTANCE            *Instance,
+  IN  SFDP_SUPPORTED_ERASE_TYPE_RECORD  *SupportedEraseType
+  )
+{
+  InitializeListHead (&SupportedEraseType->NextEraseType);
+  InsertTailList (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType);
+
+  DEBUG ((DEBUG_VERBOSE, "%a: Erase Type 0x%x is supported:\n", __func__, SupportedEraseType->EraseType));
+  DebugPrintEraseType (SupportedEraseType);
+}
+
+/**
+  Build up the erase type tables.
+
+  @param[in]  Instance    SPI Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and
+                          EFI_SPI_IO_PROTOCOL.
+
+**/
+VOID
+BuildUpEraseTypeTable (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  SFDP_SUPPORTED_ERASE_TYPE_RECORD  *SupportedEraseType;
+
+  // Build up erase type 1 entry.
+  if (Instance->SfdpBasicFlash->Erase1Size != 0) {
+    SupportedEraseType = AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_TYPE_RECORD));
+    if (SupportedEraseType != NULL) {
+      SupportedEraseType->EraseType        = SFDP_ERASE_TYPE_1;
+      SupportedEraseType->EraseInstruction = (UINT8)Instance->SfdpBasicFlash->Erase1Instr;
+      SupportedEraseType->EraseSizeInByte  = (UINT32)1 << Instance->SfdpBasicFlash->Erase1Size;
+      CalculateEraseTiming (
+        Instance->SfdpBasicFlash->Erase1Time,
+        Instance->SfdpBasicFlash->EraseMultiplier,
+        &SupportedEraseType->EraseTypicalTime,
+        &SupportedEraseType->EraseTimeout
+        );
+      CreateEraseTypeEntry (Instance, SupportedEraseType);
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED_ERASE_TYPE_RECORD (Type 1).\n", __func__));
+      ASSERT (FALSE);
+    }
+  }
+
+  // Build up erase type 2 entry.
+  if (Instance->SfdpBasicFlash->Erase2Size != 0) {
+    SupportedEraseType = AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_TYPE_RECORD));
+    if (SupportedEraseType != NULL) {
+      SupportedEraseType->EraseType        = SFDP_ERASE_TYPE_2;
+      SupportedEraseType->EraseInstruction = (UINT8)Instance->SfdpBasicFlash->Erase2Instr;
+      SupportedEraseType->EraseSizeInByte  = (UINT32)1 << Instance->SfdpBasicFlash->Erase2Size;
+      CalculateEraseTiming (
+        Instance->SfdpBasicFlash->Erase2Time,
+        Instance->SfdpBasicFlash->EraseMultiplier,
+        &SupportedEraseType->EraseTypicalTime,
+        &SupportedEraseType->EraseTimeout
+        );
+      CreateEraseTypeEntry (Instance, SupportedEraseType);
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED_ERASE_TYPE_RECORD (Type 2).\n", __func__));
+      ASSERT (FALSE);
+    }
+  }
+
+  // Build up erase type 3 entry.
+  if (Instance->SfdpBasicFlash->Erase3Size != 0) {
+    SupportedEraseType = AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_TYPE_RECORD));
+    if (SupportedEraseType != NULL) {
+      SupportedEraseType->EraseType        = SFDP_ERASE_TYPE_3;
+      SupportedEraseType->EraseInstruction = (UINT8)Instance->SfdpBasicFlash->Erase3Instr;
+      SupportedEraseType->EraseSizeInByte  = (UINT32)1 << Instance->SfdpBasicFlash->Erase3Size;
+      CalculateEraseTiming (
+        Instance->SfdpBasicFlash->Erase3Time,
+        Instance->SfdpBasicFlash->EraseMultiplier,
+        &SupportedEraseType->EraseTypicalTime,
+        &SupportedEraseType->EraseTimeout
+        );
+      CreateEraseTypeEntry (Instance, SupportedEraseType);
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED_ERASE_TYPE_RECORD (Type 3).\n", __func__));
+      ASSERT (FALSE);
+    }
+  }
+
+  // Build up erase type 4 entry.
+  if (Instance->SfdpBasicFlash->Erase4Size != 0) {
+    SupportedEraseType = AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_TYPE_RECORD));
+    if (SupportedEraseType != NULL) {
+      SupportedEraseType->EraseType        = SFDP_ERASE_TYPE_4;
+      SupportedEraseType->EraseInstruction = (UINT8)Instance->SfdpBasicFlash->Erase4Instr;
+      SupportedEraseType->EraseSizeInByte  = (UINT32)1 << Instance->SfdpBasicFlash->Erase4Size;
+      CalculateEraseTiming (
+        Instance->SfdpBasicFlash->Erase4Time,
+        Instance->SfdpBasicFlash->EraseMultiplier,
+        &SupportedEraseType->EraseTypicalTime,
+        &SupportedEraseType->EraseTimeout
+        );
+      CreateEraseTypeEntry (Instance, SupportedEraseType);
+    } else {
+      DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED_ERASE_TYPE_RECORD (Type 4).\n", __func__));
+      ASSERT (FALSE);
+    }
+  }
+}
+
+/**
+  This function check if the erase type is one of the target erase types.
+
+  @param[in]   EraseType       The erase type.
+  @param[in]   TargetTypeNum   Number of target search types.
+  @param[in]   TargetTypes     Target types.
+
+
+  @retval     TRUE    Yes, this is the target erase type.
+  @retval     FALSE   No, this is not the target erase type.
+
+**/
+BOOLEAN
+IsTargetEraseType (
+  IN UINT16  EraseType,
+  IN UINT8   TargetTypeNum,
+  IN UINT8   *TargetTypes
+  )
+{
+  UINT8  Index;
+
+  for (Index = 0; Index < TargetTypeNum; Index++) {
+    if (EraseType == *(TargetTypes + Index)) {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Search the erase type record according to the given search type and value.
+
+  @param[in]   Instance                SPI Nor Flash Instance data with pointer to
+                                       EFI_SPI_NOR_FLASH_PROTOCOL and
+                                       EFI_SPI_IO_PROTOCOL.
+  @param[in]   SearchType              Search type.
+  @param[in]   SearchValue             The value of according to search type.
+                                       - For SearchEraseTypeByCommand:
+                                         SearchValue is the erase instruction.
+                                       - For SearchEraseTypeBySize:
+                                          SearchValue is the erase block size.
+                                       - For SearchEraseTypeBySmallestSize:
+                                         SearchValue is not used.
+                                       - For SearchEraseTypeByBiggestSize:
+                                         SearchValue is not used.
+  @param[in]   SupportedTypeTargetNum  Only search the specific erase types.
+  @param[in]   SupportedTypeTarget     Pointer to SupportedTypeTargetNum of
+                                       supported erase types.
+  @param[out]  EraseTypeRecord         Pointer to receive the erase type record.
+
+  @retval     EFI_SUCCESS              Pointer to erase type record is returned.
+              EFI_INVALID_PARAMETER    Invalid SearchType.
+              EFI_NOT_FOUND            Erase type not found.
+**/
+EFI_STATUS
+GetEraseTypeRecord (
+  IN   SPI_NOR_FLASH_INSTANCE            *Instance,
+  IN   SFDP_SEARCH_ERASE_TYPE            SearchType,
+  IN   UINT32                            SearchValue,
+  IN   UINT8                             SupportedTypeTargetNum,
+  IN   UINT8                             *SupportedTypeTarget OPTIONAL,
+  OUT  SFDP_SUPPORTED_ERASE_TYPE_RECORD  **EraseTypeRecord
+  )
+{
+  SFDP_SUPPORTED_ERASE_TYPE_RECORD  *EraseType;
+  UINT32                            ValueToCompare;
+  BOOLEAN                           ExitSearching;
+
+  if (IsListEmpty (&Instance->SupportedEraseTypes)) {
+    return EFI_NOT_FOUND;
+  }
+
+  *EraseTypeRecord = NULL;
+
+  //
+  // Initial the comapre value.
+  //
+  switch (SearchType) {
+    case SearchEraseTypeByType:
+    case SearchEraseTypeByCommand:
+    case SearchEraseTypeBySize:
+      break;
+    case SearchEraseTypeBySmallestSize:
+      ValueToCompare = (UINT32)-1;
+      break;
+    case SearchEraseTypeByBiggestSize:
+      ValueToCompare = 0;
+      break;
+    default:
+      return EFI_INVALID_PARAMETER;
+  }
+
+  ExitSearching = FALSE;
+  EraseType     = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetFirstNode (&Instance->SupportedEraseTypes);
+  while (TRUE) {
+    if ((SupportedTypeTarget == NULL) || IsTargetEraseType (EraseType->EraseType, SupportedTypeTargetNum, SupportedTypeTarget)) {
+      switch (SearchType) {
+        case SearchEraseTypeByType:
+          if (EraseType->EraseType == SearchValue) {
+            *EraseTypeRecord = EraseType;
+            ExitSearching    = TRUE;
+          }
+
+          break;
+
+        case SearchEraseTypeBySize:
+          if (EraseType->EraseSizeInByte == SearchValue) {
+            *EraseTypeRecord = EraseType;
+            ExitSearching    = TRUE;
+          }
+
+          break;
+
+        case SearchEraseTypeByCommand:
+          if (EraseType->EraseInstruction == (UINT8)SearchValue) {
+            *EraseTypeRecord = EraseType;
+            ExitSearching    = TRUE;
+          }
+
+          break;
+
+        case SearchEraseTypeBySmallestSize:
+          if (EraseType->EraseSizeInByte < ValueToCompare) {
+            ValueToCompare   = EraseType->EraseSizeInByte;
+            *EraseTypeRecord = EraseType;
+          }
+
+          break;
+
+        case SearchEraseTypeByBiggestSize:
+          if (EraseType->EraseSizeInByte > ValueToCompare) {
+            ValueToCompare   = EraseType->EraseSizeInByte;
+            *EraseTypeRecord = EraseType;
+          }
+
+          break;
+
+        default:
+          return EFI_INVALID_PARAMETER;
+      }
+    }
+
+    if (IsNodeAtEnd (&Instance->SupportedEraseTypes, &EraseType->NextEraseType) || ExitSearching) {
+      break;
+    }
+
+    EraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNextNode (&Instance->SupportedEraseTypes, &EraseType->NextEraseType);
+  }
+
+  if (*EraseTypeRecord == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get the erase block attribute for the target address.
+
+  @param[in]      Instance              Spi Nor Flash Instance data with pointer to
+                                        EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+  @param[in]      FlashRegion           The region the flash address belong.
+  @param[in]      FlashAddress          The target flash address.
+  @param[in]      RemainingSize         Remaining size to erase.
+  @param[in, out] BlockSizeToErase      Input  - The block erase size for this continious blocks.
+                                        Output - The determined block size for erasing.
+  @param[in, out] BlockCountToErase     Input  - The expected blocks to erase.
+                                        Output - The determined number of blocks to erase.
+  @param[out]     BlockEraseCommand     The erase command used for this continious blocks.
+
+  @retval EFI_SUCCESS          The erase block attribute is returned.
+  @retval EFI_DEVICE_ERROR     No valid SFDP discovered.
+  @retval EFI_NOT_FOUND        No valud erase block attribute found.
+
+**/
+EFI_STATUS
+GetEraseBlockAttribute (
+  IN     SPI_NOR_FLASH_INSTANCE     *Instance,
+  IN     SFDP_SECTOR_REGION_RECORD  *FlashRegion,
+  IN     UINT32                     FlashAddress,
+  IN     UINT32                     RemainingSize,
+  IN OUT UINT32                     *BlockSizeToErase,
+  IN OUT UINT32                     *BlockCountToErase,
+  OUT    UINT8                      *BlockEraseCommand
+  )
+{
+  EFI_STATUS                        Status;
+  SFDP_SUPPORTED_ERASE_TYPE_RECORD  *EraseType;
+  UINT32                            EraseSize;
+
+  DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__));
+
+  for (EraseSize = SIZE_2GB; EraseSize != 0; EraseSize = EraseSize >> 1) {
+    Status = GetEraseTypeRecord (Instance, SearchEraseTypeBySize, EraseSize, 0, NULL, &EraseType);
+    if (!EFI_ERROR (Status)) {
+      // Validate this erase type.
+      if (((FlashAddress & (EraseType->EraseSizeInByte - 1)) == 0) &&
+          (RemainingSize >= EraseType->EraseSizeInByte))
+      {
+        *BlockSizeToErase  = EraseType->EraseSizeInByte;
+        *BlockCountToErase = 1;
+        *BlockEraseCommand = EraseType->EraseInstruction;
+        Status             = EFI_SUCCESS;
+        break;
+      }
+    }
+  }
+
+  if (EraseType == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  DEBUG ((DEBUG_VERBOSE, "  Erase address at 0x%08x.\n", FlashAddress));
+  DEBUG ((DEBUG_VERBOSE, "    - Erase block size   : 0x%08x.\n", *BlockSizeToErase));
+  DEBUG ((DEBUG_VERBOSE, "    - Erase block count  : 0x%08x.\n", *BlockCountToErase));
+  DEBUG ((DEBUG_VERBOSE, "    - Erase block command: 0x%02x.\n", *BlockEraseCommand));
+  DEBUG ((DEBUG_VERBOSE, "    - Remaining size to erase: 0x%08x.\n", RemainingSize));
+  return EFI_SUCCESS;
+}
+
+/**
+  Get the erase block attribute for the target address.
+
+  @param[in]   Instance                Spi Nor Flash Instance data with pointer to
+                                       EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+  @param[in]   FlashAddress            The target flash address.
+  @param[out]  FlashRegion             The target flash address.
+
+  @retval EFI_SUCCESS             The region is returned.
+  @retval EFI_INVALID_PARAMETER   FlashAddress is not belong to any region.
+  @retval Otherwise               Other errors.
+
+**/
+EFI_STATUS
+GetRegionByFlashAddress (
+  IN  SPI_NOR_FLASH_INSTANCE      *Instance,
+  IN  UINT32                      FlashAddress,
+  OUT  SFDP_SECTOR_REGION_RECORD  **FlashRegion
+  )
+{
+  SFDP_SECTOR_MAP_RECORD     *SectorMapRecord;
+  SFDP_SECTOR_REGION_RECORD  *RegionRecord;
+
+  DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__));
+
+  SectorMapRecord = Instance->CurrentSectorMap;
+  if (SectorMapRecord == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  RegionRecord = (SFDP_SECTOR_REGION_RECORD *)GetFirstNode (&SectorMapRecord->RegionList);
+  while (TRUE) {
+    if ((FlashAddress >= RegionRecord->RegionAddress) &&
+        (FlashAddress < RegionRecord->RegionAddress + RegionRecord->RegionTotalSize))
+    {
+      *FlashRegion = RegionRecord;
+      return EFI_SUCCESS;
+    }
+
+    if (IsNodeAtEnd (&SectorMapRecord->RegionList, &RegionRecord->NextRegion)) {
+      break;
+    }
+
+    RegionRecord = (SFDP_SECTOR_REGION_RECORD *)GetNextNode (&SectorMapRecord->RegionList, &RegionRecord->NextRegion);
+  }
+
+  return EFI_INVALID_PARAMETER;
+}
+
+/**
+  Build up the Fast Read capability tables. The earlier linked table
+  in the linked list has the faster transfer.
+  NOTE: 1. The Quad input instructions mentioned in 21th DWOWRD
+           are not considered yet.
+        2. Maximum speed options for certain Fast Read modes are
+           not considered yet. (e.g., 8D-8D-8D or 4S-4D-4D)
+
+  @param[in]  Instance    SPI Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and
+                          EFI_SPI_IO_PROTOCOL.
+
+**/
+VOID
+BuildUpFastReadTable (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  // Build up the standard Fast Read
+  // This will be first picked for the ReadData.
+  // TODO: The mechanism to choose the advance fast read
+  //       is not determined yet in this version of
+  //       SpiNorFlash driver.
+  CreateSpiFastReadTableEntry (
+    Instance,
+    SPI_FLASH_FAST_READ,
+    0,
+    SPI_FLASH_FAST_READ_DUMMY * 8
+    );
+
+  // Build up Fast Read table 1S-1S-4S
+  if (Instance->SfdpBasicFlash->FastRead114 != 0) {
+    CreateSpiFastReadTableEntry (
+      Instance,
+      Instance->SfdpBasicFlash->FastRead114Instr,
+      Instance->SfdpBasicFlash->FastRead114ModeClk,
+      Instance->SfdpBasicFlash->FastRead114Dummy
+      );
+  }
+
+  // Build up Fast Read table 1S-2S-2S
+  if (Instance->SfdpBasicFlash->FastRead122 != 0) {
+    CreateSpiFastReadTableEntry (
+      Instance,
+      Instance->SfdpBasicFlash->FastRead122Instr,
+      Instance->SfdpBasicFlash->FastRead122ModeClk,
+      Instance->SfdpBasicFlash->FastRead122Dummy
+      );
+  }
+
+  // Build up Fast Read table 2S-2S-2S
+  if (Instance->SfdpBasicFlash->FastRead222 != 0) {
+    CreateSpiFastReadTableEntry (
+      Instance,
+      Instance->SfdpBasicFlash->FastRead222Instr,
+      Instance->SfdpBasicFlash->FastRead222ModeClk,
+      Instance->SfdpBasicFlash->FastRead222Dummy
+      );
+  }
+
+  // Build up Fast Read table 1S-4S-4S
+  if (Instance->SfdpBasicFlash->FastRead144 != 0) {
+    CreateSpiFastReadTableEntry (
+      Instance,
+      Instance->SfdpBasicFlash->FastRead144Instr,
+      Instance->SfdpBasicFlash->FastRead144ModeClk,
+      Instance->SfdpBasicFlash->FastRead144Dummy
+      );
+  }
+
+  // Build up Fast Read table 4S-4S-4S
+  if (Instance->SfdpBasicFlash->FastRead444 != 0) {
+    CreateSpiFastReadTableEntry (
+      Instance,
+      Instance->SfdpBasicFlash->FastRead444Instr,
+      Instance->SfdpBasicFlash->FastRead444ModeClk,
+      Instance->SfdpBasicFlash->FastRead444Dummy
+      );
+  }
+
+  // Build up Fast Read table 1S-1S-8S
+  if (Instance->SfdpBasicFlash->FastRead118Instr != 0) {
+    CreateSpiFastReadTableEntry (
+      Instance,
+      Instance->SfdpBasicFlash->FastRead118Instr,
+      Instance->SfdpBasicFlash->FastRead118ModeClk,
+      Instance->SfdpBasicFlash->FastRead118Dummy
+      );
+  }
+
+  // Build up Fast Read table 1S-8S-8S
+  if (Instance->SfdpBasicFlash->FastRead188Instr != 0) {
+    CreateSpiFastReadTableEntry (
+      Instance,
+      Instance->SfdpBasicFlash->FastRead188Instr,
+      Instance->SfdpBasicFlash->FastRead188ModeClk,
+      Instance->SfdpBasicFlash->FastRead188Dummy
+      );
+  }
+}
+
+/**
+  This function sets up the erase types supported
+  by this region.
+
+  @param[in]  Instance          SPI Nor Flash Instance data with pointer to
+                                EFI_SPI_NOR_FLASH_PROTOCOL and
+                                EFI_SPI_IO_PROTOCOL.
+  @param[in]  RegionRecord      Pointer to SFDP_SECTOR_REGION_RECORD of this
+                                regions.
+  @retval     EFI_SUCCESS       Current sector map configuration is determined.
+              EFI_DEVICE_ERROR  Current sector map configuration is not found.
+
+**/
+EFI_STATUS
+SetupRegionEraseInfo (
+  IN  SPI_NOR_FLASH_INSTANCE     *Instance,
+  IN  SFDP_SECTOR_REGION_RECORD  *RegionRecord
+  )
+{
+  SFDP_SUPPORTED_ERASE_TYPE_RECORD  *SupportedEraseType;
+  UINT32                            MinimumEraseSize;
+
+  if (IsListEmpty (&Instance->SupportedEraseTypes)) {
+    DEBUG ((DEBUG_ERROR, "%a: No erase type suppoted on the flash device.\n", __func__));
+    ASSERT (FALSE);
+    return EFI_DEVICE_ERROR;
+  }
+
+  MinimumEraseSize   = (UINT32)-1;
+  SupportedEraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetFirstNode (&Instance->SupportedEraseTypes);
+  while (TRUE) {
+    RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = (UINT8)SupportedEraseType->EraseType;
+    RegionRecord->SupportedEraseTypeNum++;
+    RegionRecord->EraseTypeBySizeBitmap |= SupportedEraseType->EraseSizeInByte;
+    if (MinimumEraseSize > SupportedEraseType->EraseSizeInByte) {
+      MinimumEraseSize = SupportedEraseType->EraseSizeInByte;
+    }
+
+    if (IsNodeAtEnd (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType)) {
+      break;
+    }
+
+    SupportedEraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNextNode (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType);
+  }
+
+  RegionRecord->SectorSize      = MinimumEraseSize;
+  RegionRecord->RegionTotalSize = Instance->FlashDeviceSize;
+  RegionRecord->RegionSectors   = RegionRecord->RegionTotalSize / RegionRecord->SectorSize;
+  return EFI_SUCCESS;
+}
+
+/**
+  Create a single flash sector map.
+
+  @param[in]  Instance          SPI Nor Flash Instance data with pointer to
+                                EFI_SPI_NOR_FLASH_PROTOCOL and
+                                EFI_SPI_IO_PROTOCOL.
+  @retval     EFI_SUCCESS         Current sector map configuration is determined.
+              EFI_DEVICE_ERROR    Current sector map configuration is not found.
+
+**/
+EFI_STATUS
+CreateSingleFlashSectorMap (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  SFDP_SECTOR_MAP_RECORD     *SectorMapRecord;
+  SFDP_SECTOR_REGION_RECORD  *RegionRecord;
+  UINTN                      EraseIndex;
+
+  DEBUG ((DEBUG_VERBOSE, "%a: Entry:\n", __func__));
+  SectorMapRecord = (SFDP_SECTOR_MAP_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_MAP_RECORD));
+  if (SectorMapRecord == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DETECTION_RECORD.\n", __func__));
+    ASSERT (FALSE);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  // Create SFDP_SECTOR_MAP_RECORD.
+  InitializeListHead (&SectorMapRecord->NextDescriptor);
+  InitializeListHead (&SectorMapRecord->RegionList);
+  SectorMapRecord->ConfigurationId = 0;
+  SectorMapRecord->RegionCount     = 1;
+  InsertTailList (&Instance->ConfigurationMapList, &SectorMapRecord->NextDescriptor);
+  DEBUG ((DEBUG_VERBOSE, "    Sector map configurations ID     : 0x%x\n", SectorMapRecord->ConfigurationId));
+  DEBUG ((DEBUG_VERBOSE, "    Sector map configurations regions: %d\n", SectorMapRecord->RegionCount));
+
+  // Create SFDP_SECTOR_MAP_RECORD region record.
+  RegionRecord = (SFDP_SECTOR_REGION_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_REGION_RECORD));
+  if (RegionRecord == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_REGION_RECORD.\n", __func__));
+    ASSERT (FALSE);
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  InitializeListHead (&RegionRecord->NextRegion);
+
+  RegionRecord->RegionAddress = 0;
+  //
+  // Setup erase information in the region record.
+  //
+  SetupRegionEraseInfo (Instance, RegionRecord);
+
+  InsertTailList (&SectorMapRecord->RegionList, &RegionRecord->NextRegion);
+
+  Instance->CurrentSectorMap = SectorMapRecord;
+
+  DEBUG ((DEBUG_VERBOSE, "    Region totoal size         : 0x%x\n", RegionRecord->RegionTotalSize));
+  DEBUG ((DEBUG_VERBOSE, "    Region sector size         : 0x%x\n", RegionRecord->SectorSize));
+  DEBUG ((DEBUG_VERBOSE, "    Region sectors             : 0x%x\n", RegionRecord->RegionSectors));
+
+  for (EraseIndex = 0; EraseIndex < RegionRecord->SupportedEraseTypeNum; EraseIndex++) {
+    DEBUG ((DEBUG_VERBOSE, "    Region erase type supported: 0x%x\n", RegionRecord->SupportedEraseType[EraseIndex]));
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set EraseBlockBytes in SPI NOR Flash Protocol
+
+  @param[in]  Instance    Spi Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS     The erase block size is returned.
+  @retval Otherwise       Failed to get erase block size.
+
+**/
+EFI_STATUS
+SetSectorEraseBlockSize (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS                        Status;
+  SFDP_SUPPORTED_ERASE_TYPE_RECORD  *EraseTypeRecord;
+
+  // Use the smallest size for the sector erase.
+  Status = GetEraseTypeRecord (Instance, SearchEraseTypeBySmallestSize, 0, 0, NULL, &EraseTypeRecord);
+  if (!EFI_ERROR (Status)) {
+    Instance->Protocol.EraseBlockBytes = EraseTypeRecord->EraseSizeInByte;
+    DEBUG ((DEBUG_VERBOSE, "  Erase block size = 0x%08x\n", EraseTypeRecord->EraseSizeInByte));
+  }
+
+  return Status;
+}
+
+/**
+  Get the current sector map configuration.
+
+  @param[in]  Instance    SPI Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and
+                          EFI_SPI_IO_PROTOCOL.
+
+  @retval     EFI_SUCCESS         Current sector map configuration is determined.
+              EFI_DEVICE_ERROR    Current sector map configuration is not found.
+
+**/
+EFI_STATUS
+GetCurrentSectorMapConfiguration (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS                        Status;
+  UINT32                            TransactionBufferLength;
+  UINT8                             AddressLength;
+  BOOLEAN                           UseAddress;
+  UINT32                            DummyBytes;
+  UINT8                             ReturnByte;
+  UINT8                             ConfigurationId;
+  SFDP_SECTOR_MAP_RECORD            *SectorMap;
+  SFDP_SECTOR_MAP_DETECTION_RECORD  *CommandEntry;
+
+  Instance->CurrentSectorMap = NULL;
+  if (!Instance->ConfigurationCommandsNeeded) {
+    // No command needed measn only one configuration for the flash device sector map.
+    Instance->CurrentSectorMap = (SFDP_SECTOR_MAP_RECORD *)GetFirstNode (&Instance->ConfigurationMapList);
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Send the command to collect interest bit.
+  //
+  ConfigurationId = 0;
+  CommandEntry    = (SFDP_SECTOR_MAP_DETECTION_RECORD *)GetFirstNode (&Instance->ConfigurationCommandList);
+  while (TRUE) {
+    // Check not WIP
+    Status = WaitNotWip (Instance);
+
+    // Read configuration byte.
+    AddressLength = SPI_ADDR_3BYTE_ONLY;
+    DummyBytes    = 1;
+    if (CommandEntry->CommandAddressLength == SpdfConfigurationCommandAddress4Byte) {
+      AddressLength = SPI_ADDR_4BYTE_ONLY;
+      DummyBytes    = 0;
+    }
+
+    UseAddress = TRUE;
+    if (CommandEntry->CommandAddress == SpdfConfigurationCommandAddressNone) {
+      UseAddress = FALSE;
+    }
+
+    TransactionBufferLength = FillWriteBuffer (
+                                Instance,
+                                CommandEntry->CommandInstruction,
+                                DummyBytes,
+                                AddressLength,
+                                UseAddress,
+                                CommandEntry->CommandAddress,
+                                0,
+                                NULL
+                                );
+    Status = Instance->SpiIo->Transaction (
+                                Instance->SpiIo,
+                                SPI_TRANSACTION_WRITE_THEN_READ,
+                                FALSE,
+                                0,
+                                1,
+                                8,
+                                TransactionBufferLength,
+                                Instance->SpiTransactionWriteBuffer,
+                                1,
+                                &ReturnByte
+                                );
+    ASSERT_EFI_ERROR (Status);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: Fails to read the configuration byte.\n", __func__));
+      ASSERT (FALSE);
+      return EFI_DEVICE_ERROR;
+    }
+
+    //
+    // Retrieve the interest bit.
+    //
+    if ((ReturnByte & CommandEntry->ConfigurationBitMask) != 0) {
+      ConfigurationId |= 0x01;
+    }
+
+    if (IsNodeAtEnd (&Instance->ConfigurationCommandList, &CommandEntry->NextCommand)) {
+      break;
+    }
+
+    CommandEntry    = (SFDP_SECTOR_MAP_DETECTION_RECORD *)GetNextNode (&Instance->ConfigurationCommandList, &CommandEntry->NextCommand);
+    ConfigurationId = ConfigurationId << 1;
+  }
+
+  //
+  // Now we have current activated configuration ID in ConfigurationId.
+  // Walk through ConfigurationMapList to record the activated flash sector
+  // map configuration.
+  //
+  SectorMap = (SFDP_SECTOR_MAP_RECORD *)GetFirstNode (&Instance->ConfigurationMapList);
+  while (TRUE) {
+    if (SectorMap->ConfigurationId == ConfigurationId) {
+      Instance->CurrentSectorMap = SectorMap;
+      break;
+    }
+
+    if (IsNodeAtEnd (&Instance->ConfigurationMapList, &SectorMap->NextDescriptor)) {
+      break;
+    }
+
+    SectorMap = (SFDP_SECTOR_MAP_RECORD *)GetNextNode (&Instance->ConfigurationMapList, &SectorMap->NextDescriptor);
+  }
+
+  if (Instance->CurrentSectorMap == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Activated flash sector map is not found!\n", __func__));
+    ASSERT (FALSE);
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Build sector map configurations.
+
+  @param[in]  Instance    SPI Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and
+                          EFI_SPI_IO_PROTOCOL.
+
+  @retval     EFI_SUCCESS           Records of sector map configuration command and map
+                                    descriptor are built up successfully.
+              EFI_OUT_OF_RESOURCES  Not enough memory resource.
+              EFI_DEVICE_ERROR      SFDP Sector Map Parameter is not
+                                    constructed correctly.
+
+**/
+EFI_STATUS
+BuildSectorMapCommandAndMap (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  SFDP_SECTOR_MAP_TABLE              *SfdpSectorMapTable;
+  SFDP_SECTOR_CONFIGURATION_COMMAND  *SfdpDetectionCommand;
+  SFDP_SECTOR_MAP_DETECTION_RECORD   *CommandEntry;
+  SFDP_SECTOR_CONFIGURATION_MAP      *SfdpConfigurationMap;
+  SFDP_SECTOR_MAP_RECORD             *SectorMapRecord;
+  SFDP_SECTOR_REGION                 *SpdfSectorRegion;
+  SFDP_SECTOR_REGION_RECORD          *RegionRecord;
+  SFDP_SUPPORTED_ERASE_TYPE_RECORD   *SupportedEraseType;
+  UINT8                              RegionCount;
+  UINT8                              EraseTypeCount;
+  UINT32                             MinimumEraseSize;
+  UINT32                             RegionAddress;
+
+  SfdpSectorMapTable   = Instance->SfdpFlashSectorMap;
+  SfdpConfigurationMap = &SfdpSectorMapTable->ConfigurationMap;
+  SfdpDetectionCommand = &SfdpSectorMapTable->ConfigurationCommand;
+
+  if (SfdpSectorMapTable->GenericHeader.DescriptorType == SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_MAP) {
+    // No configuration detection commands are needs.
+    Instance->ConfigurationCommandsNeeded = FALSE;
+  } else {
+    DEBUG ((DEBUG_VERBOSE, "%a: Sector map configuration detection command is needed\n", __func__));
+    Instance->ConfigurationCommandsNeeded = TRUE;
+
+    // Go through the section map detection commands.
+    while (TRUE) {
+      CommandEntry = (SFDP_SECTOR_MAP_DETECTION_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_MAP_DETECTION_RECORD));
+      if (CommandEntry == NULL) {
+        DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DETECTION_RECORD.\n", __func__));
+        ASSERT (FALSE);
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      InitializeListHead (&CommandEntry->NextCommand);
+      CommandEntry->CommandAddress       = SfdpDetectionCommand->CommandAddress;
+      CommandEntry->CommandAddressLength = (SPDF_CONFIGURATION_COMMAND_ADDR_LENGTH)SfdpDetectionCommand->DetectionCommandAddressLen;
+      CommandEntry->CommandInstruction   = (UINT8)SfdpDetectionCommand->DetectionInstruction;
+      CommandEntry->ConfigurationBitMask = (UINT8)SfdpDetectionCommand->ReadDataMask;
+      CommandEntry->LatencyInClock       = (UINT8)SfdpDetectionCommand->DetectionLatency;
+      InsertTailList (&Instance->ConfigurationCommandList, &CommandEntry->NextCommand);
+      DEBUG ((DEBUG_VERBOSE, "  Command instruction   : 0x%x\n", CommandEntry->CommandInstruction));
+      DEBUG ((DEBUG_VERBOSE, "  Bit selection         : 0x%x\n", CommandEntry->ConfigurationBitMask));
+      DEBUG ((DEBUG_VERBOSE, "  Command address       : 0x%x\n", CommandEntry->CommandAddress));
+      DEBUG ((DEBUG_VERBOSE, "  Command address length: %d\n", CommandEntry->CommandAddressLength));
+      DEBUG ((DEBUG_VERBOSE, "  Command latency clocks: %d\n\n", CommandEntry->LatencyInClock));
+      if (SfdpDetectionCommand->DescriptorEnd == SFDP_SECTOR_MAP_TABLE_ENTRY_LAST) {
+        break;
+      }
+
+      SfdpDetectionCommand++;
+    }
+
+    SfdpConfigurationMap = (SFDP_SECTOR_CONFIGURATION_MAP *)SfdpDetectionCommand++;
+  }
+
+  //
+  // Go through the region table pointed in SfdpConfigurationMap.
+  //
+  if (SfdpConfigurationMap->DescriptorType != SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_MAP) {
+    DEBUG ((DEBUG_ERROR, "%a: Incorrect format of Sector Map Parameter.\n", __func__));
+    ASSERT (FALSE);
+    return EFI_DEVICE_ERROR;
+  }
+
+  while (TRUE) {
+    DEBUG ((DEBUG_VERBOSE, "%a: Sector map configurations:\n", __func__));
+    SectorMapRecord = (SFDP_SECTOR_MAP_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_MAP_RECORD));
+    if (SectorMapRecord == NULL) {
+      DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DETECTION_RECORD.\n", __func__));
+      ASSERT (FALSE);
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    InitializeListHead (&SectorMapRecord->NextDescriptor);
+    InitializeListHead (&SectorMapRecord->RegionList);
+    SectorMapRecord->ConfigurationId = (UINT8)SfdpConfigurationMap->ConfigurationID;
+    SectorMapRecord->RegionCount     = (UINT8)SfdpConfigurationMap->RegionCount;
+    InsertTailList (&Instance->ConfigurationMapList, &SectorMapRecord->NextDescriptor);
+    DEBUG ((DEBUG_VERBOSE, "    Sector map configurations ID     : 0x%x\n", SectorMapRecord->ConfigurationId));
+    DEBUG ((DEBUG_VERBOSE, "    Sector map configurations regions: %d\n", SectorMapRecord->RegionCount));
+    SpdfSectorRegion = (SFDP_SECTOR_REGION *)SfdpConfigurationMap + 1;
+    RegionAddress    = 0;
+    for (RegionCount = 0; RegionCount < SectorMapRecord->RegionCount; RegionCount++) {
+      RegionRecord = (SFDP_SECTOR_REGION_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_REGION_RECORD));
+      if (RegionRecord == NULL) {
+        DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DETECTION_RECORD.\n", __func__));
+        ASSERT (FALSE);
+        return EFI_OUT_OF_RESOURCES;
+      }
+
+      InitializeListHead (&RegionRecord->NextRegion);
+      RegionRecord->RegionTotalSize = (SpdfSectorRegion->RegionSize + 1) * SFDP_SECTOR_REGION_SIZE_UNIT;
+      //
+      // Construct erase type supported for this region.
+      //
+      if (SpdfSectorRegion->EraseType1 != 0) {
+        RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = SFDP_ERASE_TYPE_1;
+        RegionRecord->SupportedEraseTypeNum++;
+      }
+
+      if (SpdfSectorRegion->EraseType2 != 0) {
+        RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = SFDP_ERASE_TYPE_2;
+        RegionRecord->SupportedEraseTypeNum++;
+      }
+
+      if (SpdfSectorRegion->EraseType3 != 0) {
+        RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = SFDP_ERASE_TYPE_3;
+        RegionRecord->SupportedEraseTypeNum++;
+      }
+
+      if (SpdfSectorRegion->EraseType4 != 0) {
+        RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = SFDP_ERASE_TYPE_4;
+        RegionRecord->SupportedEraseTypeNum++;
+      }
+
+      //
+      // Calculate the sector size and total sectors.
+      //
+      if (IsListEmpty (&Instance->SupportedEraseTypes)) {
+        DEBUG ((DEBUG_ERROR, "%a: No erase type suppoted on the flash device.\n", __func__));
+        ASSERT (FALSE);
+        return EFI_DEVICE_ERROR;
+      }
+
+      MinimumEraseSize = (UINT32)-1;
+      for (EraseTypeCount = 0; EraseTypeCount < RegionRecord->SupportedEraseTypeNum++; EraseTypeCount++) {
+        //
+        // Walk through Instance->SupportedEraseTypes to find the matching erase type and
+        // Use the minimum erase size as the sector size;
+        //
+        SupportedEraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetFirstNode (&Instance->SupportedEraseTypes);
+        while (TRUE) {
+          if (RegionRecord->SupportedEraseType[EraseTypeCount] == SupportedEraseType->EraseType) {
+            // Set erase size bitmap.
+            RegionRecord->EraseTypeBySizeBitmap |= SupportedEraseType->EraseSizeInByte;
+
+            if (MinimumEraseSize > SupportedEraseType->EraseSizeInByte) {
+              MinimumEraseSize = SupportedEraseType->EraseSizeInByte;
+              break;
+            }
+          }
+
+          if (IsNodeAtEnd (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType)) {
+            break;
+          }
+
+          SupportedEraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNextNode (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType);
+        }
+      }
+
+      RegionRecord->SectorSize    = MinimumEraseSize;
+      RegionRecord->RegionSectors = RegionRecord->RegionTotalSize / RegionRecord->SectorSize;
+      RegionRecord->RegionAddress = RegionAddress;
+
+      // Insert to link.
+      InsertTailList (&SectorMapRecord->RegionList, &RegionRecord->NextRegion);
+      DEBUG ((DEBUG_VERBOSE, "        Region: %d\n", RegionCount));
+      DEBUG ((DEBUG_VERBOSE, "          Region totoal size: 0x%x\n", RegionRecord->RegionTotalSize));
+      DEBUG ((DEBUG_VERBOSE, "          Region sector size: 0x%x\n", RegionRecord->SectorSize));
+      DEBUG ((DEBUG_VERBOSE, "          Region sectors    : 0x%x\n", RegionRecord->RegionSectors));
+      DEBUG ((DEBUG_VERBOSE, "          Region erase supported bitmap: 0x%x\n", RegionRecord->EraseTypeBySizeBitmap));
+
+      SpdfSectorRegion++;
+      RegionAddress += RegionRecord->RegionTotalSize;
+    }
+
+    if (SfdpConfigurationMap->DescriptorEnd == SFDP_SECTOR_MAP_TABLE_ENTRY_LAST) {
+      break;
+    }
+
+    SfdpConfigurationMap = (SFDP_SECTOR_CONFIGURATION_MAP *)SpdfSectorRegion;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This routine get Write Enable latch command.
+
+  @param[in]  Instance    SPI Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and
+                          EFI_SPI_IO_PROTOCOL.
+
+**/
+VOID
+GetWriteEnableCommand  (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  //
+  // Set Wrtie Enable command.
+  //
+  Instance->WriteEnableLatchRequired = TRUE;
+  Instance->WriteEnableLatchCommand  = SPI_FLASH_WREN;
+  if (Instance->SfdpBasicFlash->VolatileStatusBlockProtect == 1) {
+    if (Instance->SfdpBasicFlash->WriteEnableVolatileStatus == 0) {
+      Instance->WriteEnableLatchCommand = SPI_FLASH_WREN_50H;
+    }
+  }
+
+  DEBUG ((DEBUG_ERROR, "%a: Use Write Enable Command 0x%x.\n", __func__, Instance->WriteEnableLatchCommand));
+}
+
+/**
+  This routine returns the desired Fast Read mode.
+
+  @param[in]           Instance                 Spi Nor Flash Instance data with pointer to
+                                                EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+  @param[in,out]       FastReadInstruction      Fast Read instruction, the input is
+                                                the default value.
+  @param[in,out]       FastReadModeBits         The operational mode bits.
+  @param[in,out]       FastReadDummyClocks      Fast Read wait state (Dummy clocks), the
+                                                input is the default value.
+  @param[out]          FastReadStr              Pointer to retrieve the human readable string
+                                                of fast read mode.
+  @retval EFI_SUCCESS     The parameters are updated.
+  @retval EFI_NOT_FOUND   No desired Fas Read mode found.
+
+**/
+EFI_STATUS
+GetFastReadParameter (
+  IN     SPI_NOR_FLASH_INSTANCE  *Instance,
+  IN OUT UINT8                   *FastReadInstruction,
+  IN OUT UINT8                   *FastReadModeBits,
+  IN OUT UINT8                   *FastReadDummyClocks
+  )
+{
+  SFPD_FAST_READ_CAPBILITY_RECORD  *FastReadEntry;
+
+  if (IsListEmpty (&Instance->FastReadTableList)) {
+    return EFI_NOT_FOUND;
+  }
+
+  FastReadEntry        = (SFPD_FAST_READ_CAPBILITY_RECORD *)GetFirstNode (&Instance->FastReadTableList);
+  *FastReadInstruction = FastReadEntry->FastReadInstruction;
+  *FastReadDummyClocks = FastReadEntry->WaitStates;
+  *FastReadModeBits    = FastReadEntry->ModeClocks;
+
+  //
+  // *FastReadOperationClock may be replaced by 8D-8D-8D or 4S-4D-4D Fast Read
+  // mode clock operation mode. Which is not cosidered in the implementation yet.
+  //
+  return EFI_SUCCESS;
+}
+
+/**
+  Return the flash device size from SFDP Basic Flash Parameter Table DWORD 2
+
+  @param[in]  Instance    Spi Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and
+                          EFI_SPI_IO_PROTOCOL.
+
+  @retval   UINT32        Flash device size in byte, zero indicates error.
+
+**/
+UINT32
+SfdpGetFlashSize (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  if (Instance == NULL) {
+    return 0;
+  }
+
+  if ((Instance->SfdpBasicFlash->Density & SFDP_FLASH_MEMORY_DENSITY_4GBIT) == 0) {
+    //
+    // The flash device size is <= 256MB.
+    //
+    return (Instance->SfdpBasicFlash->Density + 1) / 8;
+  }
+
+  //
+  // The flash deivce size is >= 512MB.
+  // Bit [0:30] defines 'N' where the density is computed as 2^N bits.
+  // N must be >=32 according to the SFDP specification.
+  //
+  if ((Instance->SfdpBasicFlash->Density & ~SFDP_FLASH_MEMORY_DENSITY_4GBIT) < 32) {
+    return 0;
+  }
+
+  return (UINT32)RShiftU64 (LShiftU64 (1, Instance->SfdpBasicFlash->Density & ~SFDP_FLASH_MEMORY_DENSITY_4GBIT), 3);
+}
+
+/**
+  Read SFDP Header
+
+  This routine reads the JEDEC SPI Flash Discoverable Parameter header from the
+  SPI chip.  Fails if Major Revision is not = 1
+
+  @param[in]  Instance    Spi Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS            Header is filled in
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadSfdpHeader (
+  IN      SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      TransactionBufferLength;
+
+  // Check not WIP
+  Status = WaitNotWip (Instance);
+
+  // Read SFDP Header
+  TransactionBufferLength = FillWriteBuffer (
+                              Instance,
+                              SPI_FLASH_RDSFDP,
+                              SPI_FLASH_RDSFDP_DUMMY,
+                              SPI_FLASH_RDSFDP_ADDR_BYTES,
+                              TRUE,
+                              0,
+                              0,
+                              NULL
+                              );
+  Status = Instance->SpiIo->Transaction (
+                              Instance->SpiIo,
+                              SPI_TRANSACTION_WRITE_THEN_READ,
+                              FALSE,
+                              0,
+                              1,
+                              8,
+                              TransactionBufferLength,
+                              Instance->SpiTransactionWriteBuffer,
+                              sizeof (SFDP_HEADER),
+                              (UINT8 *)&Instance->SfdpHeader
+                              );
+  ASSERT_EFI_ERROR (Status);
+  if (!EFI_ERROR (Status)) {
+    // Read Basic Flash Parameter Header
+    if ((Instance->SfdpHeader.Signature != SFDP_HEADER_SIGNATURE) ||
+        (Instance->SfdpHeader.MajorRev != SFDP_SUPPORTED_MAJOR_REVISION))
+    {
+      Status = EFI_DEVICE_ERROR;
+    } else {
+      DEBUG ((DEBUG_VERBOSE, "Total %d parameter headers\n", Instance->SfdpHeader.NumParameterHeaders + 1));
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Read SFDP
+  This routine reads the JEDEC SPI Flash Discoverable Parameters. We just
+  read the necessary tables in this routine.
+
+  @param[in]  Instance    Spi Nor Flash Instance data with pointer to
+                          EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS            Header is filled in
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdp (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS                        Status;
+  SFDP_SUPPORTED_ERASE_TYPE_RECORD  *EraseTypeRecord;
+
+  InitializeListHead (&Instance->FastReadTableList);
+  InitializeListHead (&Instance->SupportedEraseTypes);
+  InitializeListHead (&Instance->ConfigurationCommandList);
+  InitializeListHead (&Instance->ConfigurationMapList);
+
+  DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__));
+
+  Status = ReadSfdpHeader (Instance);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to read SFDP header\n", __func__));
+    ASSERT (FALSE);
+    return Status;
+  }
+
+  Status = ReadSfdpBasicParameterTable (Instance);
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to read SFDP Basic Parameter Table\n", __func__));
+    ASSERT (FALSE);
+    return Status;
+  }
+
+  Instance->FlashDeviceSize = SfdpGetFlashSize (Instance);
+  DEBUG ((DEBUG_VERBOSE, "%a: Flash Size=0x%X\n", __func__, Instance->FlashDeviceSize));
+  if (Instance->FlashDeviceSize == 0) {
+    ASSERT (FALSE);
+    return Status;
+  }
+
+  Status = ReadSfdpSectorMapParameterTable (Instance);
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to read SFDP Sector Map Parameter Table\n", __func__));
+    ASSERT (FALSE);
+  } else if (Status == EFI_NOT_FOUND) {
+    DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device doesn't have SFDP Sector Map Parameter Table implemented:\n", __func__));
+
+    //
+    // No SFDP Sector Map Parameter Table exist.
+    // Check if device support the uniform 4K erase size.
+    //
+    Instance->Uniform4KEraseSupported = FALSE;
+    if (Instance->SfdpBasicFlash->EraseSizes == SPI_UNIFORM_4K_ERASE_SUPPORTED) {
+      DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device supports uniform 4K erase.\n", __func__));
+
+      // Check if 4K erase type supported?
+      Status = GetEraseTypeRecord (Instance, SearchEraseTypeBySize, SIZE_4KB, 0, NULL, &EraseTypeRecord);
+      if (Status == EFI_NOT_FOUND) {
+        DEBUG ((DEBUG_ERROR, "However, no corresponding 4K size erase type found.\n", __func__));
+        ASSERT (FALSE);
+      }
+
+      Instance->Uniform4KEraseSupported = TRUE;
+    } else {
+      // Uniform 4K erase unsupported, get the smallest erase block size.
+      DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device doesn't support uniform 4K erase.\n", __func__));
+    }
+
+    //
+    // Build flash map
+    // Instance->ConfigurationMapList is an empty list because no FDP Sector Map Parameter Table.
+    //
+    CreateSingleFlashSectorMap (Instance);
+    Status = EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+/**
+  Read SFDP Specific Parameter Header
+
+  This routine reads the JEDEC SPI Flash Discoverable Parameter header from the
+  SPI chip.  Fails if Major Revision is not = SFDP_SUPPORTED_MAJOR_REVISION.
+
+  @param[in]  Instance        Spi Nor Flash Instance data with pointer to
+                              EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+  @param[in]  SfdpHeader      SFDP Header Buffer Pointer
+  @param[in]  ParameterIdMsb  Most significant byte of parameter ID.
+  @param[in]  ParameterIdLsb  Lowest significant byte of parameter ID.
+
+  @retval EFI_SUCCESS            Header is filled in
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+  @retval EFI_NOT_FOUND          Unsupported Parameter Header.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadSfdpParameterHeader (
+  IN      SPI_NOR_FLASH_INSTANCE  *Instance,
+  IN      SFDP_PARAMETER_HEADER   *SfdpParameterHeader,
+  IN      UINT8                   ParameterIdMsb,
+  IN      UINT8                   ParameterIdLsb
+  )
+{
+  EFI_STATUS             Status;
+  UINT32                 Index;
+  SFDP_PARAMETER_HEADER  LocalSfdpParameterHeader;
+  UINT32                 TransactionBufferLength;
+
+  DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__));
+  DEBUG ((DEBUG_VERBOSE, "  Looking for Parameter Header %02x:%02x\n", ParameterIdMsb, ParameterIdLsb));
+
+  //
+  // Parse Parameter Headers Starting at size eof SFDP_HEADER.
+  // SfdpHeader.NumParameterHeaders is zero based, 0 means 1 parameter header.
+  //
+  ZeroMem (SfdpParameterHeader, sizeof (SFDP_PARAMETER_HEADER));
+  for (Index = 0; Index < Instance->SfdpHeader.NumParameterHeaders + 1; Index++) {
+    // Check not WIP
+    Status = WaitNotWip (Instance);
+    if (!EFI_ERROR (Status)) {
+      TransactionBufferLength = FillWriteBuffer (
+                                  Instance,
+                                  SPI_FLASH_RDSFDP,
+                                  SPI_FLASH_RDSFDP_DUMMY,
+                                  SPI_FLASH_RDSFDP_ADDR_BYTES,
+                                  TRUE,
+                                  sizeof (SFDP_HEADER) + Index * 8, // Parameter Header Index
+                                  0,
+                                  NULL
+                                  );
+      Status = Instance->SpiIo->Transaction (
+                                  Instance->SpiIo,
+                                  SPI_TRANSACTION_WRITE_THEN_READ,
+                                  FALSE,
+                                  0,
+                                  1,
+                                  8,
+                                  TransactionBufferLength,
+                                  Instance->SpiTransactionWriteBuffer,
+                                  sizeof (LocalSfdpParameterHeader),
+                                  (UINT8 *)&LocalSfdpParameterHeader
+                                  );
+      ASSERT_EFI_ERROR (Status);
+      if (!EFI_ERROR (Status)) {
+        // Break if SfdParamHeader is Type 0, Basic SPI Protocol Parameters
+        DEBUG ((
+          DEBUG_VERBOSE,
+          "  #%d Parameter Header: %02x:%02x, revision: %d.%d\n",
+          Index,
+          LocalSfdpParameterHeader.IdMsb,
+          LocalSfdpParameterHeader.IdLsb,
+          LocalSfdpParameterHeader.MajorRev,
+          LocalSfdpParameterHeader.MinorRev >= SfdpParameterHeader->MinorRev
+          ));
+        if ((LocalSfdpParameterHeader.IdLsb == ParameterIdLsb) &&
+            (LocalSfdpParameterHeader.IdMsb == ParameterIdMsb) &&
+            (LocalSfdpParameterHeader.MajorRev == (UINT32)SFDP_SUPPORTED_MAJOR_REVISION) &&
+            (LocalSfdpParameterHeader.MinorRev >= SfdpParameterHeader->MinorRev))
+        {
+          CopyMem (
+            (VOID **)SfdpParameterHeader,
+            (VOID **)&LocalSfdpParameterHeader,
+            sizeof (SFDP_PARAMETER_HEADER)
+            );
+        }
+      } else {
+        break;
+      }
+    } else {
+      break;
+    }
+  }
+
+  if (Status != EFI_DEVICE_ERROR) {
+    if ((SfdpParameterHeader->IdLsb != ParameterIdLsb) ||
+        (SfdpParameterHeader->IdMsb != ParameterIdMsb))
+    {
+      DEBUG ((DEBUG_ERROR, "  Parameter Header: %02x:%02x is not found.\n", ParameterIdMsb, ParameterIdLsb));
+      Status =  EFI_NOT_FOUND;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Read from SFDP table pointer
+
+  This routine sends SPI_FLASH_RDSFDP command and reads parameter from the
+  given TablePointer.
+
+  @param[in]  Instance           Spi Nor Flash Instance data with pointer to
+                                 EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+  @param[in]  TablePointer       Pointer to read data from SFDP.
+  @param[in]  DestBuffer         Destination buffer.
+  @param[in]  LengthInBytes      Length to read.
+
+  @retval EFI_SUCCESS            The SPI part size is filled.
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+  @retval Other errors
+
+**/
+EFI_STATUS
+EFIAPI
+SpiReadSfdpPtp (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance,
+  IN  UINT32                  TablePointer,
+  IN  VOID                    *DestBuffer,
+  IN  UINT32                  LengthInBytes
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      Length;
+  UINT8       *CurrentBuffer;
+  UINT32      ByteCounter;
+  UINT32      CurrentAddress;
+  UINT32      MaximumTransferBytes;
+  UINT32      TransactionBufferLength;
+
+  Length               = 0;
+  MaximumTransferBytes = Instance->SpiIo->MaximumTransferBytes;
+  CurrentBuffer        = (UINT8 *)DestBuffer;
+  for (ByteCounter = 0; ByteCounter < LengthInBytes; ByteCounter += Length) {
+    CurrentAddress = TablePointer + ByteCounter;
+    Length         = LengthInBytes - ByteCounter;
+
+    // Length must be MaximumTransferBytes or less
+    if (Length > MaximumTransferBytes) {
+      Length = MaximumTransferBytes;
+    }
+
+    // Check not WIP
+    Status = WaitNotWip (Instance);
+
+    //  Read Data
+    if (!EFI_ERROR (Status)) {
+      TransactionBufferLength = FillWriteBuffer (
+                                  Instance,
+                                  SPI_FLASH_RDSFDP,
+                                  SPI_FLASH_RDSFDP_DUMMY,
+                                  SPI_FLASH_RDSFDP_ADDR_BYTES,
+                                  TRUE,
+                                  CurrentAddress,
+                                  0,
+                                  NULL
+                                  );
+      Status = Instance->SpiIo->Transaction (
+                                  Instance->SpiIo,
+                                  SPI_TRANSACTION_WRITE_THEN_READ,
+                                  FALSE,
+                                  0,
+                                  1,
+                                  8,
+                                  TransactionBufferLength,
+                                  Instance->SpiTransactionWriteBuffer,
+                                  Length,
+                                  CurrentBuffer
+                                  );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Fails to read SFDP parameter.\n", __func__));
+        ASSERT_EFI_ERROR (Status);
+      }
+
+      CurrentBuffer += Length;
+    } else {
+      break;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Read SFDP Sector Map Parameter into buffer
+
+  This routine reads the JEDEC SPI Flash Discoverable Parameters from the SPI
+  chip.
+
+  @param[in]  Instance           Spi Nor Flash Instance data with pointer to
+                                 EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS            The SPI part size is filled.
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdpSectorMapParameterTable (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS             Status;
+  SFDP_PARAMETER_HEADER  SfdpParamHeader;
+
+  Status = ReadSfdpParameterHeader (
+             Instance,
+             &SfdpParamHeader,
+             SFDP_SECTOR_MAP_PARAMETER_ID_MSB,
+             SFDP_SECTOR_MAP_PARAMETER_ID_LSB
+             );
+  if (!EFI_ERROR (Status)) {
+    // Read Sector Map Parameters.  Already know it is MajorRev = SFDP_SUPPORTED_MAJOR_REVISION
+    Instance->SfdpSectorMapByteCount = SfdpParamHeader.Length * sizeof (UINT32);
+    Instance->SfdpFlashSectorMap     = AllocateZeroPool (Instance->SfdpSectorMapByteCount);
+    if (Instance->SfdpFlashSectorMap != NULL) {
+      // Read from SFDP Parameter Table Pointer (PTP).
+      Status = SpiReadSfdpPtp (
+                 Instance,
+                 SfdpParamHeader.TablePointer,
+                 (VOID *)Instance->SfdpFlashSectorMap,
+                 Instance->SfdpSectorMapByteCount
+                 );
+      if (!EFI_ERROR (Status)) {
+        Status = BuildSectorMapCommandAndMap (Instance);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((DEBUG_ERROR, "%a: Fails to build sector map command and descriptor.\n", __func__));
+          ASSERT (FALSE);
+          Status = GetCurrentSectorMapConfiguration (Instance);
+          if (EFI_ERROR (Status)) {
+            DEBUG ((DEBUG_ERROR, "%a: Fails to get current sector map configuration.\n", __func__));
+            ASSERT (FALSE);
+          }
+        }
+      } else {
+        FreePool (Instance->SfdpFlashSectorMap);
+        Instance->SfdpFlashSectorMap = NULL;
+        DEBUG ((DEBUG_ERROR, "%a: Fails to read SFDP Sector Map Parameter.\n", __func__));
+        ASSERT (FALSE);
+      }
+    } else {
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Fails to allocate memory for reading SFDP Sector Map Parameter.\n", __func__));
+        ASSERT (FALSE);
+      }
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Read SFDP Basic Parameters into buffer
+
+  This routine reads the JEDEC SPI Flash Discoverable Parameters from the SPI
+  chip.
+
+  @param[in]  Instance    Spi Nor Flash Instance data with pointer to
+  EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS            The SPI part size is filled.
+  @retval EFI_DEVICE_ERROR       Invalid data received from SPI flash part.
+  @retval EFI_NOT_FOUND          Parameter header is not found.
+
+**/
+EFI_STATUS
+ReadSfdpBasicParameterTable (
+  IN  SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS             Status;
+  SFDP_PARAMETER_HEADER  SfdpBasicFlashParamHeader;
+
+  Status = ReadSfdpParameterHeader (
+             Instance,
+             &SfdpBasicFlashParamHeader,
+             SFDP_BASIC_PARAMETER_ID_MSB,
+             SFDP_BASIC_PARAMETER_ID_LSB
+             );
+  if (!EFI_ERROR (Status)) {
+    // Read Basic Flash Parameters.  Already know it is MajorRev = SFDP_SUPPORTED_MAJOR_REVISION
+    Instance->SfdpBasicFlashByteCount = SfdpBasicFlashParamHeader.Length * sizeof (UINT32);
+    Instance->SfdpBasicFlash          = AllocateZeroPool (Instance->SfdpBasicFlashByteCount);
+    if (Instance->SfdpBasicFlash != NULL) {
+      // Read from SFDP Parameter Table Pointer (PTP).
+      Status = SpiReadSfdpPtp (
+                 Instance,
+                 SfdpBasicFlashParamHeader.TablePointer,
+                 (VOID *)Instance->SfdpBasicFlash,
+                 Instance->SfdpBasicFlashByteCount
+                 );
+      if (!EFI_ERROR (Status)) {
+        GetWriteEnableCommand (Instance);
+        //
+        // Build the Fast Read capability table according to
+        // the Basic Flash Parameter Table.
+        //
+        BuildUpFastReadTable (Instance);
+        BuildUpEraseTypeTable (Instance); // Build up erase type and size.
+
+        // Set current address bytes to 3-Bytes.
+        Instance->CurrentAddressBytes = 3;
+      } else {
+        FreePool (Instance->SfdpBasicFlash);
+        Instance->SfdpBasicFlash = NULL;
+        DEBUG ((DEBUG_ERROR, "%a: Fails to read SFDP Basic Parameter.\n", __func__));
+        ASSERT (FALSE);
+      }
+    } else {
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Fails to allocate memory for reading SFDP Basic Parameter.\n", __func__));
+        ASSERT (FALSE);
+      }
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Initial SPI_NOR_FLASH_INSTANCE structure.
+
+  @param[in]   Instance                Pointer to SPI_NOR_FLASH_INSTANCE.
+                                       EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+  @retval EFI_SUCCESS                  SPI_NOR_FLASH_INSTANCE is initialized according to
+                                       SPI NOR Flash SFDP specification.
+  @retval EFI_INVALID_PARAMETER        Instance = NULL or
+                                       Instance->SpiIo == NULL or
+                                       Instance->SpiIo->SpiPeripheral == NULL or
+                                       Instance->SpiIo->SpiPeripheral->SpiBus == NULL or
+                                       Instance->SpiIo->SpiPeripheral->SpiBus->ControllerPath.
+  @retval Otherwise                    Failed to initial SPI_NOR_FLASH_INSTANCE structure.
+
+**/
+EFI_STATUS
+InitialSpiNorFlashSfdpInstance (
+  IN SPI_NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_SPI_NOR_FLASH_PROTOCOL  *Protocol;
+
+  if (Instance == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Instance is NULL.\n", __func__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Instance->SpiIo == NULL) ||
+      (Instance->SpiIo->SpiPeripheral == NULL) ||
+      (Instance->SpiIo->SpiPeripheral->SpiBus == NULL)
+      )
+  {
+    DEBUG ((DEBUG_ERROR, "%a: One of SpiIo, SpiPeripheral and SpiBus is NULL.\n", __func__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Instance->Signature = SPI_NOR_FLASH_SIGNATURE;
+
+  // Allocate write buffer for SPI IO transactions with extra room for Opcode
+  // and Address with 10 bytes extra room.
+  Instance->SpiTransactionWriteBuffer =
+    AllocatePool (Instance->SpiIo->MaximumTransferBytes + 10);
+
+  Protocol                = &Instance->Protocol;
+  Protocol->SpiPeripheral = Instance->SpiIo->SpiPeripheral;
+  Protocol->GetFlashid    = GetFlashId;
+  Protocol->ReadData      = ReadData;      // Fast Read transfer
+  Protocol->LfReadData    = LfReadData;    // Normal Read transfer
+  Protocol->ReadStatus    = ReadStatus;
+  Protocol->WriteStatus   = WriteStatus;
+  Protocol->WriteData     = WriteData;
+  Protocol->Erase         = Erase;
+  Status                  = Protocol->GetFlashid (Protocol, (UINT8 *)&Protocol->Deviceid);
+  ASSERT_EFI_ERROR (Status);
+  DEBUG ((
+    DEBUG_VERBOSE,
+    "%a: Flash ID: Manufacturer=0x%02X, Device=0x%02X%02X\n",
+    __func__,
+    Protocol->Deviceid[0],
+    Protocol->Deviceid[1],
+    Protocol->Deviceid[2]
+    )
+    );
+
+  Status = ReadSfdp (Instance);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to Read SFDP\n", __func__));
+    ASSERT (FALSE);
+  }
+
+  // Get flash deivce size from SFDP.
+  Protocol->FlashSize = SfdpGetFlashSize (Instance);
+  DEBUG ((DEBUG_VERBOSE, "%a: Flash Size=0x%X\n", __func__, Protocol->FlashSize));
+  if (Protocol->FlashSize == 0) {
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  // Set flash erase block size.
+  Status = SetSectorEraseBlockSize (Instance);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fails to get the smallest erase block size.\n", __func__));
+    ASSERT (FALSE);
+  }
+
+  return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
new file mode 100644
index 00000000000..88d5c2ac96a
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
@@ -0,0 +1,261 @@
+/** @file
+  SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+  DXE driver.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Revision Reference:
+    - JEDEC Standard, JESD216F.02
+      https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+
+  @par Glossary:
+    - SFDP - Serial Flash Discoverable Parameters
+    - PTP  - Parameter Table Pointer
+**/
+
+#include <Base.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/SpiConfiguration.h>
+#include <Protocol/SpiNorFlash.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiNorFlash.h"
+#include "SpiNorFlashJedecSfdpInternal.h"
+
+/**
+  Function to create SPI_NOR_FLASH_INSTANCE for this SPI part.
+
+  @param[in] SpiIoHandle  The handle with SPI I/O protocol installed.
+
+  @retval EFI_SUCCESS           Succeed.
+  @retval EFI_OUT_OF_RESOURCES  Not enough resource to create SPI_NOR_FLASH_INSTANCE.
+  @retval otherwise             Fail to create SPI NOR Flash SFDP Instance
+**/
+EFI_STATUS
+CreateSpiNorFlashSfdpInstance (
+  IN EFI_HANDLE  SpiIoHandle
+  )
+{
+  EFI_STATUS              Status;
+  SPI_NOR_FLASH_INSTANCE  *Instance;
+
+  // Allocate SPI_NOR_FLASH_INSTANCE Instance.
+  Instance = AllocateZeroPool (sizeof (SPI_NOR_FLASH_INSTANCE));
+  ASSERT (Instance != NULL);
+  if (Instance == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  // Locate the SPI IO Protocol
+  Status = gBS->HandleProtocol (
+                  SpiIoHandle,
+                  &gEdk2JedecSfdpSpiDxeDriverGuid,
+                  (VOID **)&Instance->SpiIo
+                  );
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to locate SPI I/O protocol\n", __func__));
+    FreePool (Instance);
+  } else {
+    Status = InitialSpiNorFlashSfdpInstance (Instance);
+    ASSERT_EFI_ERROR (Status);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: Fail to initial SPI_NOR_FLASH_INSTANCE.\n", __func__));
+      FreePool (Instance);
+    } else {
+      // Install SPI NOR Flash Protocol.
+      Status = gBS->InstallProtocolInterface (
+                      &Instance->Handle,
+                      &gEfiSpiNorFlashProtocolGuid,
+                      EFI_NATIVE_INTERFACE,
+                      &Instance->Protocol
+                      );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Fail to Install gEfiSpiNorFlashProtocolGuid protocol.\n", __func__));
+        FreePool (Instance);
+      }
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Callback function executed when the EFI_SPI_IO_PROTOCOL
+  protocol interface is installed.
+
+  @param[in]   Event    Event whose notification function is being invoked.
+  @param[out]  Context  Pointer to SPI I/O protocol GUID.
+
+**/
+VOID
+EFIAPI
+SpiIoProtocolInstalledCallback (
+  IN  EFI_EVENT  Event,
+  OUT VOID       *Context
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       InstanceBufferSize;
+  EFI_HANDLE  InstanceBuffer;
+
+  DEBUG ((DEBUG_INFO, "%a: Entry.\n", __func__));
+  InstanceBufferSize = sizeof (EFI_HANDLE);
+  Status             = gBS->LocateHandle (
+                              ByRegisterNotify,
+                              (EFI_GUID *)Context,
+                              NULL,
+                              &InstanceBufferSize,
+                              &InstanceBuffer
+                              );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Can't locate SPI I/O protocol.\n", __func__));
+    DEBUG ((DEBUG_INFO, "%a: Exit.\n", __func__));
+    return;
+  }
+
+  CreateSpiNorFlashSfdpInstance (InstanceBuffer);
+  DEBUG ((DEBUG_INFO, "%a: Exit.\n", __func__));
+  return;
+}
+
+/**
+  Register for the later installed SPI I/O protocol notification.
+
+  @retval EFI_SUCCESS          Succeed.
+  @retval otherwise            Fail to register SPI I/O protocol installed
+                               notification.
+**/
+EFI_STATUS
+RegisterSpioProtocolNotification (
+  VOID
+  )
+{
+  EFI_EVENT   Event;
+  EFI_STATUS  Status;
+  VOID        *Registration;
+
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  SpiIoProtocolInstalledCallback,
+                  NULL,
+                  &Event
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to create event for the SPI I/O Protocol installation.", __func__));
+    return Status;
+  }
+
+  Status = gBS->RegisterProtocolNotify (
+                  &gEdk2JedecSfdpSpiDxeDriverGuid,
+                  Event,
+                  &Registration
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the SPI I/O Protocol installation.", __func__));
+  } else {
+    DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installation was registered.", __func__));
+  }
+
+  return Status;
+}
+
+/**
+  Entry point of the Macronix SPI NOR Flash driver.
+
+  @param ImageHandle  Image handle of this driver.
+  @param SystemTable  Pointer to standard EFI system table.
+
+  @retval EFI_SUCCESS           Succeed.
+  @retval EFI_NOT_FOUND         No gEdk2JedecSfdpSpiSmmDriverGuid installed on
+                                system yet.
+  @retval EFI_OUT_OF_RESOURCES  Not enough resource for SPI NOR Flash JEDEC SFDP
+                                initialization.
+  @retval Otherwise             Other errors.
+**/
+EFI_STATUS
+EFIAPI
+SpiNorFlashJedecSfdpDxeEntry (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  *InstanceBuffer;
+  UINTN       InstanceIndex;
+  UINTN       InstanceBufferSize;
+
+  DEBUG ((DEBUG_INFO, "%a - ENTRY\n", __func__));
+
+  //
+  // Register notification for the later SPI I/O protocol installation.
+  //
+  RegisterSpioProtocolNotification ();
+  DEBUG ((DEBUG_INFO, "Check if there were already some gEdk2JedecSfdpSpiDxeDriverGuid handles installed.\n"));
+
+  //
+  // Check if there were already some gEdk2JedecSfdpSpiDxeDriverGuid
+  // handles installed.
+  //
+  // Locate the SPI I/O Protocol for the SPI flash part
+  // that supports JEDEC SFDP specification.
+  //
+  InstanceBufferSize = 0;
+  InstanceBuffer     = NULL;
+  Status             = gBS->LocateHandle (
+                              ByProtocol,
+                              &gEdk2JedecSfdpSpiDxeDriverGuid,
+                              NULL,
+                              &InstanceBufferSize,
+                              InstanceBuffer
+                              );
+  if (Status == EFI_NOT_FOUND) {
+    DEBUG ((
+      DEBUG_INFO,
+      "No gEdk2JedecSfdpSpiSmmDriverGuid handles found at the moment, wait for the notification of SPI I/O protocol installation.\n"
+      ));
+    DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+    return EFI_SUCCESS;
+  } else if (Status == EFI_BUFFER_TOO_SMALL) {
+    InstanceBuffer = (EFI_HANDLE *)AllocateZeroPool (InstanceBufferSize);
+    ASSERT (InstanceBuffer != NULL);
+    if (InstanceBuffer == NULL) {
+      DEBUG ((DEBUG_ERROR, "Not enough resource for gEdk2JedecSfdpSpiDxeDriverGuid handles.\n"));
+      DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Error to locate gEdk2JedecSfdpSpiDxeDriverGuid - Status = %r.\n", Status));
+    DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+    return Status;
+  }
+
+  Status = gBS->LocateHandle (
+                  ByProtocol,
+                  &gEdk2JedecSfdpSpiDxeDriverGuid,
+                  NULL,
+                  &InstanceBufferSize,
+                  InstanceBuffer
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Fail to locate all gEdk2JedecSfdpSpiDxeDriverGuid handles.\n"));
+    DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+    return Status;
+  }
+
+  DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiDxeDriverGuid are found.\n", InstanceBufferSize / sizeof (EFI_HANDLE)));
+  for (InstanceIndex = 0; InstanceIndex < InstanceBufferSize / sizeof (EFI_HANDLE); InstanceIndex++) {
+    Status = CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + InstanceIndex));
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Fail to create SPI NOR Flash SFDP instance #%d.\n", InstanceIndex));
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+  return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c
new file mode 100644
index 00000000000..18b69dcfb16
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c
@@ -0,0 +1,234 @@
+/** @file
+  SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+  SMM driver.
+
+  Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+  @par Revision Reference:
+    - JEDEC Standard, JESD216F.02
+      https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+
+  @par Glossary:
+    - SFDP - Serial Flash Discoverable Parameters
+    - PTP  - Parameter Table Pointer
+**/
+#include <Base.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Protocol/SpiSmmConfiguration.h>
+#include <Protocol/SpiSmmNorFlash.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiNorFlash.h"
+#include "SpiNorFlashJedecSfdpInternal.h"
+
+/**
+  Function to create SPI_NOR_FLASH_INSTANCE for this SPI part.
+
+  @param[in] SpiIoHandle  The handle with SPI I/O protocol installed.
+
+  @retval EFI_SUCCESS           Succeed.
+  @retval EFI_OUT_OF_RESOURCES  Not enough resource to create SPI_NOR_FLASH_INSTANCE.
+  @retval otherwise             Fail to create SPI NOR Flash SFDP Instance
+**/
+EFI_STATUS
+CreateSpiNorFlashSfdpInstance (
+  IN EFI_HANDLE  SpiIoHandle
+  )
+{
+  EFI_STATUS              Status;
+  SPI_NOR_FLASH_INSTANCE  *Instance;
+
+  // Allocate SPI_NOR_FLASH_INSTANCE Instance.
+  Instance = AllocateZeroPool (sizeof (SPI_NOR_FLASH_INSTANCE));
+  ASSERT (Instance != NULL);
+  if (Instance == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  // Locate the SPI IO Protocol.
+  Status = gSmst->SmmHandleProtocol (
+                    SpiIoHandle,
+                    &gEdk2JedecSfdpSpiSmmDriverGuid,
+                    (VOID **)&Instance->SpiIo
+                    );
+  ASSERT_EFI_ERROR (Status);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to locate SPI I/O protocol.\n", __func__));
+    FreePool (Instance);
+  } else {
+    Status = InitialSpiNorFlashSfdpInstance (Instance);
+    ASSERT_EFI_ERROR (Status);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "%a: Fail to initial SPI_NOR_FLASH_INSTANCE.\n", __func__));
+      FreePool (Instance);
+    } else {
+      // Install SPI NOR Flash Protocol.
+      Status = gSmst->SmmInstallProtocolInterface (
+                        &Instance->Handle,
+                        &gEfiSpiSmmNorFlashProtocolGuid,
+                        EFI_NATIVE_INTERFACE,
+                        &Instance->Protocol
+                        );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Fail to Install gEfiSpiSmmNorFlashProtocolGuid protocol.\n", __func__));
+        FreePool (Instance);
+      }
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Callback function executed when the EFI_SPI_IO_PROTOCOL
+  protocol interface is installed.
+
+  @param[in] Protocol   Points to the protocol's unique identifier.
+  @param[in] Interface  Points to the interface instance.
+  @param[in] Handle     The handle on which the interface was installed.
+
+  @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SpiIoProtocolInstalledCallback (
+  IN CONST EFI_GUID  *Protocol,
+  IN VOID            *Interface,
+  IN EFI_HANDLE      Handle
+  )
+{
+  EFI_STATUS  Status;
+
+  DEBUG ((DEBUG_INFO, "%a: Entry.\n", __func__));
+  Status = CreateSpiNorFlashSfdpInstance (Handle);
+  return Status;
+}
+
+/**
+  Register notification for the later installed SPI I/O protocol.
+
+  @retval EFI_SUCCESS          Succeed.
+  @retval otherwise            Fail to register the notification of
+                               SPI I/O protocol installation.
+
+**/
+EFI_STATUS
+RegisterSpioProtocolNotification (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+  VOID        *Registration;
+
+  Status = gSmst->SmmRegisterProtocolNotify (
+                    &gEdk2JedecSfdpSpiSmmDriverGuid,
+                    SpiIoProtocolInstalledCallback,
+                    &Registration
+                    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the SPI I/O Protocol installation.", __func__));
+  } else {
+    DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installation was registered.", __func__));
+  }
+
+  return Status;
+}
+
+/**
+  Entry point of the SPI NOR Flash SFDP SMM driver.
+
+  @param ImageHandle  Image handle of this driver.
+  @param SystemTable  Pointer to standard EFI system table.
+
+  @retval EFI_SUCCESS           Succeed.
+  @retval EFI_NOT_FOUND         No gEdk2JedecSfdpSpiSmmDriverGuid installed on
+                                system yet.
+  @retval EFI_OUT_OF_RESOURCES  Not enough resource for SPI NOR Flash JEDEC SFDP
+                                initialization.
+  @retval Otherwise             Other errors.
+**/
+EFI_STATUS
+EFIAPI
+SpiNorFlashJedecSfdpSmmEntry (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+  EFI_HANDLE  *InstanceBuffer;
+  UINTN       InstanceIndex;
+  UINTN       InstanceBufferSize;
+
+  DEBUG ((DEBUG_INFO, "%a - ENTRY.\n", __func__));
+
+  //
+  // Register notification for the later SPI I/O protocol installation.
+  //
+  RegisterSpioProtocolNotification ();
+  DEBUG ((DEBUG_INFO, "Check if there were already some gEdk2JedecSfdpSpiSmmDriverGuid handles installed.\n"));
+  //
+  // Check if there were already some gEdk2JedecSfdpSpiSmmDriverGuid
+  // handles installed.
+  //
+  // Locate the SPI I/O Protocol for the SPI flash part
+  // that supports JEDEC SFDP specification.
+  //
+  InstanceBufferSize = 0;
+  InstanceBuffer     = NULL;
+  Status             = gSmst->SmmLocateHandle (
+                                ByProtocol,
+                                &gEdk2JedecSfdpSpiSmmDriverGuid,
+                                NULL,
+                                &InstanceBufferSize,
+                                InstanceBuffer
+                                );
+  if (Status == EFI_NOT_FOUND) {
+    DEBUG ((
+      DEBUG_INFO,
+      "No gEdk2JedecSfdpSpiSmmDriverGuid handles found at the moment, wait for the notification of SPI I/O protocol installation.\n"
+      ));
+    DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+    return EFI_SUCCESS;
+  } else if (Status == EFI_BUFFER_TOO_SMALL) {
+    InstanceBuffer = (EFI_HANDLE *)AllocateZeroPool (InstanceBufferSize);
+    ASSERT (InstanceBuffer != NULL);
+    if (InstanceBuffer == NULL) {
+      DEBUG ((DEBUG_ERROR, "Not enough resource for gEdk2JedecSfdpSpiSmmDriverGuid handles.\n"));
+      DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Error to locate gEdk2JedecSfdpSpiSmmDriverGuid - Status = %r.\n", Status));
+    DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+    return Status;
+  }
+
+  Status = gSmst->SmmLocateHandle (
+                    ByProtocol,
+                    &gEdk2JedecSfdpSpiSmmDriverGuid,
+                    NULL,
+                    &InstanceBufferSize,
+                    InstanceBuffer
+                    );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Fail to locate all gEdk2JedecSfdpSpiSmmDriverGuid handles.\n"));
+    DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+    return Status;
+  }
+
+  DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiSmmDriverGuid handles are found.\n", InstanceBufferSize / sizeof (EFI_HANDLE)));
+  for (InstanceIndex = 0; InstanceIndex < InstanceBufferSize / sizeof (EFI_HANDLE); InstanceIndex++) {
+    Status = CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + InstanceIndex));
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Fail to create SPI NOR Flash SFDP instance #%d.\n", InstanceIndex));
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+  return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni
new file mode 100644
index 00000000000..4e091f6850d
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni
@@ -0,0 +1,13 @@
+// /** @file
+// SPI NOR Flash SFDP Localized Strings and Content.
+//
+// Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "EDK2 SPI NOR FLASH SFDP DXE driver"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver provides SPI NOR FLASH Serial Flash Discoverable Parameter (SFDP) compatible flash device capability discovery."
+
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni
new file mode 100644
index 00000000000..0efea67b9e4
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni
@@ -0,0 +1,11 @@
+// /** @file
+// SPI NOR Flash SFDP Localized Strings and Content.
+//
+// Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US   "SPI NOR Flash driver for JEDEC Serial Flash Discoverable Parameters (SFDP) compliant SPI Flash Memory"
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni
new file mode 100644
index 00000000000..b487ec71a12
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni
@@ -0,0 +1,13 @@
+// /** @file
+// SPI NOR Flash SFDP Localized Strings and Content.
+//
+// Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT             #language en-US "EDK2 SPI NOR FLASH SFDP SMM driver"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver provides SPI NOR FLASH Serial Flash Discoverable Parameter (SFDP) compatible flash device capability discovery."
+
-- 
2.37.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#107423): https://edk2.groups.io/g/devel/message/107423
Mute This Topic: https://groups.io/mt/100478924/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list