public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Chang, Abner via groups.io" <abner.chang=amd.com@groups.io>
To: "devel@edk2.groups.io" <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: Re: [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP
Date: Tue, 9 Apr 2024 06:45:31 +0000	[thread overview]
Message-ID: <LV8PR12MB9452A2D02DD6AD25458782ABEA072@LV8PR12MB9452.namprd12.prod.outlook.com> (raw)
In-Reply-To: <17C30980DC7A7234.4513@groups.io>

[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]
-=-=-=-=-=-=-=-=-=-=-=-



      parent reply	other threads:[~2024-04-09  6:45 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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   ` Chang, Abner via groups.io [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=LV8PR12MB9452A2D02DD6AD25458782ABEA072@LV8PR12MB9452.namprd12.prod.outlook.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox