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