public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device
@ 2024-04-04  9:24 Chang, Abner via groups.io
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 1/6] MdePkg/Include: Update definitions of SPI related header files Chang, Abner via groups.io
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Chang, Abner via groups.io @ 2024-04-04  9:24 UTC (permalink / raw)
  To: devel
  Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Abdul Lateef Attar,
	Hao A Wu, Ray Ni, Jian J Wang, Brit Chesley

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

Sending V4 for review as SPI related ECR is approved by
PIWG in PI spec 1.8A

In V5: Correct patch 6/6, as some source files are fixed in this patch.
In RESEND V4: Add Cc in patch 6/6
In V4: Enhance timeout algorithm
In V3: Relocate GUIDs/PCDs for SPI SFDP drivers to
       MdeModulePkg.dec.
In V2: Add maintainer entry for Bus/Spi.

This patch fixes the missing SPI defintions per to PI spec
1.8 errata A.
This patch also provides the implemtation of SPI NOR flash
driver that supports JEDEC SFDP specification.
This driver support the flash device that has the GUID
gEdk2JedecSfdpSpiDxeDriverGuid or gEdk2JedecSfdpSpiSmmDriverGuid
declared in EFI_SPI_PERIPHERAL SpiPeripheralDriverGuid structure.

The driver has been verified with Macronix MX25U6435F flash device.

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Brit Chesley <brit.chesley@amd.com>

Abner Chang (2):
  MdeModulePkg: Add definitions in DEC for SPI NOR Flash SFDP driver
  Maintainers: AMD as SPI driver stack maintainer

abnchang (4):
  MdePkg/Include: Update definitions of SPI related header files
  MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file
  MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP
  MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC

 MdeModulePkg/MdeModulePkg.dec                 |   28 +-
 MdeModulePkg/MdeModulePkg.dsc                 |    4 +-
 .../SpiNorFlashJedecSfdpDxe.inf               |   64 +
 .../SpiNorFlashJedecSfdpSmm.inf               |   64 +
 .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h    |  286 +++
 .../SpiNorFlashJedecSfdpInternal.h            |  299 +++
 .../IndustryStandard/SpiNorFlashJedecSfdp.h   |  324 +++
 MdePkg/Include/Protocol/SpiConfiguration.h    |   10 +-
 MdePkg/Include/Protocol/SpiHc.h               |   16 +-
 MdePkg/Include/Protocol/SpiIo.h               |   12 +-
 .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c    | 1141 +++++++++++
 .../SpiNorFlashJedecSfdp.c                    | 1780 +++++++++++++++++
 .../SpiNorFlashJedecSfdpDxe.c                 |  261 +++
 .../SpiNorFlashJedecSfdpSmm.c                 |  234 +++
 Maintainers.txt                               |   11 +
 .../SpiNorFlashJedecSfdpDxe.uni               |   13 +
 .../SpiNorFlashJedecSfdpExtra.uni             |   11 +
 .../SpiNorFlashJedecSfdpSmm.uni               |   13 +
 18 files changed, 4566 insertions(+), 5 deletions(-)
 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 MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.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

-- 
2.37.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117413): https://edk2.groups.io/g/devel/message/117413
Mute This Topic: https://groups.io/mt/105325717/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [edk2-devel] [PATCH V5 1/6] MdePkg/Include: Update definitions of SPI related header files
  2024-04-04  9:24 [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
@ 2024-04-04  9:24 ` Chang, Abner via groups.io
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 2/6] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file Chang, Abner via groups.io
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Chang, Abner via groups.io @ 2024-04-04  9:24 UTC (permalink / raw)
  To: devel
  Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Abdul Lateef Attar,
	Brit Chesley

From: abnchang <abnchang@amd.com>

BZ#: 4471
Update definitions according to PI spec 1.8 errata A

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
Cc: Brit Chesley <brit.chesley@amd.com>
---
 MdePkg/Include/Protocol/SpiConfiguration.h | 10 +++++++++-
 MdePkg/Include/Protocol/SpiHc.h            | 16 +++++++++++++++-
 MdePkg/Include/Protocol/SpiIo.h            | 12 +++++++++++-
 3 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/MdePkg/Include/Protocol/SpiConfiguration.h b/MdePkg/Include/Protocol/SpiConfiguration.h
index 3f8fb9ff62c..120b54bbad8 100644
--- a/MdePkg/Include/Protocol/SpiConfiguration.h
+++ b/MdePkg/Include/Protocol/SpiConfiguration.h
@@ -2,10 +2,11 @@
   This file defines the SPI Configuration Protocol.
 
   Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
   @par Revision Reference:
-    This Protocol was introduced in UEFI PI Specification 1.6.
+    This Protocol was introduced in UEFI PI Specification 1.8 A.
 
 **/
 
@@ -168,6 +169,13 @@ typedef struct _EFI_SPI_BUS {
   VOID    *ClockParameter;
 } EFI_SPI_BUS;
 
+///
+/// Definitions of SPI Part Attributes.
+///
+#define SPI_PART_SUPPORTS_2_BIT_DATA_BUS_WIDTH  BIT0
+#define SPI_PART_SUPPORTS_4_B1T_DATA_BUS_WIDTH  BIT1
+#define SPI_PART_SUPPORTS_8_B1T_DATA_BUS_WIDTH  BIT2
+
 ///
 /// The EFI_SPI_PERIPHERAL data structure describes how a specific block of
 /// logic which is connected to the SPI bus. This data structure also selects
diff --git a/MdePkg/Include/Protocol/SpiHc.h b/MdePkg/Include/Protocol/SpiHc.h
index 30128dd5c4d..354de721606 100644
--- a/MdePkg/Include/Protocol/SpiHc.h
+++ b/MdePkg/Include/Protocol/SpiHc.h
@@ -2,10 +2,11 @@
   This file defines the SPI Host Controller Protocol.
 
   Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
   @par Revision Reference:
-    This Protocol was introduced in UEFI PI Specification 1.6.
+    This Protocol was introduced in UEFI PI Specification 1.8 A.
 
 **/
 
@@ -121,6 +122,19 @@ typedef EFI_STATUS
   IN EFI_SPI_BUS_TRANSACTION    *BusTransaction
   );
 
+///
+/// Definitions of SPI Host Controller Attributes.
+///
+#define HC_SUPPORTS_WRITE_ONLY_OPERATIONS       BIT0
+#define HC_SUPPORTS_READ_ONLY_OPERATIONS        BIT1
+#define HC_SUPPORTS_WRITE_THEN_READ_OPERATIONS  BIT2
+#define HC_TX_FRAME_IN_MOST_SIGNIFICANT_BITS    BIT3
+#define HC_RX_FRAME_IN_MOST_SIGNIFICANT_BITS    BIT4
+#define HC_SUPPORTS_2_BIT_DATA_BUS_WIDTH        BIT5
+#define HC_SUPPORTS_4_BIT_DATA_BUS_WIDTH        BIT6
+#define HC_SUPPORTS_8_BIT_DATA_BUS_WIDTH        BIT7
+#define HC_TRANSFER_SIZE_INCLUDES_OPCODE        BIT8
+#define HC_TRANSFER_SIZE_INCLUDES_ADDRESS       BIT9
 ///
 /// Support a SPI data transaction between the SPI controller and a SPI chip.
 ///
diff --git a/MdePkg/Include/Protocol/SpiIo.h b/MdePkg/Include/Protocol/SpiIo.h
index b4fc5e03b88..2c95a375a20 100644
--- a/MdePkg/Include/Protocol/SpiIo.h
+++ b/MdePkg/Include/Protocol/SpiIo.h
@@ -2,10 +2,11 @@
   This file defines the SPI I/O Protocol.
 
   Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+  Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
   @par Revision Reference:
-    This Protocol was introduced in UEFI PI Specification 1.6.
+    This Protocol was introduced in UEFI PI Specification 1.8 A.
 
 **/
 
@@ -223,6 +224,15 @@ typedef struct _EFI_SPI_BUS_TRANSACTION {
   UINT8                       *ReadBuffer;
 } EFI_SPI_BUS_TRANSACTION;
 
+///
+/// Definitions of SPI I/O Attributes.
+///
+#define SPI_IO_SUPPORTS_2_BIT_DATA_BUS_WIDTH   BIT0
+#define SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH   BIT1
+#define SPI_IO_SUPPORTS_8_BIT_DATA_BUS_WIDTH   BIT2
+#define SPI_IO_TRANSFER_SIZE_INCLUDES_OPCODE   BIT3
+#define SPI_IO_TRANSFER_SIZE_INCLUDES_ADDRESS  BIT4
+
 ///
 /// Support managed SPI data transactions between the SPI controller and a SPI
 /// chip.
-- 
2.37.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117414): https://edk2.groups.io/g/devel/message/117414
Mute This Topic: https://groups.io/mt/105325718/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [edk2-devel] [PATCH V5 2/6] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file
  2024-04-04  9:24 [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 1/6] MdePkg/Include: Update definitions of SPI related header files Chang, Abner via groups.io
@ 2024-04-04  9:24 ` Chang, Abner via groups.io
  2024-04-15  8:23   ` Abdul Lateef Attar via groups.io
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 3/6] MdeModulePkg: Add definitions in DEC for SPI NOR Flash SFDP driver Chang, Abner via groups.io
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Chang, Abner via groups.io @ 2024-04-04  9:24 UTC (permalink / raw)
  To: devel
  Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Abdul Lateef Attar,
	Brit Chesley

From: abnchang <abnchang@amd.com>

BZ#: 4472
Add definition of JEDEC Serial Flash Discoverable Parameters
(SFDP) specification.
https://www.jedec.org/standards-documents/docs/jesd216b

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
Cc: Brit Chesley <brit.chesley@amd.com>
---
 .../IndustryStandard/SpiNorFlashJedecSfdp.h   | 324 ++++++++++++++++++
 1 file changed, 324 insertions(+)
 create mode 100644 MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h

diff --git a/MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h b/MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
new file mode 100644
index 00000000000..2577a1289be
--- /dev/null
+++ b/MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
@@ -0,0 +1,324 @@
+/** @file
+  SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+  header file.
+
+  Copyright (C) 2024 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
+**/
+
+#ifndef SPI_NOR_FLASH_JEDEC_H_
+#define SPI_NOR_FLASH_JEDEC_H_
+
+#include <Base.h>
+
+#define SFDP_HEADER_SIGNATURE          0x50444653
+#define SFDP_SUPPORTED_MAJOR_REVISION  0x1ul
+
+/// JEDEC Basic Flash Parameter Header
+#define SFDP_BASIC_PARAMETER_ID_LSB  0x00
+#define SFDP_BASIC_PARAMETER_ID_MSB  0xFF
+
+///
+/// JDEC Sector Map Parameter Header and Table
+///
+#define SFDP_SECTOR_MAP_PARAMETER_ID_LSB        0x81
+#define SFDP_FOUR_BYTE_ADDRESS_INSTRUCTION_LSB  0x84
+#define SFDP_SECTOR_MAP_PARAMETER_ID_MSB        0xFF
+
+#define SFDP_FLASH_MEMORY_DENSITY_4GBIT  0x80000000
+
+#pragma pack (1)
+typedef struct _SFDP_HEADER {
+  UINT32    Signature;
+  UINT32    MinorRev            : 8;
+  UINT32    MajorRev            : 8;
+  UINT32    NumParameterHeaders : 8;
+  UINT32    AccessProtocol      : 8;
+} SFDP_HEADER;
+
+typedef struct _SFDP_PARAMETER_HEADER {
+  UINT32    IdLsb        : 8;
+  UINT32    MinorRev     : 8;
+  UINT32    MajorRev     : 8;
+  UINT32    Length       : 8;
+  UINT32    TablePointer : 24;
+  UINT32    IdMsb        : 8;
+} SFDP_PARAMETER_HEADER;
+
+typedef struct _SFDP_BASIC_FLASH_PARAMETER {
+  // DWORD 1
+  UINT32    EraseSizes                 : 2;
+  UINT32    WriteGranularity           : 1;
+  UINT32    VolatileStatusBlockProtect : 1;
+  UINT32    WriteEnableVolatileStatus  : 1;
+  UINT32    Unused1Dw1                 : 3;
+  UINT32    FourKEraseInstr            : 8;
+  UINT32    FastRead112                : 1;
+  UINT32    AddressBytes               : 2;
+  UINT32    DtrClocking                : 1;
+  UINT32    FastRead122                : 1;
+  UINT32    FastRead144                : 1;
+  UINT32    FastRead114                : 1;
+  UINT32    Unused2Dw1                 : 9;
+  // DWORD 2
+  UINT32    Density;
+  // DWORD 3
+  // Fast Read 144
+  UINT32    FastRead144Dummy           : 5;
+  UINT32    FastRead144ModeClk         : 3;
+  UINT32    FastRead144Instr           : 8;
+  // Fast Read 114
+  UINT32    FastRead114Dummy           : 5;
+  UINT32    FastRead114ModeClk         : 3;
+  UINT32    FastRead114Instr           : 8;
+  // DWORD 4
+  // Fast Read 112
+  UINT32    FastRead112Dummy           : 5;
+  UINT32    FastRead112ModeClk         : 3;
+  UINT32    FastRead112Instr           : 8;
+  // Fast Read 122
+  UINT32    FastRead122Dummy           : 5;
+  UINT32    FastRead122ModeClk         : 3;
+  UINT32    FastRead122Instr           : 8;
+  // DWORD 5
+  UINT32    FastRead222                : 1;
+  UINT32    Unused1Dw5                 : 3;
+  UINT32    FastRead444                : 1;
+  UINT32    Unused2Dw5                 : 27;
+  // DWORD 6
+  UINT32    UnusedDw6                  : 16;
+  // Fast Read 222
+  UINT32    FastRead222Dummy           : 5;
+  UINT32    FastRead222ModeClk         : 3;
+  UINT32    FastRead222Instr           : 8;
+  // DWORD 7
+  UINT32    UnusedDw7                  : 16;
+  // Fast Read 444
+  UINT32    FastRead444Dummy           : 5;
+  UINT32    FastRead444ModeClk         : 3;
+  UINT32    FastRead444Instr           : 8;
+  // DWORD 8
+  UINT32    Erase1Size                 : 8;
+  UINT32    Erase1Instr                : 8;
+  UINT32    Erase2Size                 : 8;
+  UINT32    Erase2Instr                : 8;
+  // DWORD 9
+  UINT32    Erase3Size                 : 8;
+  UINT32    Erase3Instr                : 8;
+  UINT32    Erase4Size                 : 8;
+  UINT32    Erase4Instr                : 8;
+  // DWORD 10
+  UINT32    EraseMultiplier            : 4;
+  UINT32    Erase1Time                 : 7;
+  UINT32    Erase2Time                 : 7;
+  UINT32    Erase3Time                 : 7;
+  UINT32    Erase4Time                 : 7;
+  // DWORD 11
+  UINT32    ProgramMultiplier          : 4;
+  UINT32    PageSize                   : 4;
+  UINT32    PPTime                     : 6;
+  UINT32    BPFirstTime                : 5;
+  UINT32    BPAdditionalTime           : 5;
+  UINT32    ChipEraseTime              : 7;
+  UINT32    Unused1Dw11                : 1;
+  // DWORD 12
+  UINT32    ProgSuspendProhibit        : 4;
+  UINT32    EraseSuspendProhibit       : 4;
+  UINT32    Unused1Dw13                : 1;
+  UINT32    ProgResumeToSuspend        : 4;
+  UINT32    ProgSuspendInProgressTime  : 7;
+  UINT32    EraseResumeToSuspend       : 4;
+  UINT32    EraseSuspendInProgressTime : 7;
+  UINT32    SuspendResumeSupported     : 1;
+  // DWORD 13
+  UINT32    Unused13;
+  // DWORD 14
+  UINT32    Unused14;
+  // DWORD 15
+  UINT32    Unused15;
+  // DWORD 16
+  UINT32    Unused16;
+  // DWORD 17
+  UINT32    FastRead188Dummy   : 5;
+  UINT32    FastRead188ModeClk : 3;
+  UINT32    FastRead188Instr   : 8;
+  UINT32    FastRead118Dummy   : 5;
+  UINT32    FastRead118ModeClk : 3;
+  UINT32    FastRead118Instr   : 8;
+  //
+  // Don't care about remaining DWORDs
+  // DWORD 18 to DWORD 23
+  //
+  UINT32    Unused18;
+  UINT32    Unused19;
+  UINT32    Unused20;
+  UINT32    Unused21;
+  UINT32    Unused22;
+  UINT32    Unused23;
+} SFDP_BASIC_FLASH_PARAMETER;
+#pragma pack ()
+
+#define SPI_UNIFORM_4K_ERASE_SUPPORTED    0x01
+#define SPI_UNIFORM_4K_ERASE_UNSUPPORTED  0x03
+
+///
+/// Number of address bytes opcode can support
+///
+#define SPI_ADDR_3BYTE_ONLY  0x00
+#define SPI_ADDR_3OR4BYTE    0x01
+#define SPI_ADDR_4BYTE_ONLY  0x02
+
+#define SFDP_ERASE_TYPES_NUMBER  4
+#define SFDP_ERASE_TYPE_1        0x0001
+#define SFDP_ERASE_TYPE_2        0x0002
+#define SFDP_ERASE_TYPE_3        0x0003
+#define SFDP_ERASE_TYPE_4        0x0004
+
+///
+///  Read/Write Array Commands
+///
+#define SPI_FLASH_READ                    0x03
+#define   SPI_FLASH_READ_DUMMY            0x00
+#define   SPI_FLASH_READ_ADDR_BYTES       SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_FAST_READ               0x0B
+#define   SPI_FLASH_FAST_READ_DUMMY       0x01
+#define   SPI_FLASH_FAST_READ_ADDR_BYTES  SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_PP                      0x02
+#define   SPI_FLASH_PP_DUMMY              0x00
+#define   SPI_FLASH_PP_ADDR_BYTES         SPI_ADDR_3OR4BYTE
+#define   SPI_FLASH_PAGE_SIZE             256
+#define SPI_FLASH_SE                      0x20
+#define   SPI_FLASH_SE_DUMMY              0x00
+#define   SPI_FLASH_SE_ADDR_BYTES         SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_BE32K                   0x52
+#define   SPI_FLASH_BE32K_DUMMY           0x00
+#define   SPI_FLASH_BE32K_ADDR_BYTES      SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_BE                      0xD8
+#define   SPI_FLASH_BE_DUMMY              0x00
+#define   SPI_FLASH_BE_ADDR_BYTES         SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_CE                      0x60
+#define   SPI_FLASH_CE_DUMMY              0x00
+#define   SPI_FLASH_CE_ADDR_BYTES         SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_RDID                    0x9F
+#define   SPI_FLASH_RDID_DUMMY            0x00
+#define   SPI_FLASH_RDID_ADDR_BYTES       SPI_ADDR_3OR4BYTE
+
+///
+/// Register Setting Commands
+///
+#define SPI_FLASH_WREN                              0x06
+#define   SPI_FLASH_WREN_DUMMY                      0x00
+#define   SPI_FLASH_WREN_ADDR_BYTES                 SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_WRDI                              0x04
+#define   SPI_FLASH_WRDI_DUMMY                      0x00
+#define   SPI_FLASH_WRDI_ADDR_BYTES                 SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_RDSR                              0x05
+#define   SPI_FLASH_RDSR_DUMMY                      0x00
+#define   SPI_FLASH_RDSR_ADDR_BYTES                 SPI_ADDR_3OR4BYTE
+#define   SPI_FLASH_SR_NOT_WIP                      0x0
+#define   SPI_FLASH_SR_WIP                          BIT0
+#define   SPI_FLASH_SR_WEL                          BIT1
+#define SPI_FLASH_WRSR                              0x01
+#define   SPI_FLASH_WRSR_DUMMY                      0x00
+#define   SPI_FLASH_WRSR_ADDR_BYTES                 SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_WREN_50H                          0x50
+#define SPI_FLASH_RDSFDP                            0x5A
+#define   SPI_FLASH_RDSFDP_DUMMY                    0x01
+#define   SPI_FLASH_RDSFDP_ADDR_BYTES               SPI_ADDR_3BYTE_ONLY
+#define   ERASE_TYPICAL_TIME_UNITS_MASK             0x60
+#define   ERASE_TYPICAL_TIME_BIT_POSITION           5
+#define     ERASE_TYPICAL_TIME_UNIT_1_MS_BITMAP     0x00
+#define     ERASE_TYPICAL_TIME_UNIT_1_MS            1
+#define     ERASE_TYPICAL_TIME_UNIT_16_MS_BITMAP    0x01
+#define     ERASE_TYPICAL_TIME_UNIT_16_MS           16
+#define     ERASE_TYPICAL_TIME_UNIT_128_MS_BITMAP   0x02
+#define     ERASE_TYPICAL_TIME_UNIT_128_MS          128
+#define     ERASE_TYPICAL_TIME_UNIT_1000_MS_BITMAP  0x03
+#define     ERASE_TYPICAL_TIME_UNIT_1000_MS         1000
+#define   ERASE_TYPICAL_TIME_COUNT_MASK             0x1f
+
+///
+/// Flash Device Configuration Detection Command descriptor.
+///
+typedef struct {
+  // DWORD 1
+  UINT32    DescriptorEnd              : 1; ///< Descriptor Sequence End Indicator.
+  UINT32    DescriptorType             : 1; ///< Descriptor Type.
+  UINT32    Reserve1                   : 6; ///< Bit [7:2] is reserved.
+  UINT32    DetectionInstruction       : 8; ///< Sector map configuration detection command.
+  UINT32    DetectionLatency           : 4; ///< Configuration detection command read latency.
+  UINT32    Reserve2                   : 2; ///< Bit [21:20] is reserved.
+  UINT32    DetectionCommandAddressLen : 2; ///< Configuration detection command address length.
+  UINT32    ReadDataMask               : 8; ///< Bit mask of the interst bit of the returned
+                                            ///< byte read from the detection command.
+  // DWORD 2
+  UINT32    CommandAddress             : 32; ///< Sector map configuration detection command address.
+} SFDP_SECTOR_CONFIGURATION_COMMAND;
+
+#define SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_COMMAND  0
+#define SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_MAP      1
+#define SFDP_SECTOR_MAP_TABLE_ENTRY_LAST          1
+
+///
+/// Definition of Configuration detection command address length.
+///
+typedef enum {
+  SpdfConfigurationCommandAddressNone     = 0,
+  SpdfConfigurationCommandAddress3Byte    = 1,
+  SpdfConfigurationCommandAddress4Byte    = 2,
+  SpdfConfigurationCommandAddressVariable = 3
+} SPDF_CONFIGURATION_COMMAND_ADDR_LENGTH;
+
+///
+/// Flash Device Configuration Map descriptor.
+///
+typedef struct {
+  // DWORD 1
+  UINT32    DescriptorEnd   : 1;          ///< Descriptor Sequence End Indicator.
+  UINT32    DescriptorType  : 1;          ///< Descriptor Type.
+  UINT32    Reserve1        : 6;          ///< Bit [7:2] is reserved.
+  UINT32    ConfigurationID : 8;          ///< ID of this configuration.
+  UINT32    RegionCount     : 8;          ///< The region count of this configuration.
+  UINT32    Reserve2        : 8;          ///< [31:24] is reserved.
+} SFDP_SECTOR_CONFIGURATION_MAP;
+
+typedef struct {
+  UINT32    DescriptorEnd  : 1;           ///< Descriptor Sequence End Indicator.
+  UINT32    DescriptorType : 1;           ///< Descriptor Type.
+} SFDP_SECTOR_CONFIGURATION_GENERIC_HEADER;
+
+///
+/// Flash Device Region Definition.
+///
+typedef struct _SFDP_SECTOR_REGION {
+  // DWORD 1
+  UINT32    EraseType1 : 1;               ///< Earse type 1 is supported.
+  UINT32    EraseType2 : 1;               ///< Earse type 2 is supported.
+  UINT32    EraseType3 : 1;               ///< Earse type 3 is supported.
+  UINT32    EraseType4 : 1;               ///< Earse type 4 is supported.
+  UINT32    Reserve1   : 4;               ///< Bit [7:4] is reserved.
+  UINT32    RegionSize : 24;              ///< Region size in 256 Byte unit.
+} SFDP_SECTOR_REGION;
+#define SFDP_SECTOR_REGION_SIZE_UNIT  256
+
+///
+/// Sector Map Table structure, the entry could be
+/// either Configuration Detection Command descriptor,
+/// or Configuration Map descriptor.
+///
+typedef union _SFDP_SECTOR_MAP_TABLE {
+  SFDP_SECTOR_CONFIGURATION_GENERIC_HEADER    GenericHeader;
+  SFDP_SECTOR_CONFIGURATION_COMMAND           ConfigurationCommand; ///< Fash configuration detection command.
+  SFDP_SECTOR_CONFIGURATION_MAP               ConfigurationMap;     ///< Flash map descriptor.
+} SFDP_SECTOR_MAP_TABLE;
+
+#endif // SPI_NOR_FLASH_JEDEC_H_
-- 
2.37.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117415): https://edk2.groups.io/g/devel/message/117415
Mute This Topic: https://groups.io/mt/105325719/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [edk2-devel] [PATCH V5 3/6] MdeModulePkg: Add definitions in DEC for SPI NOR Flash SFDP driver
  2024-04-04  9:24 [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 1/6] MdePkg/Include: Update definitions of SPI related header files Chang, Abner via groups.io
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 2/6] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file Chang, Abner via groups.io
@ 2024-04-04  9:24 ` Chang, Abner via groups.io
  2024-04-15 13:51   ` Abdul Lateef Attar via groups.io
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Chang, Abner via groups.io
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: Chang, Abner via groups.io @ 2024-04-04  9:24 UTC (permalink / raw)
  To: devel; +Cc: Liming Gao, Jian J Wang, Abdul Lateef Attar

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

BZ#: 4473

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
---
 MdeModulePkg/MdeModulePkg.dec | 28 +++++++++++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index a82dedc070d..050871cdf6b 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -9,7 +9,7 @@
 # (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP<BR>
 # Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
 # Copyright (c) Microsoft Corporation.<BR>
-# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 ##
@@ -454,6 +454,12 @@
   ## GUID used for Boot Discovery Policy FormSet guid and related variables.
   gBootDiscoveryPolicyMgrFormsetGuid = { 0x5b6f7107, 0xbb3c, 0x4660, { 0x92, 0xcd, 0x54, 0x26, 0x90, 0x28, 0x0b, 0xbd } }
 
+  #
+  # SPI NOR flash JEDEC Serial Flash Discoverable Parameters (SFDP) driver GUID
+  #
+  gEdk2JedecSfdpSpiDxeDriverGuid  = { 0xBE71701E, 0xB63C, 0x4574, { 0x9C, 0x5C, 0x36, 0x29, 0xE8, 0xEA, 0xC4, 0x14 }}
+  gEdk2JedecSfdpSpiSmmDriverGuid  = { 0x95A1E915, 0x195C, 0x477C, { 0x92, 0x6F, 0x7E, 0x24, 0x67, 0xC1, 0xB3, 0x1F }}
+
 [Ppis]
   ## Include/Ppi/FirmwareVolumeShadowPpi.h
   gEdkiiPeiFirmwareVolumeShadowPpiGuid = { 0x7dfe756c, 0xed8d, 0x4d77, {0x9e, 0xc4, 0x39, 0x9a, 0x8a, 0x81, 0x51, 0x16 } }
@@ -1638,6 +1644,26 @@
   # @Prompt The value of Retry Count,  Default value is 5.
   gEfiMdeModulePkgTokenSpaceGuid.PcdAhciCommandRetryCount|5|UINT32|0x00000032
 
+  ## SPI NOR Flash operation retry counts
+  #  0x00000000:  No retry
+  #  0xFFFFFFFF:  Maximum retry value
+  #
+  # @Prompt SPI NOR Flash Operation Retry Value
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount|0x00000003|UINT32|0x00000033
+
+  ## SPI NOR Flash operation retry counts for the fixed timeout value
+  #  0x00000000:  No retry
+  #  0xFFFFFFFF:  Maximum retry value
+  #
+  # @Prompt SPI NOR Flash Operation Retry Value for the Fixed Timeout Value
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount|0x0000FFFF|UINT32|0x00000034
+
+  ## SPI NOR Flash operation delay in microseconds
+  #  Deafult is set to 0x00000010 microseconds
+  #
+  # @Prompt SPI NOR Flash Operation Delay in Microseconds (16 us)
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds|0x00000010|UINT32|0x00000035
+
 [PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
   ## This PCD defines the Console output row. The default value is 25 according to UEFI spec.
   #  This PCD could be set to 0 then console output would be at max column and max row.
-- 
2.37.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117416): https://edk2.groups.io/g/devel/message/117416
Mute This Topic: https://groups.io/mt/105325720/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP
  2024-04-04  9:24 [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
                   ` (2 preceding siblings ...)
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 3/6] MdeModulePkg: Add definitions in DEC for SPI NOR Flash SFDP driver Chang, Abner via groups.io
@ 2024-04-04  9:24 ` Chang, Abner via groups.io
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 5/6] MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC Chang, Abner via groups.io
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Chang, Abner via groups.io @ 2024-04-04  9:24 UTC (permalink / raw)
  To: devel; +Cc: Hao A Wu, Ray Ni, Abdul Lateef Attar, Brit Chesley

From: abnchang <abnchang@amd.com>

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

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
Cc: Brit Chesley <brit.chesley@amd.com>
---
 .../SpiNorFlashJedecSfdpDxe.inf               |   64 +
 .../SpiNorFlashJedecSfdpSmm.inf               |   64 +
 .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h    |  286 +++
 .../SpiNorFlashJedecSfdpInternal.h            |  299 +++
 .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c    | 1141 +++++++++++
 .../SpiNorFlashJedecSfdp.c                    | 1780 +++++++++++++++++
 .../SpiNorFlashJedecSfdpDxe.c                 |  261 +++
 .../SpiNorFlashJedecSfdpSmm.c                 |  234 +++
 .../SpiNorFlashJedecSfdpDxe.uni               |   13 +
 .../SpiNorFlashJedecSfdpExtra.uni             |   11 +
 .../SpiNorFlashJedecSfdpSmm.uni               |   13 +
 11 files changed, 4166 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..26dbff3c8da
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
@@ -0,0 +1,64 @@
+## @file
+#  The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+#  DXE driver INF file.
+#
+#  Copyright (C) 2024 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]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount
+  gEfiMdeModulePkgTokenSpaceGuid.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..89aceb0684d
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
@@ -0,0 +1,64 @@
+## @file
+#  The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+#  SMM driver INF file.
+#
+#  Copyright (C) 2024 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]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount
+  gEfiMdeModulePkgTokenSpaceGuid.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..fb71e8d56f4
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h
@@ -0,0 +1,286 @@
+/** @file
+  Definitions of SPI NOR flash operation functions.
+
+  Copyright (C) 2024 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.
+  @param[in]  Timeout     Timeout in microsecond
+  @param[in]  RetryCount  The retry count
+
+  @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,
+  IN      UINT32                  Timeout,
+  IN      UINT32                  RetryCount
+  );
+
+/**
+  Check for write enable latch set and not device write in progress
+
+  @param[in]  Instance    SPI NOR instance with all protocols, etc.
+  @param[in]  Timeout     Timeout in microsecond
+  @param[in]  RetryCount  The retry count
+
+  @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,
+  IN      UINT32                  Timeout,
+  IN      UINT32                  RetryCount
+  );
+
+/**
+  Check for not write enable latch set and not device write in progress
+
+  @param[in]  Instance    SPI NOR instance with all protocols, etc.
+  @param[in]  Timeout     Timeout in microsecond
+  @param[in]  RetryCount  The retry count
+
+  @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,
+  IN      UINT32                  Timeout,
+  IN      UINT32                  RetryCount
+  );
+
+/**
+  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..309d8dcea70
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h
@@ -0,0 +1,299 @@
+/** @file
+  SPI NOR flash driver internal definitions.
+
+  Copyright (C) 2024 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.
+  @param[out]     TypicalTime           Pointer to receive the typical time in millisecond
+                                        to erase this erase type size.
+  @param[out]     MaximumTimeout        Pointer to receive the maximum timeout in millisecond
+                                        to erase this erase type size.
+  @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,
+  OUT    UINT32                     *TypicalTime,
+  OUT    UINT64                     *MaximumTimeout
+  );
+
+/**
+  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..3ac5420fbf6
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c
@@ -0,0 +1,1141 @@
+/** @file
+  SPI NOR Flash operation functions.
+
+  Copyright (C) 2024 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]    Instance               The instance of SPI_NOR_FLASH
+  @param[in]    Opcode                 Opcode for transaction
+  @param[in]    DummyBytes             The dummy bytes send to SPI flash device
+  @param[in]    AddressBytesSupported  Bytes of address supported by SPI flash device
+  @param[in]    UseAddress             Send the address for SPI flash command
+  @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) {
+    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]  SpiNorFlashInstance  SPI NOR instance with all protocols, etc.
+  @param[in]  Timeout              Timeout in microsecond
+  @param[in]  RetryCount           The retry count
+
+  @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,
+  IN      UINT32                  Timeout,
+  IN      UINT32                  RetryCount
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       DeviceStatus;
+  UINT32      AlreadyDelayedInMicroseconds;
+
+  if (Timeout == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if (RetryCount == 0) {
+    RetryCount = 1;
+  }
+
+  do {
+    AlreadyDelayedInMicroseconds = 0;
+    while (AlreadyDelayedInMicroseconds < Timeout) {
+      Status = InternalReadStatus (SpiNorFlashInstance, 1, &DeviceStatus);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Read status error\n", __func__));
+        ASSERT (FALSE);
+        return Status;
+      }
+
+      if ((DeviceStatus & SPI_FLASH_SR_WIP) == SPI_FLASH_SR_NOT_WIP) {
+        return Status;
+      }
+
+      MicroSecondDelay (FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds));
+      AlreadyDelayedInMicroseconds += FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds);
+    }
+
+    RetryCount--;
+  } while (RetryCount > 0);
+
+  DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__));
+  return EFI_DEVICE_ERROR;
+}
+
+/**
+  Check for write enable latch set and not device write in progress.
+
+  @param[in]  SpiNorFlashInstance  SPI NOR instance with all protocols, etc.
+  @param[in]  Timeout              Timeout in microsecond
+  @param[in]  RetryCount           The retry count
+
+  @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,
+  IN      UINT32                  Timeout,
+  IN      UINT32                  RetryCount
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       DeviceStatus;
+  UINT32      AlreadyDelayedInMicroseconds;
+
+  if (Timeout == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if (RetryCount == 0) {
+    RetryCount = 1;
+  }
+
+  do {
+    AlreadyDelayedInMicroseconds = 0;
+    while (AlreadyDelayedInMicroseconds < Timeout) {
+      Status = InternalReadStatus (SpiNorFlashInstance, 1, &DeviceStatus);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "%a: Fail to read WEL.\n", __func__));
+        ASSERT_EFI_ERROR (Status);
+        return Status;
+      }
+
+      if ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL)) == SPI_FLASH_SR_WEL) {
+        return Status;
+      }
+
+      MicroSecondDelay (FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds));
+      AlreadyDelayedInMicroseconds += FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds);
+    }
+
+    RetryCount--;
+  } while (RetryCount > 0);
+
+  DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__));
+  return EFI_DEVICE_ERROR;
+}
+
+/**
+  Check for not write enable latch set and not device write in progress.
+
+  @param[in]  SpiNorFlashInstance  SPI NOR instance with all protocols, etc.
+  @param[in]  Timeout              Timeout in microsecond
+  @param[in]  RetryCount           The retry count
+
+  @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,
+  IN      UINT32                  Timeout,
+  IN      UINT32                  RetryCount
+  )
+{
+  EFI_STATUS  Status;
+  UINT8       DeviceStatus;
+  UINT32      AlreadyDelayedInMicroseconds;
+
+  if (Timeout == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if (RetryCount == 0) {
+    RetryCount = 1;
+  }
+
+  do {
+    AlreadyDelayedInMicroseconds = 0;
+    while (AlreadyDelayedInMicroseconds < Timeout) {
+      Status = InternalReadStatus (SpiNorFlashInstance, 1, &DeviceStatus);
+      ASSERT_EFI_ERROR (Status);
+      if (EFI_ERROR (Status) ||
+          ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL)) == SPI_FLASH_SR_NOT_WIP))
+      {
+        return Status;
+      }
+
+      MicroSecondDelay (FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds));
+      AlreadyDelayedInMicroseconds += FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds);
+    }
+
+    RetryCount--;
+  } while (RetryCount > 0);
+
+  DEBUG ((DEBUG_ERROR, "SpiNorFlash:%a: Timeout error\n", __func__));
+  return EFI_DEVICE_ERROR;
+}
+
+/**
+  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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+
+  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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+    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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+    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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+
+  // 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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+    }
+
+    // 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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+    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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+      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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+    } else {
+      Status = WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+      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;
+  UINT32                     TypicalEraseTime;
+  UINT64                     MaximumEraseTimeout;
+  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,
+                 &TypicalEraseTime,
+                 &MaximumEraseTimeout
+                 );
+      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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+    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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+      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
+      // Use the timeout value calculated by SPI NOR flash SFDP.
+      //
+      Status = WaitNotWelNotWip (Instance, (UINT32)MaximumEraseTimeout * 1000, FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount));
+      if (EFI_ERROR (Status)) {
+        break;
+      }
+    } else {
+      //
+      // Use the timeout value calculated by SPI NOR flash SFDP.
+      //
+      Status = WaitNotWip (Instance, (UINT32)MaximumEraseTimeout * 1000, FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount));
+      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..284567d1f4b
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c
@@ -0,0 +1,1780 @@
+/** @file
+  SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+  common functions.
+
+  Copyright (C) 2024 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.
+
+**/
+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.
+  @param[out]     TypicalTime           Pointer to receive the typical time in millisecond
+                                        to erase this erase type size.
+  @param[out]     MaximumTimeout        Pointer to receive the maximum timeout in millisecond
+                                        to erase this erase type size.
+
+  @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,
+  OUT    UINT32                     *TypicalTime,
+  OUT    UINT64                     *MaximumTimeout
+  )
+{
+  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;
+        *TypicalTime       = EraseType->EraseTypicalTime;
+        *MaximumTimeout    = EraseType->EraseTimeout;
+        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));
+  DEBUG ((DEBUG_VERBOSE, "    - Erase typical time: %d milliseconds.\n", *TypicalTime));
+  DEBUG ((DEBUG_VERBOSE, "    - Erase timeout: %d milliseconds.\n", *MaximumTimeout));
+  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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+
+    // 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.
+
+  @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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+
+  // 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"));
+        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]  SfdpParameterHeader  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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+    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, FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount));
+
+    //  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..d8b86ddd8a3
--- /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) 2024 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"));
+    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..c9fe44704fd
--- /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) 2024 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..130e958cdba
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni
@@ -0,0 +1,13 @@
+// /** @file
+// SPI NOR Flash SFDP Localized Strings and Content.
+//
+// Copyright (C) 2024 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..4703cf8b230
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni
@@ -0,0 +1,11 @@
+// /** @file
+// SPI NOR Flash SFDP Localized Strings and Content.
+//
+// Copyright (C) 2024 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..757da3ddbd6
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni
@@ -0,0 +1,13 @@
+// /** @file
+// SPI NOR Flash SFDP Localized Strings and Content.
+//
+// Copyright (C) 2024 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 (#117419): https://edk2.groups.io/g/devel/message/117419
Mute This Topic: https://groups.io/mt/105325725/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [edk2-devel] [PATCH V5 5/6] MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC
  2024-04-04  9:24 [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
                   ` (3 preceding siblings ...)
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Chang, Abner via groups.io
@ 2024-04-04  9:24 ` Chang, Abner via groups.io
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 6/6] Maintainers: AMD as SPI driver stack maintainer Chang, Abner via groups.io
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: Chang, Abner via groups.io @ 2024-04-04  9:24 UTC (permalink / raw)
  To: devel; +Cc: Jian J Wang, Liming Gao, Abdul Lateef Attar, Brit Chesley

From: abnchang <abnchang@amd.com>

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

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Abdul Lateef Attar <abdattar@amd.com>
Cc: Brit Chesley <brit.chesley@amd.com>
---
 MdeModulePkg/MdeModulePkg.dsc | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index c0f1df3bfbc..6bed9205ea6 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -4,7 +4,7 @@
 # (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
 # Copyright (c) 2007 - 2021, Intel Corporation. All rights reserved.<BR>
 # Copyright (c) Microsoft Corporation.
-# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
 #
 #    SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -285,6 +285,8 @@
   MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf
   MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf
   MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
+  MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
+  MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
 
   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
   MdeModulePkg/Core/Pei/PeiMain.inf
-- 
2.37.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117417): https://edk2.groups.io/g/devel/message/117417
Mute This Topic: https://groups.io/mt/105325722/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [edk2-devel] [PATCH V5 6/6] Maintainers: AMD as SPI driver stack maintainer
  2024-04-04  9:24 [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
                   ` (4 preceding siblings ...)
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 5/6] MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC Chang, Abner via groups.io
@ 2024-04-04  9:24 ` Chang, Abner via groups.io
  2024-04-09  6:09 ` 回复: [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device gaoliming via groups.io
       [not found] ` <17C30980DC7A7234.4513@groups.io>
  7 siblings, 0 replies; 11+ messages in thread
From: Chang, Abner via groups.io @ 2024-04-04  9:24 UTC (permalink / raw)
  To: devel; +Cc: Andrew Fish, Leif Lindholm, Michael D Kinney

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

Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Andrew Fish <afish@apple.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
---
 Maintainers.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Maintainers.txt b/Maintainers.txt
index 799f27f914c..7d9cdca611f 100644
--- a/Maintainers.txt
+++ b/Maintainers.txt
@@ -417,6 +417,11 @@ M: Abner Chang <abner.chang@amd.com> [changab]
 R: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> [abdattar]
 R: Nickle Wang <nicklew@nvidia.com> [nicklela]
 
+MdeModulePkg: SPI driver stack
+F: MdeModulePkg/Bus/Spi/
+M: Abner Chang <abner.chang@amd.com> [changab]
+R: Brit Chesley <brit.chesley@amd.com> [BritChesley]
+
 MdePkg
 F: MdePkg/
 W: https://github.com/tianocore/tianocore.github.io/wiki/MdePkg
@@ -450,6 +455,12 @@ M: Abner Chang <abner.chang@amd.com> [changab]
 R: Abdul Lateef Attar <AbdulLateef.Attar@amd.com> [abdattar]
 R: Nickle Wang <nicklew@nvidia.com> [nicklela]
 
+MdePkg: SPI related C header files
+F: MdePkg/Include/Protocol/Spi*.h
+F: MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
+M: Abner Chang <abner.chang@amd.com> [changab]
+R: Brit Chesley <brit.chesley@amd.com> [BritChesley]
+
 NetworkPkg
 F: NetworkPkg/
 W: https://github.com/tianocore/tianocore.github.io/wiki/NetworkPkg
-- 
2.37.1.windows.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117418): https://edk2.groups.io/g/devel/message/117418
Mute This Topic: https://groups.io/mt/105325724/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* 回复: [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device
  2024-04-04  9:24 [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
                   ` (5 preceding siblings ...)
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 6/6] Maintainers: AMD as SPI driver stack maintainer Chang, Abner via groups.io
@ 2024-04-09  6:09 ` gaoliming via groups.io
       [not found] ` <17C30980DC7A7234.4513@groups.io>
  7 siblings, 0 replies; 11+ messages in thread
From: gaoliming via groups.io @ 2024-04-09  6:09 UTC (permalink / raw)
  To: devel, abner.chang
  Cc: 'Michael D Kinney', 'Zhiguang Liu',
	'Abdul Lateef Attar', 'Hao A Wu',
	'Ray Ni', 'Jian J Wang', 'Brit Chesley'

Abner:
  The change is good to me. Reviewed-by: Liming Gao
<gaoliming@byosoft.com.cn>

Thanks
Liming
> -----邮件原件-----
> 发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Chang, Abner
> via groups.io
> 发送时间: 2024年4月4日 17:25
> 收件人: devel@edk2.groups.io
> 抄送: Michael D Kinney <michael.d.kinney@intel.com>; Liming Gao
> <gaoliming@byosoft.com.cn>; Zhiguang Liu <zhiguang.liu@intel.com>; Abdul
> Lateef Attar <abdattar@amd.com>; Hao A Wu <hao.a.wu@intel.com>; Ray Ni
> <ray.ni@intel.com>; Jian J Wang <jian.j.wang@intel.com>; Brit Chesley
> <brit.chesley@amd.com>
> 主题: [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash
device
> 
> From: Abner Chang <abner.chang@amd.com>
> 
> Sending V4 for review as SPI related ECR is approved by
> PIWG in PI spec 1.8A
> 
> In V5: Correct patch 6/6, as some source files are fixed in this patch.
> In RESEND V4: Add Cc in patch 6/6
> In V4: Enhance timeout algorithm
> In V3: Relocate GUIDs/PCDs for SPI SFDP drivers to
>        MdeModulePkg.dec.
> In V2: Add maintainer entry for Bus/Spi.
> 
> This patch fixes the missing SPI defintions per to PI spec
> 1.8 errata A.
> This patch also provides the implemtation of SPI NOR flash
> driver that supports JEDEC SFDP specification.
> This driver support the flash device that has the GUID
> gEdk2JedecSfdpSpiDxeDriverGuid or gEdk2JedecSfdpSpiSmmDriverGuid
> declared in EFI_SPI_PERIPHERAL SpiPeripheralDriverGuid structure.
> 
> The driver has been verified with Macronix MX25U6435F flash device.
> 
> Signed-off-by: Abner Chang <abner.chang@amd.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Abdul Lateef Attar <abdattar@amd.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Brit Chesley <brit.chesley@amd.com>
> 
> Abner Chang (2):
>   MdeModulePkg: Add definitions in DEC for SPI NOR Flash SFDP driver
>   Maintainers: AMD as SPI driver stack maintainer
> 
> abnchang (4):
>   MdePkg/Include: Update definitions of SPI related header files
>   MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file
>   MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP
>   MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC
> 
>  MdeModulePkg/MdeModulePkg.dec                 |   28 +-
>  MdeModulePkg/MdeModulePkg.dsc                 |    4 +-
>  .../SpiNorFlashJedecSfdpDxe.inf               |   64 +
>  .../SpiNorFlashJedecSfdpSmm.inf               |   64 +
>  .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h    |  286 +++
>  .../SpiNorFlashJedecSfdpInternal.h            |  299 +++
>  .../IndustryStandard/SpiNorFlashJedecSfdp.h   |  324 +++
>  MdePkg/Include/Protocol/SpiConfiguration.h    |   10 +-
>  MdePkg/Include/Protocol/SpiHc.h               |   16 +-
>  MdePkg/Include/Protocol/SpiIo.h               |   12 +-
>  .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c    | 1141 +++++++++++
>  .../SpiNorFlashJedecSfdp.c                    | 1780
> +++++++++++++++++
>  .../SpiNorFlashJedecSfdpDxe.c                 |  261 +++
>  .../SpiNorFlashJedecSfdpSmm.c                 |  234 +++
>  Maintainers.txt                               |   11 +
>  .../SpiNorFlashJedecSfdpDxe.uni               |   13 +
>  .../SpiNorFlashJedecSfdpExtra.uni             |   11 +
>  .../SpiNorFlashJedecSfdpSmm.uni               |   13 +
>  18 files changed, 4566 insertions(+), 5 deletions(-)
>  create mode 100644
> MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
>  create mode 100644
> MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.in
> f
>  create mode 100644
> MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h
>  create mode 100644
> MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal
> .h
>  create mode 100644
> MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.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.u
> ni
>  create mode 100644
> MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.u
> ni
> 
> --
> 2.37.1.windows.1
> 
> 
> 
> 
> 





-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117531): https://edk2.groups.io/g/devel/message/117531
Mute This Topic: https://groups.io/mt/105417086/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP
       [not found] ` <17C30980DC7A7234.4513@groups.io>
@ 2024-04-09  6:45   ` Chang, Abner via groups.io
  0 siblings, 0 replies; 11+ messages in thread
From: Chang, Abner via groups.io @ 2024-04-09  6:45 UTC (permalink / raw)
  To: devel@edk2.groups.io
  Cc: Hao A Wu, Ray Ni, Attar, AbdulLateef (Abdul Lateef),
	Chesley, Brit

[AMD Official Use Only - General]

Hi Ray and Hao,
This patch proposes a Spi folder under MdeModulePkg/Bus, AMD will also upstream entire SPI BUS driver stack after this patch set got merged and maintain the related drivers. Are you agree with this update?

Thank you
Abner

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of Chang,
> Abner via groups.io
> Sent: Thursday, April 4, 2024 5:25 PM
> To: devel@edk2.groups.io
> Cc: Hao A Wu <hao.a.wu@intel.com>; Ray Ni <ray.ni@intel.com>; Attar,
> AbdulLateef (Abdul Lateef) <AbdulLateef.Attar@amd.com>; Chesley, Brit
> <Brit.Chesley@amd.com>
> Subject: [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI
> NOR Flash JEDEC SFDP
>
> Caution: This message originated from an External Source. Use proper caution
> when opening attachments, clicking links, or responding.
>
>
> From: abnchang <abnchang@amd.com>
>
> BZ#: 4471
> SPI NOR Flash JEDEC Serial Flash Discoverable Driver
> implementation.
>
> Signed-off-by: Abner Chang <abner.chang@amd.com>
> Cc: Hao A Wu <hao.a.wu@intel.com>
> Cc: Ray Ni <ray.ni@intel.com>
> Cc: Abdul Lateef Attar <abdattar@amd.com>
> Cc: Brit Chesley <brit.chesley@amd.com>
> ---
>  .../SpiNorFlashJedecSfdpDxe.inf               |   64 +
>  .../SpiNorFlashJedecSfdpSmm.inf               |   64 +
>  .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h    |  286 +++
>  .../SpiNorFlashJedecSfdpInternal.h            |  299 +++
>  .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c    | 1141 +++++++++++
>  .../SpiNorFlashJedecSfdp.c                    | 1780 +++++++++++++++++
>  .../SpiNorFlashJedecSfdpDxe.c                 |  261 +++
>  .../SpiNorFlashJedecSfdpSmm.c                 |  234 +++
>  .../SpiNorFlashJedecSfdpDxe.uni               |   13 +
>  .../SpiNorFlashJedecSfdpExtra.uni             |   11 +
>  .../SpiNorFlashJedecSfdpSmm.uni               |   13 +
>  11 files changed, 4166 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..26dbff3c8da
> --- /dev/null
> +++
> b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
> @@ -0,0 +1,64 @@
> +## @file
> +#  The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
> +#  DXE driver INF file.
> +#
> +#  Copyright (C) 2024 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]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicrosecond
> s
> +
> +[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..89aceb0684d
> --- /dev/null
> +++
> b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
> @@ -0,0 +1,64 @@
> +## @file
> +#  The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
> +#  SMM driver INF file.
> +#
> +#  Copyright (C) 2024 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]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicrosecond
> s
> +
> +[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..fb71e8d56f4
> --- /dev/null
> +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h
> @@ -0,0 +1,286 @@
> +/** @file
> +  Definitions of SPI NOR flash operation functions.
> +
> +  Copyright (C) 2024 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.
> +  @param[in]  Timeout     Timeout in microsecond
> +  @param[in]  RetryCount  The retry count
> +
> +  @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,
> +  IN      UINT32                  Timeout,
> +  IN      UINT32                  RetryCount
> +  );
> +
> +/**
> +  Check for write enable latch set and not device write in progress
> +
> +  @param[in]  Instance    SPI NOR instance with all protocols, etc.
> +  @param[in]  Timeout     Timeout in microsecond
> +  @param[in]  RetryCount  The retry count
> +
> +  @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,
> +  IN      UINT32                  Timeout,
> +  IN      UINT32                  RetryCount
> +  );
> +
> +/**
> +  Check for not write enable latch set and not device write in progress
> +
> +  @param[in]  Instance    SPI NOR instance with all protocols, etc.
> +  @param[in]  Timeout     Timeout in microsecond
> +  @param[in]  RetryCount  The retry count
> +
> +  @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,
> +  IN      UINT32                  Timeout,
> +  IN      UINT32                  RetryCount
> +  );
> +
> +/**
> +  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..309d8dcea70
> --- /dev/null
> +++
> b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.
> h
> @@ -0,0 +1,299 @@
> +/** @file
> +  SPI NOR flash driver internal definitions.
> +
> +  Copyright (C) 2024 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.
> +  @param[out]     TypicalTime           Pointer to receive the typical time in
> millisecond
> +                                        to erase this erase type size.
> +  @param[out]     MaximumTimeout        Pointer to receive the maximum
> timeout in millisecond
> +                                        to erase this erase type size.
> +  @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,
> +  OUT    UINT32                     *TypicalTime,
> +  OUT    UINT64                     *MaximumTimeout
> +  );
> +
> +/**
> +  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..3ac5420fbf6
> --- /dev/null
> +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c
> @@ -0,0 +1,1141 @@
> +/** @file
> +  SPI NOR Flash operation functions.
> +
> +  Copyright (C) 2024 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]    Instance               The instance of SPI_NOR_FLASH
> +  @param[in]    Opcode                 Opcode for transaction
> +  @param[in]    DummyBytes             The dummy bytes send to SPI flash device
> +  @param[in]    AddressBytesSupported  Bytes of address supported by SPI flash
> device
> +  @param[in]    UseAddress             Send the address for SPI flash command
> +  @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) {
> +    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]  SpiNorFlashInstance  SPI NOR instance with all protocols, etc.
> +  @param[in]  Timeout              Timeout in microsecond
> +  @param[in]  RetryCount           The retry count
> +
> +  @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,
> +  IN      UINT32                  Timeout,
> +  IN      UINT32                  RetryCount
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       DeviceStatus;
> +  UINT32      AlreadyDelayedInMicroseconds;
> +
> +  if (Timeout == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (RetryCount == 0) {
> +    RetryCount = 1;
> +  }
> +
> +  do {
> +    AlreadyDelayedInMicroseconds = 0;
> +    while (AlreadyDelayedInMicroseconds < Timeout) {
> +      Status = InternalReadStatus (SpiNorFlashInstance, 1, &DeviceStatus);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a: Read status error\n", __func__));
> +        ASSERT (FALSE);
> +        return Status;
> +      }
> +
> +      if ((DeviceStatus & SPI_FLASH_SR_WIP) == SPI_FLASH_SR_NOT_WIP) {
> +        return Status;
> +      }
> +
> +      MicroSecondDelay (FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds));
> +      AlreadyDelayedInMicroseconds += FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds);
> +    }
> +
> +    RetryCount--;
> +  } while (RetryCount > 0);
> +
> +  DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__));
> +  return EFI_DEVICE_ERROR;
> +}
> +
> +/**
> +  Check for write enable latch set and not device write in progress.
> +
> +  @param[in]  SpiNorFlashInstance  SPI NOR instance with all protocols, etc.
> +  @param[in]  Timeout              Timeout in microsecond
> +  @param[in]  RetryCount           The retry count
> +
> +  @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,
> +  IN      UINT32                  Timeout,
> +  IN      UINT32                  RetryCount
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       DeviceStatus;
> +  UINT32      AlreadyDelayedInMicroseconds;
> +
> +  if (Timeout == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (RetryCount == 0) {
> +    RetryCount = 1;
> +  }
> +
> +  do {
> +    AlreadyDelayedInMicroseconds = 0;
> +    while (AlreadyDelayedInMicroseconds < Timeout) {
> +      Status = InternalReadStatus (SpiNorFlashInstance, 1, &DeviceStatus);
> +      if (EFI_ERROR (Status)) {
> +        DEBUG ((DEBUG_ERROR, "%a: Fail to read WEL.\n", __func__));
> +        ASSERT_EFI_ERROR (Status);
> +        return Status;
> +      }
> +
> +      if ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL)) ==
> SPI_FLASH_SR_WEL) {
> +        return Status;
> +      }
> +
> +      MicroSecondDelay (FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds));
> +      AlreadyDelayedInMicroseconds += FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds);
> +    }
> +
> +    RetryCount--;
> +  } while (RetryCount > 0);
> +
> +  DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__));
> +  return EFI_DEVICE_ERROR;
> +}
> +
> +/**
> +  Check for not write enable latch set and not device write in progress.
> +
> +  @param[in]  SpiNorFlashInstance  SPI NOR instance with all protocols, etc.
> +  @param[in]  Timeout              Timeout in microsecond
> +  @param[in]  RetryCount           The retry count
> +
> +  @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,
> +  IN      UINT32                  Timeout,
> +  IN      UINT32                  RetryCount
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT8       DeviceStatus;
> +  UINT32      AlreadyDelayedInMicroseconds;
> +
> +  if (Timeout == 0) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (RetryCount == 0) {
> +    RetryCount = 1;
> +  }
> +
> +  do {
> +    AlreadyDelayedInMicroseconds = 0;
> +    while (AlreadyDelayedInMicroseconds < Timeout) {
> +      Status = InternalReadStatus (SpiNorFlashInstance, 1, &DeviceStatus);
> +      ASSERT_EFI_ERROR (Status);
> +      if (EFI_ERROR (Status) ||
> +          ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL)) ==
> SPI_FLASH_SR_NOT_WIP))
> +      {
> +        return Status;
> +      }
> +
> +      MicroSecondDelay (FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds));
> +      AlreadyDelayedInMicroseconds += FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds);
> +    }
> +
> +    RetryCount--;
> +  } while (RetryCount > 0);
> +
> +  DEBUG ((DEBUG_ERROR, "SpiNorFlash:%a: Timeout error\n", __func__));
> +  return EFI_DEVICE_ERROR;
> +}
> +
> +/**
> +  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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +
> +  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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +    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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +    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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +
> +  // 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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +    }
> +
> +    // 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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +    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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +      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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +      if (EFI_ERROR (Status)) {
> +        break;
> +      }
> +    } else {
> +      Status = WaitNotWip (Instance, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +      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;
> +  UINT32                     TypicalEraseTime;
> +  UINT64                     MaximumEraseTimeout;
> +  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,
> +                 &TypicalEraseTime,
> +                 &MaximumEraseTimeout
> +                 );
> +      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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +    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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +      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
> +      // Use the timeout value calculated by SPI NOR flash SFDP.
> +      //
> +      Status = WaitNotWelNotWip (Instance, (UINT32)MaximumEraseTimeout *
> 1000, FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount));
> +      if (EFI_ERROR (Status)) {
> +        break;
> +      }
> +    } else {
> +      //
> +      // Use the timeout value calculated by SPI NOR flash SFDP.
> +      //
> +      Status = WaitNotWip (Instance, (UINT32)MaximumEraseTimeout * 1000,
> FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount));
> +      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..284567d1f4b
> --- /dev/null
> +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c
> @@ -0,0 +1,1780 @@
> +/** @file
> +  SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
> +  common functions.
> +
> +  Copyright (C) 2024 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.
> +
> +**/
> +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.
> +  @param[out]     TypicalTime           Pointer to receive the typical time in
> millisecond
> +                                        to erase this erase type size.
> +  @param[out]     MaximumTimeout        Pointer to receive the maximum
> timeout in millisecond
> +                                        to erase this erase type size.
> +
> +  @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,
> +  OUT    UINT32                     *TypicalTime,
> +  OUT    UINT64                     *MaximumTimeout
> +  )
> +{
> +  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;
> +        *TypicalTime       = EraseType->EraseTypicalTime;
> +        *MaximumTimeout    = EraseType->EraseTimeout;
> +        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));
> +  DEBUG ((DEBUG_VERBOSE, "    - Erase typical time: %d milliseconds.\n",
> *TypicalTime));
> +  DEBUG ((DEBUG_VERBOSE, "    - Erase timeout: %d milliseconds.\n",
> *MaximumTimeout));
> +  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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +
> +    // 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.
> +
> +  @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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +
> +  // 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"));
> +        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]  SfdpParameterHeader  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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +    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, FixedPcdGet32
> (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32
> (PcdSpiNorFlashFixedTimeoutRetryCount));
> +
> +    //  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..d8b86ddd8a3
> --- /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) 2024 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"));
> +    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..c9fe44704fd
> --- /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) 2024 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..130e958cdba
> --- /dev/null
> +++
> b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni
> @@ -0,0 +1,13 @@
> +// /** @file
> +// SPI NOR Flash SFDP Localized Strings and Content.
> +//
> +// Copyright (C) 2024 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..4703cf8b230
> --- /dev/null
> +++
> b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni
> @@ -0,0 +1,11 @@
> +// /** @file
> +// SPI NOR Flash SFDP Localized Strings and Content.
> +//
> +// Copyright (C) 2024 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..757da3ddbd6
> --- /dev/null
> +++
> b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni
> @@ -0,0 +1,13 @@
> +// /** @file
> +// SPI NOR Flash SFDP Localized Strings and Content.
> +//
> +// Copyright (C) 2024 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 (#117542): https://edk2.groups.io/g/devel/message/117542
Mute This Topic: https://groups.io/mt/105417381/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [edk2-devel] [PATCH V5 2/6] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 2/6] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file Chang, Abner via groups.io
@ 2024-04-15  8:23   ` Abdul Lateef Attar via groups.io
  0 siblings, 0 replies; 11+ messages in thread
From: Abdul Lateef Attar via groups.io @ 2024-04-15  8:23 UTC (permalink / raw)
  To: abner.chang, devel
  Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Abdul Lateef Attar,
	Brit Chesley

Reviewed-by: Abdul Lateef Attar <abdattar@amd.com>

On 04-04-2024 14:54, abner.chang@amd.com wrote:
> From: abnchang <abnchang@amd.com>
>
> BZ#: 4472
> Add definition of JEDEC Serial Flash Discoverable Parameters
> (SFDP) specification.
> https://www.jedec.org/standards-documents/docs/jesd216b
>
> Signed-off-by: Abner Chang <abner.chang@amd.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Liming Gao <gaoliming@byosoft.com.cn>
> Cc: Zhiguang Liu <zhiguang.liu@intel.com>
> Cc: Abdul Lateef Attar <abdattar@amd.com>
> Cc: Brit Chesley <brit.chesley@amd.com>
> ---
>   .../IndustryStandard/SpiNorFlashJedecSfdp.h   | 324 ++++++++++++++++++
>   1 file changed, 324 insertions(+)
>   create mode 100644 MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
>
> diff --git a/MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h b/MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
> new file mode 100644
> index 00000000000..2577a1289be
> --- /dev/null
> +++ b/MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
> @@ -0,0 +1,324 @@
> +/** @file
> +  SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
> +  header file.
> +
> +  Copyright (C) 2024 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
> +**/
> +
> +#ifndef SPI_NOR_FLASH_JEDEC_H_
> +#define SPI_NOR_FLASH_JEDEC_H_
> +
> +#include <Base.h>
> +
> +#define SFDP_HEADER_SIGNATURE          0x50444653
> +#define SFDP_SUPPORTED_MAJOR_REVISION  0x1ul
> +
> +/// JEDEC Basic Flash Parameter Header
> +#define SFDP_BASIC_PARAMETER_ID_LSB  0x00
> +#define SFDP_BASIC_PARAMETER_ID_MSB  0xFF
> +
> +///
> +/// JDEC Sector Map Parameter Header and Table
> +///
> +#define SFDP_SECTOR_MAP_PARAMETER_ID_LSB        0x81
> +#define SFDP_FOUR_BYTE_ADDRESS_INSTRUCTION_LSB  0x84
> +#define SFDP_SECTOR_MAP_PARAMETER_ID_MSB        0xFF
> +
> +#define SFDP_FLASH_MEMORY_DENSITY_4GBIT  0x80000000
> +
> +#pragma pack (1)
> +typedef struct _SFDP_HEADER {
> +  UINT32    Signature;
> +  UINT32    MinorRev            : 8;
> +  UINT32    MajorRev            : 8;
> +  UINT32    NumParameterHeaders : 8;
> +  UINT32    AccessProtocol      : 8;
> +} SFDP_HEADER;
> +
> +typedef struct _SFDP_PARAMETER_HEADER {
> +  UINT32    IdLsb        : 8;
> +  UINT32    MinorRev     : 8;
> +  UINT32    MajorRev     : 8;
> +  UINT32    Length       : 8;
> +  UINT32    TablePointer : 24;
> +  UINT32    IdMsb        : 8;
> +} SFDP_PARAMETER_HEADER;
> +
> +typedef struct _SFDP_BASIC_FLASH_PARAMETER {
> +  // DWORD 1
> +  UINT32    EraseSizes                 : 2;
> +  UINT32    WriteGranularity           : 1;
> +  UINT32    VolatileStatusBlockProtect : 1;
> +  UINT32    WriteEnableVolatileStatus  : 1;
> +  UINT32    Unused1Dw1                 : 3;
> +  UINT32    FourKEraseInstr            : 8;
> +  UINT32    FastRead112                : 1;
> +  UINT32    AddressBytes               : 2;
> +  UINT32    DtrClocking                : 1;
> +  UINT32    FastRead122                : 1;
> +  UINT32    FastRead144                : 1;
> +  UINT32    FastRead114                : 1;
> +  UINT32    Unused2Dw1                 : 9;
> +  // DWORD 2
> +  UINT32    Density;
> +  // DWORD 3
> +  // Fast Read 144
> +  UINT32    FastRead144Dummy           : 5;
> +  UINT32    FastRead144ModeClk         : 3;
> +  UINT32    FastRead144Instr           : 8;
> +  // Fast Read 114
> +  UINT32    FastRead114Dummy           : 5;
> +  UINT32    FastRead114ModeClk         : 3;
> +  UINT32    FastRead114Instr           : 8;
> +  // DWORD 4
> +  // Fast Read 112
> +  UINT32    FastRead112Dummy           : 5;
> +  UINT32    FastRead112ModeClk         : 3;
> +  UINT32    FastRead112Instr           : 8;
> +  // Fast Read 122
> +  UINT32    FastRead122Dummy           : 5;
> +  UINT32    FastRead122ModeClk         : 3;
> +  UINT32    FastRead122Instr           : 8;
> +  // DWORD 5
> +  UINT32    FastRead222                : 1;
> +  UINT32    Unused1Dw5                 : 3;
> +  UINT32    FastRead444                : 1;
> +  UINT32    Unused2Dw5                 : 27;
> +  // DWORD 6
> +  UINT32    UnusedDw6                  : 16;
> +  // Fast Read 222
> +  UINT32    FastRead222Dummy           : 5;
> +  UINT32    FastRead222ModeClk         : 3;
> +  UINT32    FastRead222Instr           : 8;
> +  // DWORD 7
> +  UINT32    UnusedDw7                  : 16;
> +  // Fast Read 444
> +  UINT32    FastRead444Dummy           : 5;
> +  UINT32    FastRead444ModeClk         : 3;
> +  UINT32    FastRead444Instr           : 8;
> +  // DWORD 8
> +  UINT32    Erase1Size                 : 8;
> +  UINT32    Erase1Instr                : 8;
> +  UINT32    Erase2Size                 : 8;
> +  UINT32    Erase2Instr                : 8;
> +  // DWORD 9
> +  UINT32    Erase3Size                 : 8;
> +  UINT32    Erase3Instr                : 8;
> +  UINT32    Erase4Size                 : 8;
> +  UINT32    Erase4Instr                : 8;
> +  // DWORD 10
> +  UINT32    EraseMultiplier            : 4;
> +  UINT32    Erase1Time                 : 7;
> +  UINT32    Erase2Time                 : 7;
> +  UINT32    Erase3Time                 : 7;
> +  UINT32    Erase4Time                 : 7;
> +  // DWORD 11
> +  UINT32    ProgramMultiplier          : 4;
> +  UINT32    PageSize                   : 4;
> +  UINT32    PPTime                     : 6;
> +  UINT32    BPFirstTime                : 5;
> +  UINT32    BPAdditionalTime           : 5;
> +  UINT32    ChipEraseTime              : 7;
> +  UINT32    Unused1Dw11                : 1;
> +  // DWORD 12
> +  UINT32    ProgSuspendProhibit        : 4;
> +  UINT32    EraseSuspendProhibit       : 4;
> +  UINT32    Unused1Dw13                : 1;
> +  UINT32    ProgResumeToSuspend        : 4;
> +  UINT32    ProgSuspendInProgressTime  : 7;
> +  UINT32    EraseResumeToSuspend       : 4;
> +  UINT32    EraseSuspendInProgressTime : 7;
> +  UINT32    SuspendResumeSupported     : 1;
> +  // DWORD 13
> +  UINT32    Unused13;
> +  // DWORD 14
> +  UINT32    Unused14;
> +  // DWORD 15
> +  UINT32    Unused15;
> +  // DWORD 16
> +  UINT32    Unused16;
> +  // DWORD 17
> +  UINT32    FastRead188Dummy   : 5;
> +  UINT32    FastRead188ModeClk : 3;
> +  UINT32    FastRead188Instr   : 8;
> +  UINT32    FastRead118Dummy   : 5;
> +  UINT32    FastRead118ModeClk : 3;
> +  UINT32    FastRead118Instr   : 8;
> +  //
> +  // Don't care about remaining DWORDs
> +  // DWORD 18 to DWORD 23
> +  //
> +  UINT32    Unused18;
> +  UINT32    Unused19;
> +  UINT32    Unused20;
> +  UINT32    Unused21;
> +  UINT32    Unused22;
> +  UINT32    Unused23;
> +} SFDP_BASIC_FLASH_PARAMETER;
> +#pragma pack ()
> +
> +#define SPI_UNIFORM_4K_ERASE_SUPPORTED    0x01
> +#define SPI_UNIFORM_4K_ERASE_UNSUPPORTED  0x03
> +
> +///
> +/// Number of address bytes opcode can support
> +///
> +#define SPI_ADDR_3BYTE_ONLY  0x00
> +#define SPI_ADDR_3OR4BYTE    0x01
> +#define SPI_ADDR_4BYTE_ONLY  0x02
> +
> +#define SFDP_ERASE_TYPES_NUMBER  4
> +#define SFDP_ERASE_TYPE_1        0x0001
> +#define SFDP_ERASE_TYPE_2        0x0002
> +#define SFDP_ERASE_TYPE_3        0x0003
> +#define SFDP_ERASE_TYPE_4        0x0004
> +
> +///
> +///  Read/Write Array Commands
> +///
> +#define SPI_FLASH_READ                    0x03
> +#define   SPI_FLASH_READ_DUMMY            0x00
> +#define   SPI_FLASH_READ_ADDR_BYTES       SPI_ADDR_3OR4BYTE
> +#define SPI_FLASH_FAST_READ               0x0B
> +#define   SPI_FLASH_FAST_READ_DUMMY       0x01
> +#define   SPI_FLASH_FAST_READ_ADDR_BYTES  SPI_ADDR_3OR4BYTE
> +#define SPI_FLASH_PP                      0x02
> +#define   SPI_FLASH_PP_DUMMY              0x00
> +#define   SPI_FLASH_PP_ADDR_BYTES         SPI_ADDR_3OR4BYTE
> +#define   SPI_FLASH_PAGE_SIZE             256
> +#define SPI_FLASH_SE                      0x20
> +#define   SPI_FLASH_SE_DUMMY              0x00
> +#define   SPI_FLASH_SE_ADDR_BYTES         SPI_ADDR_3OR4BYTE
> +#define SPI_FLASH_BE32K                   0x52
> +#define   SPI_FLASH_BE32K_DUMMY           0x00
> +#define   SPI_FLASH_BE32K_ADDR_BYTES      SPI_ADDR_3OR4BYTE
> +#define SPI_FLASH_BE                      0xD8
> +#define   SPI_FLASH_BE_DUMMY              0x00
> +#define   SPI_FLASH_BE_ADDR_BYTES         SPI_ADDR_3OR4BYTE
> +#define SPI_FLASH_CE                      0x60
> +#define   SPI_FLASH_CE_DUMMY              0x00
> +#define   SPI_FLASH_CE_ADDR_BYTES         SPI_ADDR_3OR4BYTE
> +#define SPI_FLASH_RDID                    0x9F
> +#define   SPI_FLASH_RDID_DUMMY            0x00
> +#define   SPI_FLASH_RDID_ADDR_BYTES       SPI_ADDR_3OR4BYTE
> +
> +///
> +/// Register Setting Commands
> +///
> +#define SPI_FLASH_WREN                              0x06
> +#define   SPI_FLASH_WREN_DUMMY                      0x00
> +#define   SPI_FLASH_WREN_ADDR_BYTES                 SPI_ADDR_3OR4BYTE
> +#define SPI_FLASH_WRDI                              0x04
> +#define   SPI_FLASH_WRDI_DUMMY                      0x00
> +#define   SPI_FLASH_WRDI_ADDR_BYTES                 SPI_ADDR_3OR4BYTE
> +#define SPI_FLASH_RDSR                              0x05
> +#define   SPI_FLASH_RDSR_DUMMY                      0x00
> +#define   SPI_FLASH_RDSR_ADDR_BYTES                 SPI_ADDR_3OR4BYTE
> +#define   SPI_FLASH_SR_NOT_WIP                      0x0
> +#define   SPI_FLASH_SR_WIP                          BIT0
> +#define   SPI_FLASH_SR_WEL                          BIT1
> +#define SPI_FLASH_WRSR                              0x01
> +#define   SPI_FLASH_WRSR_DUMMY                      0x00
> +#define   SPI_FLASH_WRSR_ADDR_BYTES                 SPI_ADDR_3OR4BYTE
> +#define SPI_FLASH_WREN_50H                          0x50
> +#define SPI_FLASH_RDSFDP                            0x5A
> +#define   SPI_FLASH_RDSFDP_DUMMY                    0x01
> +#define   SPI_FLASH_RDSFDP_ADDR_BYTES               SPI_ADDR_3BYTE_ONLY
> +#define   ERASE_TYPICAL_TIME_UNITS_MASK             0x60
> +#define   ERASE_TYPICAL_TIME_BIT_POSITION           5
> +#define     ERASE_TYPICAL_TIME_UNIT_1_MS_BITMAP     0x00
> +#define     ERASE_TYPICAL_TIME_UNIT_1_MS            1
> +#define     ERASE_TYPICAL_TIME_UNIT_16_MS_BITMAP    0x01
> +#define     ERASE_TYPICAL_TIME_UNIT_16_MS           16
> +#define     ERASE_TYPICAL_TIME_UNIT_128_MS_BITMAP   0x02
> +#define     ERASE_TYPICAL_TIME_UNIT_128_MS          128
> +#define     ERASE_TYPICAL_TIME_UNIT_1000_MS_BITMAP  0x03
> +#define     ERASE_TYPICAL_TIME_UNIT_1000_MS         1000
> +#define   ERASE_TYPICAL_TIME_COUNT_MASK             0x1f
> +
> +///
> +/// Flash Device Configuration Detection Command descriptor.
> +///
> +typedef struct {
> +  // DWORD 1
> +  UINT32    DescriptorEnd              : 1; ///< Descriptor Sequence End Indicator.
> +  UINT32    DescriptorType             : 1; ///< Descriptor Type.
> +  UINT32    Reserve1                   : 6; ///< Bit [7:2] is reserved.
> +  UINT32    DetectionInstruction       : 8; ///< Sector map configuration detection command.
> +  UINT32    DetectionLatency           : 4; ///< Configuration detection command read latency.
> +  UINT32    Reserve2                   : 2; ///< Bit [21:20] is reserved.
> +  UINT32    DetectionCommandAddressLen : 2; ///< Configuration detection command address length.
> +  UINT32    ReadDataMask               : 8; ///< Bit mask of the interst bit of the returned
> +                                            ///< byte read from the detection command.
> +  // DWORD 2
> +  UINT32    CommandAddress             : 32; ///< Sector map configuration detection command address.
> +} SFDP_SECTOR_CONFIGURATION_COMMAND;
> +
> +#define SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_COMMAND  0
> +#define SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_MAP      1
> +#define SFDP_SECTOR_MAP_TABLE_ENTRY_LAST          1
> +
> +///
> +/// Definition of Configuration detection command address length.
> +///
> +typedef enum {
> +  SpdfConfigurationCommandAddressNone     = 0,
> +  SpdfConfigurationCommandAddress3Byte    = 1,
> +  SpdfConfigurationCommandAddress4Byte    = 2,
> +  SpdfConfigurationCommandAddressVariable = 3
> +} SPDF_CONFIGURATION_COMMAND_ADDR_LENGTH;
> +
> +///
> +/// Flash Device Configuration Map descriptor.
> +///
> +typedef struct {
> +  // DWORD 1
> +  UINT32    DescriptorEnd   : 1;          ///< Descriptor Sequence End Indicator.
> +  UINT32    DescriptorType  : 1;          ///< Descriptor Type.
> +  UINT32    Reserve1        : 6;          ///< Bit [7:2] is reserved.
> +  UINT32    ConfigurationID : 8;          ///< ID of this configuration.
> +  UINT32    RegionCount     : 8;          ///< The region count of this configuration.
> +  UINT32    Reserve2        : 8;          ///< [31:24] is reserved.
> +} SFDP_SECTOR_CONFIGURATION_MAP;
> +
> +typedef struct {
> +  UINT32    DescriptorEnd  : 1;           ///< Descriptor Sequence End Indicator.
> +  UINT32    DescriptorType : 1;           ///< Descriptor Type.
> +} SFDP_SECTOR_CONFIGURATION_GENERIC_HEADER;
> +
> +///
> +/// Flash Device Region Definition.
> +///
> +typedef struct _SFDP_SECTOR_REGION {
> +  // DWORD 1
> +  UINT32    EraseType1 : 1;               ///< Earse type 1 is supported.
> +  UINT32    EraseType2 : 1;               ///< Earse type 2 is supported.
> +  UINT32    EraseType3 : 1;               ///< Earse type 3 is supported.
> +  UINT32    EraseType4 : 1;               ///< Earse type 4 is supported.
> +  UINT32    Reserve1   : 4;               ///< Bit [7:4] is reserved.
> +  UINT32    RegionSize : 24;              ///< Region size in 256 Byte unit.
> +} SFDP_SECTOR_REGION;
> +#define SFDP_SECTOR_REGION_SIZE_UNIT  256
> +
> +///
> +/// Sector Map Table structure, the entry could be
> +/// either Configuration Detection Command descriptor,
> +/// or Configuration Map descriptor.
> +///
> +typedef union _SFDP_SECTOR_MAP_TABLE {
> +  SFDP_SECTOR_CONFIGURATION_GENERIC_HEADER    GenericHeader;
> +  SFDP_SECTOR_CONFIGURATION_COMMAND           ConfigurationCommand; ///< Fash configuration detection command.
> +  SFDP_SECTOR_CONFIGURATION_MAP               ConfigurationMap;     ///< Flash map descriptor.
> +} SFDP_SECTOR_MAP_TABLE;
> +
> +#endif // SPI_NOR_FLASH_JEDEC_H_


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117770): https://edk2.groups.io/g/devel/message/117770
Mute This Topic: https://groups.io/mt/105325719/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [edk2-devel] [PATCH V5 3/6] MdeModulePkg: Add definitions in DEC for SPI NOR Flash SFDP driver
  2024-04-04  9:24 ` [edk2-devel] [PATCH V5 3/6] MdeModulePkg: Add definitions in DEC for SPI NOR Flash SFDP driver Chang, Abner via groups.io
@ 2024-04-15 13:51   ` Abdul Lateef Attar via groups.io
  0 siblings, 0 replies; 11+ messages in thread
From: Abdul Lateef Attar via groups.io @ 2024-04-15 13:51 UTC (permalink / raw)
  To: abner.chang, devel; +Cc: Liming Gao, Jian J Wang, Abdul Lateef Attar

[-- Attachment #1: Type: text/plain, Size: 3608 bytes --]

Reviewed-by: Abdul Lateef Attar <abdattar@amd.com>

On 04-04-2024 14:54, abner.chang@amd.com wrote:
> From: Abner Chang<abner.chang@amd.com>
>
> BZ#: 4473
>
> Signed-off-by: Abner Chang<abner.chang@amd.com>
> Cc: Liming Gao<gaoliming@byosoft.com.cn>
> Cc: Jian J Wang<jian.j.wang@intel.com>
> Cc: Abdul Lateef Attar<abdattar@amd.com>
> ---
>   MdeModulePkg/MdeModulePkg.dec | 28 +++++++++++++++++++++++++++-
>   1 file changed, 27 insertions(+), 1 deletion(-)
>
> diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
> index a82dedc070d..050871cdf6b 100644
> --- a/MdeModulePkg/MdeModulePkg.dec
> +++ b/MdeModulePkg/MdeModulePkg.dec
> @@ -9,7 +9,7 @@
>   # (C) Copyright 2016 - 2019 Hewlett Packard Enterprise Development LP<BR>
>   # Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>
>   # Copyright (c) Microsoft Corporation.<BR>
> -# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR>
> +# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
>   # SPDX-License-Identifier: BSD-2-Clause-Patent
>   #
>   ##
> @@ -454,6 +454,12 @@
>     ## GUID used for Boot Discovery Policy FormSet guid and related variables.
>     gBootDiscoveryPolicyMgrFormsetGuid = { 0x5b6f7107, 0xbb3c, 0x4660, { 0x92, 0xcd, 0x54, 0x26, 0x90, 0x28, 0x0b, 0xbd } }
>   
> +  #
> +  # SPI NOR flash JEDEC Serial Flash Discoverable Parameters (SFDP) driver GUID
> +  #
> +  gEdk2JedecSfdpSpiDxeDriverGuid  = { 0xBE71701E, 0xB63C, 0x4574, { 0x9C, 0x5C, 0x36, 0x29, 0xE8, 0xEA, 0xC4, 0x14 }}
> +  gEdk2JedecSfdpSpiSmmDriverGuid  = { 0x95A1E915, 0x195C, 0x477C, { 0x92, 0x6F, 0x7E, 0x24, 0x67, 0xC1, 0xB3, 0x1F }}
> +
>   [Ppis]
>     ## Include/Ppi/FirmwareVolumeShadowPpi.h
>     gEdkiiPeiFirmwareVolumeShadowPpiGuid = { 0x7dfe756c, 0xed8d, 0x4d77, {0x9e, 0xc4, 0x39, 0x9a, 0x8a, 0x81, 0x51, 0x16 } }
> @@ -1638,6 +1644,26 @@
>     # @Prompt The value of Retry Count,  Default value is 5.
>     gEfiMdeModulePkgTokenSpaceGuid.PcdAhciCommandRetryCount|5|UINT32|0x00000032
>   
> +  ## SPI NOR Flash operation retry counts
> +  #  0x00000000:  No retry
> +  #  0xFFFFFFFF:  Maximum retry value
> +  #
> +  # @Prompt SPI NOR Flash Operation Retry Value
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount|0x00000003|UINT32|0x00000033
> +
> +  ## SPI NOR Flash operation retry counts for the fixed timeout value
> +  #  0x00000000:  No retry
> +  #  0xFFFFFFFF:  Maximum retry value
> +  #
> +  # @Prompt SPI NOR Flash Operation Retry Value for the Fixed Timeout Value
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount|0x0000FFFF|UINT32|0x00000034
> +
> +  ## SPI NOR Flash operation delay in microseconds
> +  #  Deafult is set to 0x00000010 microseconds
> +  #
> +  # @Prompt SPI NOR Flash Operation Delay in Microseconds (16 us)
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds|0x00000010|UINT32|0x00000035
> +
>   [PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
>     ## This PCD defines the Console output row. The default value is 25 according to UEFI spec.
>     #  This PCD could be set to 0 then console output would be at max column and max row.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#117786): https://edk2.groups.io/g/devel/message/117786
Mute This Topic: https://groups.io/mt/105325720/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 4843 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2024-04-15 13:51 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-04  9:24 [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
2024-04-04  9:24 ` [edk2-devel] [PATCH V5 1/6] MdePkg/Include: Update definitions of SPI related header files Chang, Abner via groups.io
2024-04-04  9:24 ` [edk2-devel] [PATCH V5 2/6] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file Chang, Abner via groups.io
2024-04-15  8:23   ` Abdul Lateef Attar via groups.io
2024-04-04  9:24 ` [edk2-devel] [PATCH V5 3/6] MdeModulePkg: Add definitions in DEC for SPI NOR Flash SFDP driver Chang, Abner via groups.io
2024-04-15 13:51   ` Abdul Lateef Attar via groups.io
2024-04-04  9:24 ` [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Chang, Abner via groups.io
2024-04-04  9:24 ` [edk2-devel] [PATCH V5 5/6] MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC Chang, Abner via groups.io
2024-04-04  9:24 ` [edk2-devel] [PATCH V5 6/6] Maintainers: AMD as SPI driver stack maintainer Chang, Abner via groups.io
2024-04-09  6:09 ` 回复: [edk2-devel] [PATCH V5 0/6] SPI NOR Flash Driver for SFDP flash device gaoliming via groups.io
     [not found] ` <17C30980DC7A7234.4513@groups.io>
2024-04-09  6:45   ` [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Chang, Abner via groups.io

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox