MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP

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>
Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
This commit is contained in:
abnchang 2023-06-18 05:44:35 +08:00 committed by mergify[bot]
parent 6dc09fda04
commit 8b02ecc5f0
11 changed files with 4166 additions and 0 deletions

File diff suppressed because it is too large Load Diff

@ -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_

File diff suppressed because it is too large Load Diff

@ -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;
}

@ -0,0 +1,64 @@
## @file
# The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
# DXE driver INF file.
#
# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
# @par Revision Reference:
# - JEDEC Standard, JESD216F.02
# https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
#
# @par Glossary:
# - SFDP - Serial Flash Discoverable Parameters
# - PTP - Parameter Table Pointer
##
[Defines]
INF_VERSION = 1.25
BASE_NAME = SpiNorFlashJedecSfdpDxe
FILE_GUID = 0DC9C2C7-D450-41BA-9CF7-D2090C35A797
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 0.1
PI_SPECIFICATION_VERSION = 1.10
ENTRY_POINT = SpiNorFlashJedecSfdpDxeEntry
MODULE_UNI_FILE = SpiNorFlashJedecSfdpDxe.uni
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DebugLib
DevicePathLib
MemoryAllocationLib
TimerLib
UefiDriverEntryPoint
UefiBootServicesTableLib
[Sources]
SpiNorFlashJedecSfdpDxe.c
SpiNorFlash.c
SpiNorFlashJedecSfdp.c
SpiNorFlashJedecSfdpInternal.h
SpiNorFlash.h
[Protocols]
gEfiSpiNorFlashProtocolGuid ## PROCUDES
[FixedPcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount
gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds
[Guids]
gEdk2JedecSfdpSpiDxeDriverGuid
[Depex]
gEdk2JedecSfdpSpiDxeDriverGuid
[UserExtensions.TianoCore."ExtraFiles"]
SpiNorFlashJedecSfdpExtra.uni

@ -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."

@ -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"

@ -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_

@ -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;
}

@ -0,0 +1,64 @@
## @file
# The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
# SMM driver INF file.
#
# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
# @par Revision Reference:
# - JEDEC Standard, JESD216F.02
# https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
#
# @par Glossary:
# - SFDP - Serial Flash Discoverable Parameters
# - PTP - Parameter Table Pointer
##
[Defines]
INF_VERSION = 1.25
BASE_NAME = SpiNorFlashJedecSfdpSmm
FILE_GUID = AC7884C7-35A2-40AC-B9E0-AD67298E3BBA
MODULE_TYPE = DXE_SMM_DRIVER
VERSION_STRING = 0.1
PI_SPECIFICATION_VERSION = 1.10
ENTRY_POINT = SpiNorFlashJedecSfdpSmmEntry
MODULE_UNI_FILE = SpiNorFlashJedecSfdpSmm.uni
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DebugLib
DevicePathLib
MemoryAllocationLib
SmmServicesTableLib
TimerLib
UefiDriverEntryPoint
[Sources]
SpiNorFlashJedecSfdpSmm.c
SpiNorFlash.c
SpiNorFlashJedecSfdp.c
SpiNorFlashJedecSfdpInternal.h
SpiNorFlash.h
[Protocols]
gEfiSpiSmmNorFlashProtocolGuid ## PROCUDES
[FixedPcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount
gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds
[Guids]
gEdk2JedecSfdpSpiSmmDriverGuid
[Depex]
gEdk2JedecSfdpSpiSmmDriverGuid
[UserExtensions.TianoCore."ExtraFiles"]
SpiNorFlashJedecSfdpExtra.uni

@ -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."