* [edk2-devel] [PATCH 0/5] SPI NOR Flash Driver for SFDP flash device
@ 2023-07-25 7:10 Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 1/5] MdePkg/Include: Update definitions of SPI related header files Chang, Abner via groups.io
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Chang, Abner via groups.io @ 2023-07-25 7:10 UTC (permalink / raw)
To: devel
Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Abdul Lateef Attar,
Hao A Wu, Ray Ni, Jian J Wang
From: Abner Chang <abner.chang@amd.com>
This patch fixes the missing SPI defintions per to the
PIWG approval against PI spec 1.8 errata for ticket #2394.
This patch also provides the implemtation of SPI NOR flash
driver that supports JEDEC SFDP specification.
This driver support the flash device that has the GUID
gEdk2JedecSfdpSpiDxeDriverGuid or gEdk2JedecSfdpSpiSmmDriverGuid
declared in EFI_SPI_PERIPHERAL SpiPeripheralDriverGuid structure.
The driver has been verified with Macronix MX25U6435F flash device.
Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
abnchang (5):
MdePkg/Include: Update definitions of SPI related header files
MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file
MdePkg: Add definitions in DEC for SPI NOR Flash SPDF driver
MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP
MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC
MdePkg/MdePkg.dec | 19 +
MdeModulePkg/MdeModulePkg.dsc | 2 +
.../SpiNorFlashJedecSfdpDxe.inf | 63 +
.../SpiNorFlashJedecSfdpSmm.inf | 63 +
.../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h | 274 +++
.../SpiNorFlashJedecSfdpInternal.h | 294 +++
.../IndustryStandard/SpiNorFlashJedecSfdp.h | 324 +++
MdePkg/Include/Protocol/SpiConfiguration.h | 8 +
MdePkg/Include/Protocol/SpiHc.h | 14 +
MdePkg/Include/Protocol/SpiIo.h | 10 +
.../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c | 1114 +++++++++++
.../SpiNorFlashJedecSfdp.c | 1772 +++++++++++++++++
.../SpiNorFlashJedecSfdpDxe.c | 261 +++
.../SpiNorFlashJedecSfdpSmm.c | 234 +++
.../SpiNorFlashJedecSfdpDxe.uni | 13 +
.../SpiNorFlashJedecSfdpExtra.uni | 11 +
.../SpiNorFlashJedecSfdpSmm.uni | 13 +
17 files changed, 4489 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 MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni
--
2.37.1.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#107220): https://edk2.groups.io/g/devel/message/107220
Mute This Topic: https://groups.io/mt/100345720/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH 1/5] MdePkg/Include: Update definitions of SPI related header files
2023-07-25 7:10 [edk2-devel] [PATCH 0/5] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
@ 2023-07-25 7:10 ` Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 2/5] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file Chang, Abner via groups.io
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Chang, Abner via groups.io @ 2023-07-25 7:10 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Abdul Lateef Attar
From: abnchang <abnchang@amd.com>
BZ#: 4471
Update definitions according to PI spec v1.8 Errata as it
is approved in PIWG (Ticket #2394).
Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
---
MdePkg/Include/Protocol/SpiConfiguration.h | 8 ++++++++
MdePkg/Include/Protocol/SpiHc.h | 14 ++++++++++++++
MdePkg/Include/Protocol/SpiIo.h | 10 ++++++++++
3 files changed, 32 insertions(+)
diff --git a/MdePkg/Include/Protocol/SpiConfiguration.h b/MdePkg/Include/Protocol/SpiConfiguration.h
index 3f8fb9ff62c..cffdc8e232d 100644
--- a/MdePkg/Include/Protocol/SpiConfiguration.h
+++ b/MdePkg/Include/Protocol/SpiConfiguration.h
@@ -2,6 +2,7 @@
This file defines the SPI Configuration Protocol.
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
@@ -168,6 +169,13 @@ typedef struct _EFI_SPI_BUS {
VOID *ClockParameter;
} EFI_SPI_BUS;
+///
+/// Definitions of SPI Part Attributes.
+///
+#define SPI_PART_SUPPORTS_2_BIT_DATA_BUS_WIDTH BIT0
+#define SPl_PART_SUPPORTS_4_B1T_DATA_BUS_WIDTH BIT1
+#define SPl_PART_SUPPORTS_8_B1T_DATA_BUS_WIDTH BIT2
+
///
/// The EFI_SPI_PERIPHERAL data structure describes how a specific block of
/// logic which is connected to the SPI bus. This data structure also selects
diff --git a/MdePkg/Include/Protocol/SpiHc.h b/MdePkg/Include/Protocol/SpiHc.h
index 30128dd5c4d..645bfdefe9b 100644
--- a/MdePkg/Include/Protocol/SpiHc.h
+++ b/MdePkg/Include/Protocol/SpiHc.h
@@ -2,6 +2,7 @@
This file defines the SPI Host Controller Protocol.
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
@@ -121,6 +122,19 @@ typedef EFI_STATUS
IN EFI_SPI_BUS_TRANSACTION *BusTransaction
);
+///
+/// Definitions of SPI Host Controller Attributes.
+///
+#define HC_SUPPORTS_WRITE_ONLY_OPERATIONS BIT0
+#define HC_SUPPORTS_READ_ONLY_OPERATIONS BIT1
+#define HC_SUPPORTS_WRITE_THEN_READ_OPERATIONS BIT2
+#define HC_TX_FRAME_IN_MOST_SIGNIFICANT_BITS BIT3
+#define HC_RX_FRAME_IN_MOST_SIGNIFICANT_BITS BIT4
+#define HC_SUPPORTS_2_BIT_DATA_BUS_WIDTH BIT5
+#define HC_SUPPORTS_4_BIT_DATA_BUS_WIDTH BIT6
+#define HC_SUPPORTS_8_BIT_DATA_BUS_WIDTH BIT7
+#define HC_TRANSFER_SIZE_INCLUDES_OPCODE BIT8
+#define HC_TRANSFER_SIZE_INCLUDES_ADDRESS BIT9
///
/// Support a SPI data transaction between the SPI controller and a SPI chip.
///
diff --git a/MdePkg/Include/Protocol/SpiIo.h b/MdePkg/Include/Protocol/SpiIo.h
index b4fc5e03b88..0ea881fd115 100644
--- a/MdePkg/Include/Protocol/SpiIo.h
+++ b/MdePkg/Include/Protocol/SpiIo.h
@@ -2,6 +2,7 @@
This file defines the SPI I/O Protocol.
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
@@ -223,6 +224,15 @@ typedef struct _EFI_SPI_BUS_TRANSACTION {
UINT8 *ReadBuffer;
} EFI_SPI_BUS_TRANSACTION;
+///
+/// Definitions of SPI I/O Attributes.
+///
+#define SPI_IO_SUPPORTS_2_BIT_DATA_BUS_WIDTH BIT0
+#define SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH BIT1
+#define SPI_IO_SUPPORTS_8_BIT_DATA_BUS_WIDTH BIT2
+#define SPI_IO_TRANSFER_SIZE_INCLUDES_OPCODE BIT3
+#define SPI_IO_TRANSFER_SIZE_INCLUDES_ADDRESS BIT4
+
///
/// Support managed SPI data transactions between the SPI controller and a SPI
/// chip.
--
2.37.1.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#107221): https://edk2.groups.io/g/devel/message/107221
Mute This Topic: https://groups.io/mt/100345721/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH 2/5] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file
2023-07-25 7:10 [edk2-devel] [PATCH 0/5] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 1/5] MdePkg/Include: Update definitions of SPI related header files Chang, Abner via groups.io
@ 2023-07-25 7:10 ` Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 3/5] MdePkg: Add definitions in DEC for SPI NOR Flash SPDF driver Chang, Abner via groups.io
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Chang, Abner via groups.io @ 2023-07-25 7:10 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Abdul Lateef Attar
From: abnchang <abnchang@amd.com>
BZ#: 4472
Add definition of JEDEC Serial Flash Discoverable Parameters
(SFDP) specification.
https://www.jedec.org/standards-documents/docs/jesd216b
Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
---
.../IndustryStandard/SpiNorFlashJedecSfdp.h | 324 ++++++++++++++++++
1 file changed, 324 insertions(+)
create mode 100644 MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
diff --git a/MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h b/MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
new file mode 100644
index 00000000000..44ab5a12633
--- /dev/null
+++ b/MdePkg/Include/IndustryStandard/SpiNorFlashJedecSfdp.h
@@ -0,0 +1,324 @@
+/** @file
+ SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+ header file.
+
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Revision Reference:
+ - JEDEC Standard, JESD216F.02
+ https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+
+ @par Glossary:
+ - SFDP - Serial Flash Discoverable Parameters
+ - PTP - Parameter Table Pointer
+**/
+
+#ifndef SPI_NOR_FLASH_JEDEC_H_
+#define SPI_NOR_FLASH_JEDEC_H_
+
+#include <Base.h>
+
+#define SFDP_HEADER_SIGNATURE 0x50444653
+#define SFDP_SUPPORTED_MAJOR_REVISION 0x1ul
+
+/// JEDEC Basic Flash Parameter Header
+#define SFDP_BASIC_PARAMETER_ID_LSB 0x00
+#define SFDP_BASIC_PARAMETER_ID_MSB 0xFF
+
+///
+/// JDEC Sector Map Parameter Header and Table
+///
+#define SFDP_SECTOR_MAP_PARAMETER_ID_LSB 0x81
+#define SFDP_FOUR_BYTE_ADDRESS_INSTRUCTION_LSB 0x84
+#define SFDP_SECTOR_MAP_PARAMETER_ID_MSB 0xFF
+
+#define SFDP_FLASH_MEMORY_DENSITY_4GBIT 0x80000000
+
+#pragma pack (1)
+typedef struct _SFDP_HEADER {
+ UINT32 Signature;
+ UINT32 MinorRev : 8;
+ UINT32 MajorRev : 8;
+ UINT32 NumParameterHeaders : 8;
+ UINT32 AccessProtocol : 8;
+} SFDP_HEADER;
+
+typedef struct _SFDP_PARAMETER_HEADER {
+ UINT32 IdLsb : 8;
+ UINT32 MinorRev : 8;
+ UINT32 MajorRev : 8;
+ UINT32 Length : 8;
+ UINT32 TablePointer : 24;
+ UINT32 IdMsb : 8;
+} SFDP_PARAMETER_HEADER;
+
+typedef struct _SFDP_BASIC_FLASH_PARAMETER {
+ // DWORD 1
+ UINT32 EraseSizes : 2;
+ UINT32 WriteGranularity : 1;
+ UINT32 VolatileStatusBlockProtect : 1;
+ UINT32 WriteEnableVolatileStatus : 1;
+ UINT32 Unused1Dw1 : 3;
+ UINT32 FourKEraseInstr : 8;
+ UINT32 FastRead112 : 1;
+ UINT32 AddressBytes : 2;
+ UINT32 DtrClocking : 1;
+ UINT32 FastRead122 : 1;
+ UINT32 FastRead144 : 1;
+ UINT32 FastRead114 : 1;
+ UINT32 Unused2Dw1 : 9;
+ // DWORD 2
+ UINT32 Density;
+ // DWORD 3
+ // Fast Read 144
+ UINT32 FastRead144Dummy : 5;
+ UINT32 FastRead144ModeClk : 3;
+ UINT32 FastRead144Instr : 8;
+ // Fast Read 114
+ UINT32 FastRead114Dummy : 5;
+ UINT32 FastRead114ModeClk : 3;
+ UINT32 FastRead114Instr : 8;
+ // DWORD 4
+ // Fast Read 112
+ UINT32 FastRead112Dummy : 5;
+ UINT32 FastRead112ModeClk : 3;
+ UINT32 FastRead112Instr : 8;
+ // Fast Read 122
+ UINT32 FastRead122Dummy : 5;
+ UINT32 FastRead122ModeClk : 3;
+ UINT32 FastRead122Instr : 8;
+ // DWORD 5
+ UINT32 FastRead222 : 1;
+ UINT32 Unused1Dw5 : 3;
+ UINT32 FastRead444 : 1;
+ UINT32 Unused2Dw5 : 27;
+ // DWORD 6
+ UINT32 UnusedDw6 : 16;
+ // Fast Read 222
+ UINT32 FastRead222Dummy : 5;
+ UINT32 FastRead222ModeClk : 3;
+ UINT32 FastRead222Instr : 8;
+ // DWORD 7
+ UINT32 UnusedDw7 : 16;
+ // Fast Read 444
+ UINT32 FastRead444Dummy : 5;
+ UINT32 FastRead444ModeClk : 3;
+ UINT32 FastRead444Instr : 8;
+ // DWORD 8
+ UINT32 Erase1Size : 8;
+ UINT32 Erase1Instr : 8;
+ UINT32 Erase2Size : 8;
+ UINT32 Erase2Instr : 8;
+ // DWORD 9
+ UINT32 Erase3Size : 8;
+ UINT32 Erase3Instr : 8;
+ UINT32 Erase4Size : 8;
+ UINT32 Erase4Instr : 8;
+ // DWORD 10
+ UINT32 EraseMultiplier : 4;
+ UINT32 Erase1Time : 7;
+ UINT32 Erase2Time : 7;
+ UINT32 Erase3Time : 7;
+ UINT32 Erase4Time : 7;
+ // DWORD 11
+ UINT32 ProgramMultiplier : 4;
+ UINT32 PageSize : 4;
+ UINT32 PPTime : 6;
+ UINT32 BPFirstTime : 5;
+ UINT32 BPAdditionalTime : 5;
+ UINT32 ChipEraseTime : 7;
+ UINT32 Unused1Dw11 : 1;
+ // DWORD 12
+ UINT32 ProgSuspendProhibit : 4;
+ UINT32 EraseSuspendProhibit : 4;
+ UINT32 Unused1Dw13 : 1;
+ UINT32 ProgResumeToSuspend : 4;
+ UINT32 ProgSuspendInProgressTime : 7;
+ UINT32 EraseResumeToSuspend : 4;
+ UINT32 EraseSuspendInProgressTime : 7;
+ UINT32 SuspendResumeSupported : 1;
+ // DWORD 13
+ UINT32 Unused13;
+ // DWORD 14
+ UINT32 Unused14;
+ // DWORD 15
+ UINT32 Unused15;
+ // DWORD 16
+ UINT32 Unused16;
+ // DWORD 17
+ UINT32 FastRead188Dummy : 5;
+ UINT32 FastRead188ModeClk : 3;
+ UINT32 FastRead188Instr : 8;
+ UINT32 FastRead118Dummy : 5;
+ UINT32 FastRead118ModeClk : 3;
+ UINT32 FastRead118Instr : 8;
+ //
+ // Don't care about remaining DWORDs
+ // DWORD 18 to DWORD 23
+ //
+ UINT32 Unused18;
+ UINT32 Unused19;
+ UINT32 Unused20;
+ UINT32 Unused21;
+ UINT32 Unused22;
+ UINT32 Unused23;
+} SFDP_BASIC_FLASH_PARAMETER;
+#pragma pack ()
+
+#define SPI_UNIFORM_4K_ERASE_SUPPORTED 0x01
+#define SPI_UNIFORM_4K_ERASE_UNSUPPORTED 0x03
+
+///
+/// Number of address bytes opcode can support
+///
+#define SPI_ADDR_3BYTE_ONLY 0x00
+#define SPI_ADDR_3OR4BYTE 0x01
+#define SPI_ADDR_4BYTE_ONLY 0x02
+
+#define SFDP_ERASE_TYPES_NUMBER 4
+#define SFDP_ERASE_TYPE_1 0x0001
+#define SFDP_ERASE_TYPE_2 0x0002
+#define SFDP_ERASE_TYPE_3 0x0003
+#define SFDP_ERASE_TYPE_4 0x0004
+
+///
+/// Read/Write Array Commands
+///
+#define SPI_FLASH_READ 0x03
+#define SPI_FLASH_READ_DUMMY 0x00
+#define SPI_FLASH_READ_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_FAST_READ 0x0B
+#define SPI_FLASH_FAST_READ_DUMMY 0x01
+#define SPI_FLASH_FAST_READ_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_PP 0x02
+#define SPI_FLASH_PP_DUMMY 0x00
+#define SPI_FLASH_PP_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_PAGE_SIZE 256
+#define SPI_FLASH_SE 0x20
+#define SPI_FLASH_SE_DUMMY 0x00
+#define SPI_FLASH_SE_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_BE32K 0x52
+#define SPI_FLASH_BE32K_DUMMY 0x00
+#define SPI_FLASH_BE32K_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_BE 0xD8
+#define SPI_FLASH_BE_DUMMY 0x00
+#define SPI_FLASH_BE_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_CE 0x60
+#define SPI_FLASH_CE_DUMMY 0x00
+#define SPI_FLASH_CE_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_RDID 0x9F
+#define SPI_FLASH_RDID_DUMMY 0x00
+#define SPI_FLASH_RDID_ADDR_BYTES SPI_ADDR_3OR4BYTE
+
+///
+/// Register Setting Commands
+///
+#define SPI_FLASH_WREN 0x06
+#define SPI_FLASH_WREN_DUMMY 0x00
+#define SPI_FLASH_WREN_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_WRDI 0x04
+#define SPI_FLASH_WRDI_DUMMY 0x00
+#define SPI_FLASH_WRDI_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_RDSR 0x05
+#define SPI_FLASH_RDSR_DUMMY 0x00
+#define SPI_FLASH_RDSR_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_SR_NOT_WIP 0x0
+#define SPI_FLASH_SR_WIP BIT0
+#define SPI_FLASH_SR_WEL BIT1
+#define SPI_FLASH_WRSR 0x01
+#define SPI_FLASH_WRSR_DUMMY 0x00
+#define SPI_FLASH_WRSR_ADDR_BYTES SPI_ADDR_3OR4BYTE
+#define SPI_FLASH_WREN_50H 0x50
+#define SPI_FLASH_RDSFDP 0x5A
+#define SPI_FLASH_RDSFDP_DUMMY 0x01
+#define SPI_FLASH_RDSFDP_ADDR_BYTES SPI_ADDR_3BYTE_ONLY
+#define ERASE_TYPICAL_TIME_UNITS_MASK 0x60
+#define ERASE_TYPICAL_TIME_BIT_POSITION 5
+#define ERASE_TYPICAL_TIME_UNIT_1_MS_BITMAP 0x00
+#define ERASE_TYPICAL_TIME_UNIT_1_MS 1
+#define ERASE_TYPICAL_TIME_UNIT_16_MS_BITMAP 0x01
+#define ERASE_TYPICAL_TIME_UNIT_16_MS 16
+#define ERASE_TYPICAL_TIME_UNIT_128_MS_BITMAP 0x10
+#define ERASE_TYPICAL_TIME_UNIT_128_MS 128
+#define ERASE_TYPICAL_TIME_UNIT_1000_MS_BITMAP 0x11
+#define ERASE_TYPICAL_TIME_UNIT_1000_MS 1000
+#define ERASE_TYPICAL_TIME_COUNT_MASK 0x1f
+
+///
+/// Flash Device Configuration Detection Command descriptor.
+///
+typedef struct {
+ // DWORD 1
+ UINT32 DescriptorEnd : 1; ///< Descriptor Sequence End Indicator.
+ UINT32 DescriptorType : 1; ///< Descriptor Type.
+ UINT32 Reserve1 : 6; ///< Bit [7:2] is reserved.
+ UINT32 DetectionInstruction : 8; ///< Sector map configuration detection command.
+ UINT32 DetectionLatency : 4; ///< Configuration detection command read latency.
+ UINT32 Reserve2 : 2; ///< Bit [21:20] is reserved.
+ UINT32 DetectionCommandAddressLen : 2; ///< Configuration detection command address length.
+ UINT32 ReadDataMask : 8; ///< Bit mask of the interst bit of the returned
+ ///< byte read from the detection command.
+ // DWORD 2
+ UINT32 CommandAddress : 32; ///< Sector map configuration detection command address.
+} SFDP_SECTOR_CONFIGURATION_COMMAND;
+
+#define SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_COMMAND 0
+#define SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_MAP 1
+#define SFDP_SECTOR_MAP_TABLE_ENTRY_LAST 1
+
+///
+/// Definition of Configuration detection command address length.
+///
+typedef enum {
+ SpdfConfigurationCommandAddressNone = 0,
+ SpdfConfigurationCommandAddress3Byte = 1,
+ SpdfConfigurationCommandAddress4Byte = 2,
+ SpdfConfigurationCommandAddressVariable = 3
+} SPDF_CONFIGURATION_COMMAND_ADDR_LENGTH;
+
+///
+/// Flash Device Configuration Map descriptor.
+///
+typedef struct {
+ // DWORD 1
+ UINT32 DescriptorEnd : 1; ///< Descriptor Sequence End Indicator.
+ UINT32 DescriptorType : 1; ///< Descriptor Type.
+ UINT32 Reserve1 : 6; ///< Bit [7:2] is reserved.
+ UINT32 ConfigurationID : 8; ///< ID of this configuration.
+ UINT32 RegionCount : 8; ///< The region count of this configuration.
+ UINT32 Reserve2 : 8; ///< [31:24] is reserved.
+} SFDP_SECTOR_CONFIGURATION_MAP;
+
+typedef struct {
+ UINT32 DescriptorEnd : 1; ///< Descriptor Sequence End Indicator.
+ UINT32 DescriptorType : 1; ///< Descriptor Type.
+} SFDP_SECTOR_CONFIGURATION_GENERIC_HEADER;
+
+///
+/// Flash Device Region Definition.
+///
+typedef struct _SFDP_SECTOR_REGION {
+ // DWORD 1
+ UINT32 EraseType1 : 1; ///< Earse type 1 is supported.
+ UINT32 EraseType2 : 1; ///< Earse type 2 is supported.
+ UINT32 EraseType3 : 1; ///< Earse type 3 is supported.
+ UINT32 EraseType4 : 1; ///< Earse type 4 is supported.
+ UINT32 Reserve1 : 4; ///< Bit [7:4] is reserved.
+ UINT32 RegionSize : 24; ///< Region size in 256 Byte unit.
+} SFDP_SECTOR_REGION;
+#define SFDP_SECTOR_REGION_SIZE_UNIT 256
+
+///
+/// Sector Map Table structure, the entry could be
+/// either Configuration Detection Command descriptor,
+/// or Configuration Map descriptor.
+///
+typedef union _SFDP_SECTOR_MAP_TABLE {
+ SFDP_SECTOR_CONFIGURATION_GENERIC_HEADER GenericHeader;
+ SFDP_SECTOR_CONFIGURATION_COMMAND ConfigurationCommand; ///< Fash configuration detection command.
+ SFDP_SECTOR_CONFIGURATION_MAP ConfigurationMap; ///< Flash map descriptor.
+} SFDP_SECTOR_MAP_TABLE;
+
+#endif // SPI_NOR_FLASH_JEDEC_H_
--
2.37.1.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#107222): https://edk2.groups.io/g/devel/message/107222
Mute This Topic: https://groups.io/mt/100345722/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH 3/5] MdePkg: Add definitions in DEC for SPI NOR Flash SPDF driver
2023-07-25 7:10 [edk2-devel] [PATCH 0/5] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 1/5] MdePkg/Include: Update definitions of SPI related header files Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 2/5] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file Chang, Abner via groups.io
@ 2023-07-25 7:10 ` Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 4/5] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 5/5] MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC Chang, Abner via groups.io
4 siblings, 0 replies; 6+ messages in thread
From: Chang, Abner via groups.io @ 2023-07-25 7:10 UTC (permalink / raw)
To: devel; +Cc: Michael D Kinney, Liming Gao, Zhiguang Liu, Abdul Lateef Attar
From: abnchang <abnchang@amd.com>
BZ#: 4473
Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Abdul Lateef Attar <abdattar@amd.com>
---
MdePkg/MdePkg.dec | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index b85614992b9..47d8daba826 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -875,6 +875,12 @@
## Include/Protocol/CcMeasurement.h
gEfiCcFinalEventsTableGuid = { 0xdd4a4648, 0x2de7, 0x4665, { 0x96, 0x4d, 0x21, 0xd9, 0xef, 0x5f, 0xb4, 0x46 }}
+ #
+ # SPI NOR flash JEDEC Serial Flash Discoverable Parameters (SFDP) driver GUID
+ #
+ gEdk2JedecSfdpSpiDxeDriverGuid = { 0xBE71701E, 0xB63C, 0x4574, { 0x9C, 0x5C, 0x36, 0x29, 0xE8, 0xEA, 0xC4, 0x14 }}
+ gEdk2JedecSfdpSpiSmmDriverGuid = { 0x95A1E915, 0x195C, 0x477C, { 0x92, 0x6F, 0x7E, 0x24, 0x67, 0xC1, 0xB3, 0x1F }}
+
[Guids.IA32, Guids.X64]
## Include/Guid/Cper.h
gEfiIa32X64ErrorTypeCacheCheckGuid = { 0xA55701F5, 0xE3EF, 0x43de, { 0xAC, 0x72, 0x24, 0x9B, 0x57, 0x3F, 0xAD, 0x2C }}
@@ -2232,6 +2238,19 @@
# @Prompt Speculation Barrier Type.
gEfiMdePkgTokenSpaceGuid.PcdSpeculationBarrierType|0x01|UINT8|0x30001018
+ ## SPI NOR Flash operation retry counts
+ # 0x00000000: No retry
+ # 0xFFFFFFFF: Maximum retry value
+ #
+ # @Prompt SPI NOR Flash Operation Retry Value
+ gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount|0xFFFFFFFF|UINT32|0x30001019
+
+ ## SPI NOR Flash operation delay in microseconds
+ # Deafult is set to 0x0000000f microseconds
+ #
+ # @Prompt SPI NOR Flash Operation Delay in Microseconds
+ gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds|0x0000000F|UINT32|0x3000101A
+
[PcdsFixedAtBuild,PcdsPatchableInModule]
## Indicates the maximum length of unicode string used in the following
# BaseLib functions: StrLen(), StrSize(), StrCmp(), StrnCmp(), StrCpy(), StrnCpy()<BR><BR>
--
2.37.1.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#107223): https://edk2.groups.io/g/devel/message/107223
Mute This Topic: https://groups.io/mt/100345723/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH 4/5] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP
2023-07-25 7:10 [edk2-devel] [PATCH 0/5] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
` (2 preceding siblings ...)
2023-07-25 7:10 ` [edk2-devel] [PATCH 3/5] MdePkg: Add definitions in DEC for SPI NOR Flash SPDF driver Chang, Abner via groups.io
@ 2023-07-25 7:10 ` Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 5/5] MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC Chang, Abner via groups.io
4 siblings, 0 replies; 6+ messages in thread
From: Chang, Abner via groups.io @ 2023-07-25 7:10 UTC (permalink / raw)
To: devel; +Cc: Hao A Wu, Ray Ni, Abdul Lateef Attar
From: abnchang <abnchang@amd.com>
BZ#: 4473
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>
---
.../SpiNorFlashJedecSfdpDxe.inf | 63 +
.../SpiNorFlashJedecSfdpSmm.inf | 63 +
.../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h | 274 +++
.../SpiNorFlashJedecSfdpInternal.h | 294 +++
.../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c | 1114 +++++++++++
.../SpiNorFlashJedecSfdp.c | 1772 +++++++++++++++++
.../SpiNorFlashJedecSfdpDxe.c | 261 +++
.../SpiNorFlashJedecSfdpSmm.c | 234 +++
.../SpiNorFlashJedecSfdpDxe.uni | 13 +
| 11 +
.../SpiNorFlashJedecSfdpSmm.uni | 13 +
11 files changed, 4112 insertions(+)
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni
create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
new file mode 100644
index 00000000000..d3c9c5a0641
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
@@ -0,0 +1,63 @@
+## @file
+# The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+# DXE driver INF file.
+#
+# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# @par Revision Reference:
+# - JEDEC Standard, JESD216F.02
+# https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+#
+# @par Glossary:
+# - SFDP - Serial Flash Discoverable Parameters
+# - PTP - Parameter Table Pointer
+##
+
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = SpiNorFlashJedecSfdpDxe
+ FILE_GUID = 0DC9C2C7-D450-41BA-9CF7-D2090C35A797
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 0.1
+ PI_SPECIFICATION_VERSION = 1.10
+ ENTRY_POINT = SpiNorFlashJedecSfdpDxeEntry
+ MODULE_UNI_FILE = SpiNorFlashJedecSfdpDxe.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ TimerLib
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+
+[Sources]
+ SpiNorFlashJedecSfdpDxe.c
+ SpiNorFlash.c
+ SpiNorFlashJedecSfdp.c
+ SpiNorFlashJedecSfdpInternal.h
+ SpiNorFlash.h
+
+[Protocols]
+ gEfiSpiNorFlashProtocolGuid ## PROCUDES
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
+ gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds
+
+[Guids]
+ gEdk2JedecSfdpSpiDxeDriverGuid
+
+[Depex]
+ gEdk2JedecSfdpSpiDxeDriverGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SpiNorFlashJedecSfdpExtra.uni
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
new file mode 100644
index 00000000000..e95dd9f3b56
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
@@ -0,0 +1,63 @@
+## @file
+# The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+# SMM driver INF file.
+#
+# Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# @par Revision Reference:
+# - JEDEC Standard, JESD216F.02
+# https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+#
+# @par Glossary:
+# - SFDP - Serial Flash Discoverable Parameters
+# - PTP - Parameter Table Pointer
+##
+
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = SpiNorFlashJedecSfdpSmm
+ FILE_GUID = AC7884C7-35A2-40AC-B9E0-AD67298E3BBA
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 0.1
+ PI_SPECIFICATION_VERSION = 1.10
+ ENTRY_POINT = SpiNorFlashJedecSfdpSmmEntry
+ MODULE_UNI_FILE = SpiNorFlashJedecSfdpSmm.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ SmmServicesTableLib
+ TimerLib
+ UefiDriverEntryPoint
+
+[Sources]
+ SpiNorFlashJedecSfdpSmm.c
+ SpiNorFlash.c
+ SpiNorFlashJedecSfdp.c
+ SpiNorFlashJedecSfdpInternal.h
+ SpiNorFlash.h
+
+[Protocols]
+ gEfiSpiSmmNorFlashProtocolGuid ## PROCUDES
+
+[FixedPcd]
+ gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount
+ gEfiMdePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds
+
+[Guids]
+ gEdk2JedecSfdpSpiSmmDriverGuid
+
+[Depex]
+ gEdk2JedecSfdpSpiSmmDriverGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SpiNorFlashJedecSfdpExtra.uni
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h
new file mode 100644
index 00000000000..ca85ab103ab
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h
@@ -0,0 +1,274 @@
+/** @file
+ Definitions of SPI NOR flash operation functions.
+
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SPI_NOR_FLASH_H_
+#define SPI_NOR_FLASH_H_
+
+#include <PiDxe.h>
+#include <Protocol/SpiNorFlash.h>
+#include <Protocol/SpiIo.h>
+#include "SpiNorFlashJedecSfdpInternal.h"
+
+/**
+ Fill Write Buffer with Opcode, Address, Dummy Bytes, and Data
+
+ @param[in] Opcode - Opcode for transaction
+ @param[in] Address - SPI Offset Start Address
+ @param[in] WriteBytes - Number of bytes to write to SPI device
+ @param[in] WriteBuffer - Buffer containing bytes to write to SPI device
+
+ @retval Size of Data in Buffer
+**/
+UINT32
+FillWriteBuffer (
+ IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance,
+ IN UINT8 Opcode,
+ IN UINT32 DummyBytes,
+ IN UINT8 AddressBytesSupported,
+ IN BOOLEAN UseAddress,
+ IN UINT32 Address,
+ IN UINT32 WriteBytes,
+ IN UINT8 *WriteBuffer
+ );
+
+/**
+ Set Write Enable Latch
+
+ @param[in] Instance SPI NOR instance with all protocols, etc.
+
+ @retval EFI_SUCCESS SPI Write Enable succeeded
+ @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly
+**/
+EFI_STATUS
+SetWel (
+ IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance
+ );
+
+/**
+ Check for not device write in progress
+
+ @param[in] Instance - SPI NOR instance with all protocols, etc.
+
+ @retval EFI_SUCCESS Device does not have a write in progress
+ @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitNotWip (
+ IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance
+ );
+
+/**
+ Check for write enable latch set and not device write in progress
+
+ @param[in] Instance - SPI NOR instance with all protocols, etc.
+
+ @retval EFI_SUCCESS Device does not have a write in progress and
+ write enable latch is set
+ @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitWelNotWip (
+ IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance
+ );
+
+/**
+ Check for not write enable latch set and not device write in progress
+
+ @param[in] Instance - SPI NOR instance with all protocols, etc.
+
+ @retval EFI_SUCCESS Device does not have a write in progress and
+ write enable latch is not set
+ @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitNotWelNotWip (
+ IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance
+ );
+
+/**
+ Read the 3 byte manufacture and device ID from the SPI flash.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine reads the 3 byte manufacture and device ID from the flash part
+ filling the buffer provided.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data structure.
+ @param[out] Buffer Pointer to a 3 byte buffer to receive the manufacture and
+ device ID.
+
+
+
+ @retval EFI_SUCCESS The manufacture and device ID was read
+ successfully.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+EFIAPI
+GetFlashId (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ OUT UINT8 *Buffer
+ );
+
+/**
+ Read data from the SPI flash.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine reads data from the SPI part in the buffer provided.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] FlashAddress Address in the flash to start reading
+ @param[in] LengthInBytes Read length in bytes
+ @param[out] Buffer Address of a buffer to receive the data
+
+ @retval EFI_SUCCESS The data was read successfully.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL, or
+ FlashAddress >= This->FlashSize, or
+ LengthInBytes > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+ReadData (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 FlashAddress,
+ IN UINT32 LengthInBytes,
+ OUT UINT8 *Buffer
+ );
+
+/**
+ Read data from the SPI flash at not fast speed
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine reads data from the SPI part in the buffer provided.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] FlashAddress Address in the flash to start reading
+ @param[in] LengthInBytes Read length in bytes
+ @param[out] Buffer Address of a buffer to receive the data
+
+ @retval EFI_SUCCESS The data was read successfully.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL, or
+ FlashAddress >= This->FlashSize, or
+ LengthInBytes > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+LfReadData (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 FlashAddress,
+ IN UINT32 LengthInBytes,
+ OUT UINT8 *Buffer
+ );
+
+/**
+ Read the flash status register.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine reads the flash part status register.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] LengthInBytes Number of status bytes to read.
+ @param[out] FlashStatus Pointer to a buffer to receive the flash status.
+
+ @retval EFI_SUCCESS The status register was read successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadStatus (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 LengthInBytes,
+ OUT UINT8 *FlashStatus
+ );
+
+/**
+ Write the flash status register.
+
+ This routine must be called at or below TPL_N OTIFY.
+ This routine writes the flash part status register.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] LengthInBytes Number of status bytes to write.
+ @param[in] FlashStatus Pointer to a buffer containing the new status.
+
+ @retval EFI_SUCCESS The status write was successful.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate the write buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteStatus (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 LengthInBytes,
+ IN UINT8 *FlashStatus
+ );
+
+/**
+ Write data to the SPI flash.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine breaks up the write operation as necessary to write the data to
+ the SPI part.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] FlashAddress Address in the flash to start writing
+ @param[in] LengthInBytes Write length in bytes
+ @param[in] Buffer Address of a buffer containing the data
+
+ @retval EFI_SUCCESS The data was written successfully.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL, or
+ FlashAddress >= This->FlashSize, or
+ LengthInBytes > This->FlashSize - FlashAddress
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory to copy buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteData (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 FlashAddress,
+ IN UINT32 LengthInBytes,
+ IN UINT8 *Buffer
+ );
+
+/**
+ Efficiently erases one or more 4KiB regions in the SPI flash.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine uses a combination of 4 KiB and larger blocks to erase the
+ specified area.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] FlashAddress Address within a 4 KiB block to start erasing
+ @param[in] BlockCount Number of 4 KiB blocks to erase
+
+ @retval EFI_SUCCESS The erase was completed successfully.
+ @retval EFI_INVALID_PARAMETER FlashAddress >= This->FlashSize, or
+ BlockCount * 4 KiB
+ > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+Erase (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 FlashAddress,
+ IN UINT32 BlockCount
+ );
+
+#endif // SPI_NOR_FLASH_H_
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h
new file mode 100644
index 00000000000..6812559b880
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h
@@ -0,0 +1,294 @@
+/** @file
+ SPI NOR flash driver internal definitions.
+
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SPI_NOR_FLASH_INSTANCE_H_
+#define SPI_NOR_FLASH_INSTANCE_H_
+
+#include <PiDxe.h>
+#include <Protocol/SpiNorFlash.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+
+#define SPI_NOR_FLASH_SIGNATURE SIGNATURE_32 ('s', 'n', 'f', 'm')
+
+#define SPI_NOR_FLASH_FROM_THIS(a) CR (a, SPI_NOR_FLASH_INSTANCE, Protocol, SPI_NOR_FLASH_SIGNATURE)
+
+typedef struct {
+ LIST_ENTRY NextFastReadCap; ///< Link list to next Fast read capability
+ UINT8 FastReadInstruction; ///< Fast read instruction.
+ UINT8 ModeClocks; ///< Fast read clock.
+ UINT8 WaitStates; ///< Fast read wait dummy clocks
+} SFPD_FAST_READ_CAPBILITY_RECORD;
+
+typedef struct {
+ LIST_ENTRY NextEraseType; ///< Link list to next erase type.
+ UINT16 EraseType; ///< Erase type this flash device supports.
+ UINT8 EraseInstruction; ///< Erase instruction
+ UINT32 EraseSizeInByte; ///< The size of byte in 2^EraseSize the erase type command
+ ///< can erase.
+ UINT32 EraseTypicalTime; ///< Time the device typically takes to erase this type
+ ///< size.
+ UINT64 EraseTimeout; ///< Maximum typical erase timeout.
+} SFDP_SUPPORTED_ERASE_TYPE_RECORD;
+
+typedef enum {
+ SearchEraseTypeByType = 1,
+ SearchEraseTypeByCommand,
+ SearchEraseTypeBySize,
+ SearchEraseTypeBySmallestSize,
+ SearchEraseTypeByBiggestSize
+} SFDP_SEARCH_ERASE_TYPE;
+
+typedef struct {
+ LIST_ENTRY NextCommand; ///< Link list to next detection command.
+ UINT32 CommandAddress; ///< Address to issue the command.
+ UINT8 CommandInstruction; ///< Detection command instruction.
+ UINT8 LatencyInClock; ///< Command latency in clocks.
+ SPDF_CONFIGURATION_COMMAND_ADDR_LENGTH CommandAddressLength; ///< Adddress length of detection command.
+ UINT8 ConfigurationBitMask; ///< The interest bit of the byte data retunred
+ ///< after sending the detection command.
+} SFDP_SECTOR_MAP_DETECTION_RECORD;
+
+typedef struct {
+ LIST_ENTRY NextRegion; ///< Link list to the next region.
+ UINT32 RegionAddress; ///< Region starting address.
+ UINT32 RegionTotalSize; ///< Region total size in bytes.
+ UINT32 RegionSectors; ///< Sectors in this region.
+ UINT32 SectorSize; ///< Sector size in byte (Minimum blcok erase size)
+ UINT8 SupportedEraseTypeNum; ///< Number of erase type supported.
+ UINT8 SupportedEraseType[SFDP_ERASE_TYPES_NUMBER]; ///< Erase types supported.
+ UINT32 EraseTypeBySizeBitmap; ///< The bitmap of supoprted srase block sizes.
+ ///< from big to small.
+} SFDP_SECTOR_REGION_RECORD;
+
+typedef struct {
+ LIST_ENTRY NextDescriptor; ///< Link list to next flash map descriptor.
+ UINT8 ConfigurationId; ///< The ID of this configuration.
+ UINT8 RegionCount; ///< The regions of this sector map configuration.
+ LIST_ENTRY RegionList; ///< The linked list of the regions.
+} SFDP_SECTOR_MAP_RECORD;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_SPI_NOR_FLASH_PROTOCOL Protocol;
+ EFI_SPI_IO_PROTOCOL *SpiIo;
+ UINT32 SfdpBasicFlashByteCount;
+ UINT32 SfdpSectorMapByteCount;
+ SFDP_BASIC_FLASH_PARAMETER *SfdpBasicFlash;
+ SFDP_SECTOR_MAP_TABLE *SfdpFlashSectorMap;
+ UINT8 *SpiTransactionWriteBuffer;
+ UINT32 SpiTransactionWriteBufferIndex;
+ //
+ // SFDP information.
+ //
+ SFDP_HEADER SfdpHeader; ///< SFDP header.
+ UINT32 FlashDeviceSize; ///< The total size of this flash device.
+ UINT8 CurrentAddressBytes; ///< The current address bytes.
+
+ //
+ // This is a linked list in which the Fast Read capability tables
+ // are linked from the low performance transfer to higher performance
+ // transfer. The SPI read would use the first Fast Read entry for
+ // SPI read operation.
+ //
+ LIST_ENTRY FastReadTableList;
+
+ LIST_ENTRY SupportedEraseTypes; ///< The linked list of supported erase types.
+ BOOLEAN Uniform4KEraseSupported; ///< The flash device supoprts uniform 4K erase.
+ BOOLEAN WriteEnableLatchRequired; ///< Wether Write Enable Latch is supported.
+ UINT8 WriteEnableLatchCommand; ///< Write Enable Latch command.
+ //
+ // Below is the linked list of flash device sector
+ // map configuration detection command and map descriptors.
+ //
+ BOOLEAN ConfigurationCommandsNeeded; ///< Indicates whether sector map
+ ///< configuration detection is
+ ///< required.
+ LIST_ENTRY ConfigurationCommandList; ///< The linked list of configuration
+ ///< detection command sequence.
+ LIST_ENTRY ConfigurationMapList; ///< The linked list of configuration
+ ///< map descriptors.
+ SFDP_SECTOR_MAP_RECORD *CurrentSectorMap; ///< The current activated flash device
+ ///< sector map.
+} SPI_NOR_FLASH_INSTANCE;
+
+/**
+ This routine returns the desired Fast Read mode.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+ @param[in,out] FastReadInstruction Fast Read instruction, the input is
+ the default value.
+ @param[in,out] FastReadOperationClock Fast Read operation clock, the input is
+ the default value.
+ @param[in,out] FastReadDummyClocks Fast Read wait state (Dummy clocks), the
+ input is the default value.
+ @retval EFI_SUCCESS The parameters are updated.
+ @retval EFI_NOT_FOUND No desired Fas Read mode found.
+
+**/
+EFI_STATUS
+GetFastReadParameter (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN OUT UINT8 *FastReadInstruction,
+ IN OUT UINT8 *FastReadOperationClock,
+ IN OUT UINT8 *FastReadDummyClocks
+ );
+
+/**
+ Read SFDP parameters into buffer
+
+ This routine reads the JEDEC SPI Flash Discoverable Parameters from the SPI
+ chip.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS The SPI part size is filled.
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdpBasicParameterTable (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ );
+
+/**
+ Read SFDP Sector Map Parameter into buffer
+
+ This routine reads the JEDEC SPI Flash Discoverable Parameters from the SPI
+ chip.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS The SPI part size is filled.
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdpSectorMapParameterTable (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ );
+
+/**
+ Return flash device size from SFDP Basic Flash Parameter Table DWORD 2
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+
+* @retval UINT32 Flash device size in byte, zero indicates error.
+
+**/
+UINT32
+SfdpGetFlashSize (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ );
+
+/**
+ Read SFDP
+ This routine reads the JEDEC SPI Flash Discoverable Parameters. We just
+ read the necessary tables in this routine.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS Header is filled in
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdp (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ );
+
+/**
+ Set EraseBlockBytes in SPI NOR Flash Protocol
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS The erase block size is returned.
+ @retval Otherwise Failed to get erase block size.
+
+**/
+EFI_STATUS
+SetSectorEraseBlockSize (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ );
+
+/**
+ Get the erase block attribute for the target address.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+ @param[in] FlashRegion The region the flash address belong.
+ @param[in] FlashAddress The target flash address.
+ @param[in] RemainingSize Remaining size to erase.
+ @param[in, out] BlockSizeToErase Input - The block erase size for this continious blocks.
+ Output - The determined block size for erasing.
+ @param[in, out] BlockCountToErase Input - The expected blocks to erase.
+ Output - The determined number of blocks to erase.
+ @param[out] BlockEraseCommand The erase command used for this continious blocks.
+
+ @retval EFI_SUCCESS The erase block attribute is returned.
+ @retval EFI_DEVICE_ERROR No valid SFDP discovered.
+ @retval EFI_NOT_FOUND No valud erase block attribute found.
+
+**/
+EFI_STATUS
+GetEraseBlockAttribute (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN SFDP_SECTOR_REGION_RECORD *FlashRegion,
+ IN UINT32 FlashAddress,
+ IN UINT32 RemainingSize,
+ IN OUT UINT32 *BlockSizeToErase,
+ IN OUT UINT32 *BlockCountToErase,
+ OUT UINT8 *BlockEraseCommand
+ );
+
+/**
+ Get the erase block attribute for the target address.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+ @param[in] FlashAddress The target flash address.
+ @param[out] FlashRegion The target flash address.
+
+ @retval EFI_SUCCESS The region is returned.
+ @retval EFI_INVALID_PARAMETER FlashAddress is not belong to any region.
+ @retval EFI_INVALID_PARAMETER Other errors.
+
+**/
+EFI_STATUS
+GetRegionByFlashAddress (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN UINT32 FlashAddress,
+ OUT SFDP_SECTOR_REGION_RECORD **FlashRegion
+ );
+
+/**
+ Initial SPI_NOR_FLASH_INSTANCE structure.
+
+ @param[in] Instance Pointer to SPI_NOR_FLASH_INSTANCE.
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS SPI_NOR_FLASH_INSTANCE is initialized according to
+ SPI NOR Flash SFDP specification.
+ @retval Otherwisw Failed to initial SPI_NOR_FLASH_INSTANCE structure.
+
+**/
+EFI_STATUS
+InitialSpiNorFlashSfdpInstance (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ );
+
+#endif // SPI_NOR_FLASH_INSTANCE_H_
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c
new file mode 100644
index 00000000000..5f6724a9324
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c
@@ -0,0 +1,1114 @@
+/** @file
+ SPI NOR Flash operation functions.
+
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TimerLib.h>
+#include <Protocol/SpiConfiguration.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiNorFlash.h"
+
+/**
+ Fill Write Buffer with Opcode, Address, Dummy Bytes, and Data
+
+ @param[in] Opcode - Opcode for transaction
+ @param[in] Address - SPI Offset Start Address
+ @param[in] WriteBytes - Number of bytes to write to SPI device
+ @param[in] WriteBuffer - Buffer containing bytes to write to SPI device
+
+ @retval Size of Data in Buffer
+**/
+UINT32
+FillWriteBuffer (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN UINT8 Opcode,
+ IN UINT32 DummyBytes,
+ IN UINT8 AddressBytesSupported,
+ IN BOOLEAN UseAddress,
+ IN UINT32 Address,
+ IN UINT32 WriteBytes,
+ IN UINT8 *WriteBuffer
+ )
+{
+ UINT32 AddressSize;
+ UINT32 BigEndianAddress;
+ UINT32 Index;
+ UINT8 SfdpAddressBytes;
+
+ SfdpAddressBytes = (UINT8)Instance->SfdpBasicFlash->AddressBytes;
+
+ // Copy Opcode into Write Buffer
+ Instance->SpiTransactionWriteBuffer[0] = Opcode;
+ Index = 1;
+ if (UseAddress == TRUE) {
+ if (AddressBytesSupported == SPI_ADDR_3BYTE_ONLY) {
+ if (SfdpAddressBytes != 0) {
+ // Check if the supported address length is already initiated.
+ if ((SfdpAddressBytes != SPI_ADDR_3BYTE_ONLY) && (SfdpAddressBytes != SPI_ADDR_3OR4BYTE)) {
+ DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFDP is: 0x%x\n", __func__, AddressBytesSupported, SfdpAddressBytes));
+ ASSERT (FALSE);
+ }
+ }
+
+ AddressSize = 3;
+ } else if (AddressBytesSupported == SPI_ADDR_4BYTE_ONLY) {
+ if (SfdpAddressBytes != 0) {
+ // Check if the supported address length is already initiated.
+ if ((SfdpAddressBytes != SPI_ADDR_4BYTE_ONLY) && (SfdpAddressBytes != SPI_ADDR_3OR4BYTE)) {
+ DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFDP is: 0x%x\n", __func__, AddressBytesSupported, SfdpAddressBytes));
+ ASSERT (FALSE);
+ }
+ }
+
+ AddressSize = 4;
+ } else if (AddressBytesSupported == SPI_ADDR_3OR4BYTE) {
+ if (SfdpAddressBytes != 0) {
+ // Check if the supported address length is already initiated.
+ if (SfdpAddressBytes != SPI_ADDR_3OR4BYTE) {
+ DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFDP is: 0x%x\n", __func__, AddressBytesSupported, SfdpAddressBytes));
+ ASSERT (FALSE);
+ }
+ }
+
+ if (Instance->Protocol.FlashSize <= SIZE_16MB) {
+ AddressSize = 3;
+ } else {
+ // SPI part is > 16MB use 4-byte addressing.
+ AddressSize = 4;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Invalid Address Bytes\n", __func__));
+ ASSERT (FALSE);
+ }
+
+ BigEndianAddress = SwapBytes32 ((UINT32)Address);
+ BigEndianAddress >>= ((sizeof (UINT32) - AddressSize) * 8);
+ CopyMem (
+ &Instance->SpiTransactionWriteBuffer[Index],
+ &BigEndianAddress,
+ AddressSize
+ );
+ Index += AddressSize;
+ }
+
+ if (SfdpAddressBytes == SPI_ADDR_3OR4BYTE) {
+ //
+ // TODO:
+ // We may need to enter/exit 4-Byte mode if SPI flash
+ // device is currently operated in 3-Bytes mode.
+ //
+ }
+
+ // Fill DummyBytes
+ if (DummyBytes != 0) {
+ SetMem (
+ &Instance->SpiTransactionWriteBuffer[Index],
+ DummyBytes,
+ 0
+ );
+ Index += DummyBytes;
+ }
+
+ // Fill Data
+ if (WriteBytes > 0) {
+ CopyMem (
+ &Instance->SpiTransactionWriteBuffer[Index],
+ WriteBuffer,
+ WriteBytes
+ );
+ Index += WriteBytes;
+ }
+
+ return Index;
+}
+
+/**
+ Internal Read the flash status register.
+
+ This routine reads the flash part status register.
+
+ @param[in] Instance SPI_NOR_FLASH_INSTANCE
+ structure.
+ @param[in] LengthInBytes Number of status bytes to read.
+ @param[out] FlashStatus Pointer to a buffer to receive the flash status.
+
+ @retval EFI_SUCCESS The status register was read successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalReadStatus (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN UINT32 LengthInBytes,
+ OUT UINT8 *FlashStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TransactionBufferLength;
+
+ // Read Status register
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ SPI_FLASH_RDSR,
+ SPI_FLASH_RDSR_DUMMY,
+ SPI_FLASH_RDSR_ADDR_BYTES,
+ FALSE,
+ 0,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_THEN_READ,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ 1,
+ FlashStatus
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+/**
+ Set Write Enable Latch
+
+ @param[in] Instance SPI NOR instance with all protocols, etc.
+
+ @retval EFI_SUCCESS SPI Write Enable succeeded
+ @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly
+**/
+EFI_STATUS
+SetWel (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TransactionBufferLength;
+
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ Instance->WriteEnableLatchCommand,
+ SPI_FLASH_WREN_DUMMY,
+ SPI_FLASH_WREN_ADDR_BYTES,
+ FALSE,
+ 0,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_ONLY,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ 0,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Set WEL fail.\n", __func__));
+ ASSERT (FALSE);
+ }
+
+ return Status;
+}
+
+/**
+ Check for not device write in progress
+
+ @param[in] Instance - SPI NOR instance with all protocols, etc.
+
+ @retval EFI_SUCCESS Device does not have a write in progress
+ @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitNotWip (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceStatus;
+ UINTN RetryCount;
+ UINTN DelayMicroseconds;
+
+ DelayMicroseconds = FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds);
+ RetryCount = FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount);
+ if (RetryCount == 0) {
+ RetryCount = 1;
+ }
+
+ do {
+ Status = InternalReadStatus (Instance, 1, &DeviceStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Read status error\n", __func__));
+ ASSERT (FALSE);
+ break;
+ }
+
+ if ( EFI_ERROR (Status)
+ || ((DeviceStatus & SPI_FLASH_SR_WIP) == SPI_FLASH_SR_NOT_WIP))
+ {
+ break;
+ }
+
+ MicroSecondDelay (DelayMicroseconds);
+ RetryCount--;
+ } while (RetryCount > 0);
+
+ if (RetryCount == 0) {
+ DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Check for write enable latch set and not device write in progress
+
+ @param[in] Instance - SPI NOR instance with all protocols, etc.
+
+ @retval EFI_SUCCESS Device does not have a write in progress and
+ write enable latch is set
+ @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitWelNotWip (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceStatus;
+ UINTN RetryCount;
+ UINTN DelayMicroseconds;
+
+ DelayMicroseconds = FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds);
+ RetryCount = FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount);
+ if (RetryCount == 0) {
+ RetryCount = 1;
+ }
+
+ do {
+ Status = InternalReadStatus (Instance, 1, &DeviceStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to read WEL.\n", __func__));
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if ( EFI_ERROR (Status)
+ || ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL))
+ == SPI_FLASH_SR_WEL))
+ {
+ break;
+ }
+
+ MicroSecondDelay (DelayMicroseconds);
+ RetryCount--;
+ } while (RetryCount > 0);
+
+ if (RetryCount == 0) {
+ DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Check for not write enable latch set and not device write in progress
+
+ @param[in] Instance - SPI NOR instance with all protocols, etc.
+
+ @retval EFI_SUCCESS Device does not have a write in progress and
+ write enable latch is not set
+ @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly
+**/
+EFI_STATUS
+WaitNotWelNotWip (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceStatus;
+ UINTN RetryCount;
+ UINTN DelayMicroseconds;
+
+ DelayMicroseconds = FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicroseconds);
+ RetryCount = FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount);
+ if (RetryCount == 0) {
+ RetryCount = 1;
+ }
+
+ do {
+ Status = InternalReadStatus (Instance, 1, &DeviceStatus);
+ ASSERT_EFI_ERROR (Status);
+ if ( EFI_ERROR (Status)
+ || ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL))
+ == SPI_FLASH_SR_NOT_WIP))
+ {
+ break;
+ }
+
+ MicroSecondDelay (DelayMicroseconds);
+ RetryCount--;
+ } while (RetryCount > 0);
+
+ if (RetryCount == 0) {
+ DEBUG ((DEBUG_ERROR, "SpiNorFlash:%a: Timeout error\n", __func__));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Read the 3 byte manufacture and device ID from the SPI flash.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine reads the 3 byte manufacture and device ID from the flash part
+ filling the buffer provided.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data structure.
+ @param[out] Buffer Pointer to a 3 byte buffer to receive the manufacture and
+ device ID.
+
+ @retval EFI_SUCCESS The manufacture and device ID was read
+ successfully.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+EFIAPI
+GetFlashId (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SPI_NOR_FLASH_INSTANCE *Instance;
+ UINT32 TransactionBufferLength;
+
+ DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__));
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = SPI_NOR_FLASH_FROM_THIS (This);
+
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+
+ if (!EFI_ERROR (Status)) {
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ SPI_FLASH_RDID,
+ SPI_FLASH_RDID_DUMMY,
+ SPI_FLASH_RDID_ADDR_BYTES,
+ FALSE,
+ 0,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_THEN_READ,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ 3,
+ Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Status;
+}
+
+/**
+ Read data from the SPI flash at not fast speed
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine reads data from the SPI part in the buffer provided.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] FlashAddress Address in the flash to start reading
+ @param[in] LengthInBytes Read length in bytes
+ @param[out] Buffer Address of a buffer to receive the data
+
+ @retval EFI_SUCCESS The data was read successfully.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL, or
+ FlashAddress >= This->FlashSize, or
+ LengthInBytes > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+LfReadData (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 FlashAddress,
+ IN UINT32 LengthInBytes,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SPI_NOR_FLASH_INSTANCE *Instance;
+ UINT32 ByteCounter;
+ UINT32 CurrentAddress;
+ UINT8 *CurrentBuffer;
+ UINT32 Length;
+ UINT32 TransactionBufferLength;
+ UINT32 MaximumTransferBytes;
+
+ DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__));
+
+ Status = EFI_DEVICE_ERROR;
+ if ((Buffer == NULL) ||
+ (FlashAddress >= This->FlashSize) ||
+ (LengthInBytes > This->FlashSize - FlashAddress))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = SPI_NOR_FLASH_FROM_THIS (This);
+ MaximumTransferBytes = Instance->SpiIo->MaximumTransferBytes;
+
+ CurrentBuffer = Buffer;
+ Length = 0;
+ for (ByteCounter = 0; ByteCounter < LengthInBytes;) {
+ CurrentAddress = FlashAddress + ByteCounter;
+ CurrentBuffer = Buffer + ByteCounter;
+ Length = LengthInBytes - ByteCounter;
+ // Length must be MaximumTransferBytes or less
+ if (Length > MaximumTransferBytes) {
+ Length = MaximumTransferBytes;
+ }
+
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ SPI_FLASH_READ,
+ SPI_FLASH_READ_DUMMY,
+ SPI_FLASH_READ_ADDR_BYTES,
+ TRUE,
+ CurrentAddress,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_THEN_READ,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ Length,
+ CurrentBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ByteCounter += Length;
+ }
+
+ return Status;
+}
+
+/**
+ Read data from the SPI flash.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine reads data from the SPI part in the buffer provided.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] FlashAddress Address in the flash to start reading
+ @param[in] LengthInBytes Read length in bytes
+ @param[out] Buffer Address of a buffer to receive the data
+
+ @retval EFI_SUCCESS The data was read successfully.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL, or
+ FlashAddress >= This->FlashSize, or
+ LengthInBytes > This->FlashSize - FlashAddress
+
+**/
+EFI_STATUS
+EFIAPI
+ReadData (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 FlashAddress,
+ IN UINT32 LengthInBytes,
+ OUT UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SPI_NOR_FLASH_INSTANCE *Instance;
+ UINT32 ByteCounter;
+ UINT32 CurrentAddress;
+ UINT8 *CurrentBuffer;
+ UINT32 Length;
+ UINT32 TransactionBufferLength;
+ UINT32 MaximumTransferBytes;
+ UINT8 FastReadInstruction;
+ UINT8 FastReadWaitStateDummyClocks;
+ UINT8 FastReadModeClock;
+
+ DEBUG ((DEBUG_INFO, "%a: Entry, Read address = 0x%08x, Length = 0x%08x\n", __func__, FlashAddress, LengthInBytes));
+
+ Status = EFI_DEVICE_ERROR;
+ if ((Buffer == NULL) ||
+ (FlashAddress >= This->FlashSize) ||
+ (LengthInBytes > This->FlashSize - FlashAddress))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = SPI_NOR_FLASH_FROM_THIS (This);
+ MaximumTransferBytes = Instance->SpiIo->MaximumTransferBytes;
+
+ //
+ // Initial the default read operation parameters.
+ //
+ FastReadInstruction = SPI_FLASH_FAST_READ;
+ FastReadWaitStateDummyClocks = SPI_FLASH_FAST_READ_DUMMY * 8;
+ FastReadModeClock = 0;
+ //
+ // Override by the Fast Read capabiity table.
+ //
+ // Get the first supported fast read comamnd.
+ // This will be the standard fast read command (0x0b),
+ // which is the first fast read command added to the
+ // supported list.
+ // TODO: The mechanism to choose the advanced fast read
+ // is not determined yet in this version of
+ // SpiNorFlash driver.
+ Status = GetFastReadParameter (
+ Instance,
+ &FastReadInstruction,
+ &FastReadModeClock,
+ &FastReadWaitStateDummyClocks
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, " Use below Fast Read mode:\n"));
+ } else {
+ DEBUG ((DEBUG_VERBOSE, " Use the default Fast Read mode:\n"));
+ }
+
+ DEBUG ((DEBUG_VERBOSE, " Instruction : 0x%x\n", FastReadInstruction));
+ DEBUG ((DEBUG_VERBOSE, " Mode Clock : 0x%x\n", FastReadModeClock));
+ DEBUG ((DEBUG_VERBOSE, " Wait States (Dummy Clocks) in clock: 0x%x\n", FastReadWaitStateDummyClocks));
+ DEBUG ((DEBUG_VERBOSE, " Supported erase address bytes by device: 0x%02x.\n", Instance->SfdpBasicFlash->AddressBytes));
+ DEBUG ((DEBUG_VERBOSE, " (00: 3-Byte, 01: 3 or 4-Byte. 10: 4-Byte)\n"));
+
+ CurrentBuffer = Buffer;
+ Length = 0;
+ for (ByteCounter = 0; ByteCounter < LengthInBytes;) {
+ CurrentAddress = FlashAddress + ByteCounter;
+ CurrentBuffer = Buffer + ByteCounter;
+ Length = LengthInBytes - ByteCounter;
+ // Length must be MaximumTransferBytes or less
+ if (Length > MaximumTransferBytes) {
+ Length = MaximumTransferBytes;
+ }
+
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ FastReadInstruction,
+ FastReadWaitStateDummyClocks / 8,
+ (UINT8)Instance->SfdpBasicFlash->AddressBytes,
+ TRUE,
+ CurrentAddress,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_THEN_READ,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ Length,
+ CurrentBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ByteCounter += Length;
+ }
+
+ return Status;
+}
+
+/**
+ Read the flash status register.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine reads the flash part status register.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] LengthInBytes Number of status bytes to read.
+ @param[out] FlashStatus Pointer to a buffer to receive the flash status.
+
+ @retval EFI_SUCCESS The status register was read successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadStatus (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 LengthInBytes,
+ OUT UINT8 *FlashStatus
+ )
+{
+ EFI_STATUS Status;
+ SPI_NOR_FLASH_INSTANCE *Instance;
+
+ if (LengthInBytes != 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = SPI_NOR_FLASH_FROM_THIS (This);
+
+ Status = InternalReadStatus (Instance, LengthInBytes, FlashStatus);
+
+ return Status;
+}
+
+/**
+ Write the flash status register.
+
+ This routine must be called at or below TPL_N OTIFY.
+ This routine writes the flash part status register.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] LengthInBytes Number of status bytes to write.
+ @param[in] FlashStatus Pointer to a buffer containing the new status.
+
+ @retval EFI_SUCCESS The status write was successful.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate the write buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteStatus (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 LengthInBytes,
+ IN UINT8 *FlashStatus
+ )
+{
+ EFI_STATUS Status;
+ SPI_NOR_FLASH_INSTANCE *Instance;
+ UINT32 TransactionBufferLength;
+
+ if (LengthInBytes != 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = SPI_NOR_FLASH_FROM_THIS (This);
+
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+
+ // Set Write Enable
+ if (!EFI_ERROR (Status)) {
+ if (Instance->WriteEnableLatchRequired) {
+ Status = SetWel (Instance);
+ DEBUG ((DEBUG_ERROR, "%a: set Write Enable Error.\n", __func__));
+ ASSERT_EFI_ERROR (Status);
+ // Check not WIP & WEL enabled
+ Status = WaitWelNotWip (Instance);
+ }
+
+ // Write the Status Register
+ if (!EFI_ERROR (Status)) {
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ SPI_FLASH_WRSR,
+ SPI_FLASH_WRSR_DUMMY,
+ SPI_FLASH_WRSR_ADDR_BYTES,
+ FALSE,
+ 0,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_ONLY,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ 0,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Write data to the SPI flash.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine breaks up the write operation as necessary to write the data to
+ the SPI part.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] FlashAddress Address in the flash to start writing
+ @param[in] LengthInBytes Write length in bytes
+ @param[in] Buffer Address of a buffer containing the data
+
+ @retval EFI_SUCCESS The data was written successfully.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL, or
+ FlashAddress >= This->FlashSize, or
+ LengthInBytes > This->FlashSize - FlashAddress
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory to copy buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+WriteData (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 FlashAddress,
+ IN UINT32 LengthInBytes,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ SPI_NOR_FLASH_INSTANCE *Instance;
+ UINT32 ByteCounter;
+ UINT32 CurrentAddress;
+ UINT32 Length;
+ UINT32 BytesUntilBoundary;
+ UINT8 *CurrentBuffer;
+ UINT32 TransactionBufferLength;
+ UINT32 MaximumTransferBytes;
+ UINT32 SpiFlashPageSize;
+
+ DEBUG ((DEBUG_INFO, "%a: Entry: Write address = 0x%08x, Length = 0x%08x\n", __func__, FlashAddress, LengthInBytes));
+
+ Status = EFI_DEVICE_ERROR;
+ if ((Buffer == NULL) ||
+ (LengthInBytes == 0) ||
+ (FlashAddress >= This->FlashSize) ||
+ (LengthInBytes > This->FlashSize - FlashAddress))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance = SPI_NOR_FLASH_FROM_THIS (This);
+ MaximumTransferBytes = Instance->SpiIo->MaximumTransferBytes;
+ if (Instance->SfdpBasicFlashByteCount >= 11 * 4) {
+ // JESD216C spec DWORD 11
+ SpiFlashPageSize = 1 << Instance->SfdpBasicFlash->PageSize;
+ } else {
+ SpiFlashPageSize = 256;
+ }
+
+ CurrentBuffer = Buffer;
+ Length = 0;
+ for (ByteCounter = 0; ByteCounter < LengthInBytes;) {
+ CurrentAddress = FlashAddress + ByteCounter;
+ CurrentBuffer = Buffer + ByteCounter;
+ Length = LengthInBytes - ByteCounter;
+ // Length must be MaximumTransferBytes or less
+ if (Length > MaximumTransferBytes) {
+ Length = MaximumTransferBytes;
+ }
+
+ // Cannot cross SpiFlashPageSize boundary
+ BytesUntilBoundary = SpiFlashPageSize
+ - (CurrentAddress % SpiFlashPageSize);
+ if ((BytesUntilBoundary != 0) && (Length > BytesUntilBoundary)) {
+ Length = BytesUntilBoundary;
+ }
+
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Instance->WriteEnableLatchRequired) {
+ // Set Write Enable
+ Status = SetWel (Instance);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ // Check not WIP & WEL enabled
+ Status = WaitWelNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ // Write Data
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ SPI_FLASH_PP,
+ SPI_FLASH_PP_DUMMY,
+ SPI_FLASH_PP_ADDR_BYTES,
+ TRUE,
+ CurrentAddress,
+ Length,
+ CurrentBuffer
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_ONLY,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ 0,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Instance->WriteEnableLatchRequired) {
+ // Check not WIP & not WEL
+ Status = WaitNotWelNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ } else {
+ Status = WaitNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ ByteCounter += Length;
+ }
+
+ return Status;
+}
+
+/**
+ Efficiently erases blocks in the SPI flash.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine may use the combination of variable earse sizes to erase the
+ specified area accroding to the flash region.
+
+ @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data
+ structure.
+ @param[in] FlashAddress Address to start erasing
+ @param[in] BlockCount Number of blocks to erase. The block size is indicated
+ in EraseBlockBytes in EFI_SPI_NOR_FLASH_PROTOCOL.
+
+ @retval EFI_SUCCESS The erase was completed successfully.
+ @retval EFI_DEVICE_ERROR The flash devices has problems.
+ @retval EFI_INVALID_PARAMETER The given FlashAddress and/or BlockCount
+ is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+Erase (
+ IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This,
+ IN UINT32 FlashAddress,
+ IN UINT32 BlockCount
+ )
+{
+ EFI_STATUS Status;
+ SPI_NOR_FLASH_INSTANCE *Instance;
+ UINT8 Opcode;
+ UINT32 Dummy;
+ UINT32 ByteCounter;
+ UINT32 EraseLength;
+ UINT32 TotalEraseLength;
+ UINT32 CurrentAddress;
+ UINT32 TransactionBufferLength;
+ UINT32 BlockCountToErase;
+ UINT32 BlockSizeToErase;
+ UINT8 BlockEraseCommand;
+ SFDP_SECTOR_REGION_RECORD *FlashRegion;
+
+ DEBUG ((DEBUG_INFO, "%a: Entry: Erase address = 0x%08x, Block count = 0x%x\n", __func__, FlashAddress, BlockCount));
+
+ Status = EFI_DEVICE_ERROR;
+ Instance = SPI_NOR_FLASH_FROM_THIS (This);
+
+ // Get the region of this flash address.
+ Status = GetRegionByFlashAddress (Instance, FlashAddress, &FlashRegion);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, " Failed to get the flash region of this flash address.\n"));
+ ASSERT (FALSE);
+ return Status;
+ }
+
+ CurrentAddress = FlashAddress;
+ BlockCountToErase = BlockCount;
+ BlockSizeToErase = FlashRegion->SectorSize; // This is also the minimum block erase size.
+ TotalEraseLength = BlockCountToErase * FlashRegion->SectorSize;
+ if ((FlashAddress + TotalEraseLength) > (FlashRegion->RegionAddress + FlashRegion->RegionTotalSize)) {
+ DEBUG ((DEBUG_ERROR, " The blocks to erase exceeds the region boundary.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, " Region starting address: 0x%08x.\n", FlashRegion->RegionAddress));
+ DEBUG ((DEBUG_VERBOSE, " Region size : 0x%08x.\n", FlashRegion->RegionTotalSize));
+ DEBUG ((DEBUG_VERBOSE, " Region sector size : 0x%08x.\n", FlashRegion->SectorSize));
+ DEBUG ((DEBUG_VERBOSE, " Supported erase address bytes by device: 0x%02x.\n", Instance->SfdpBasicFlash->AddressBytes));
+ DEBUG ((DEBUG_VERBOSE, " (00: 3-Byte, 01: 3 or 4-Byte. 10: 4-Byte)\n"));
+
+ // Loop until all blocks are erased.
+ ByteCounter = 0;
+ while (ByteCounter < TotalEraseLength) {
+ CurrentAddress = FlashAddress + ByteCounter;
+
+ // Is this the whole device erase.
+ if (TotalEraseLength == This->FlashSize) {
+ Opcode = SPI_FLASH_CE;
+ Dummy = SPI_FLASH_CE_DUMMY;
+ EraseLength = TotalEraseLength;
+ DEBUG ((DEBUG_VERBOSE, " This is the chip erase.\n"));
+ } else {
+ //
+ // Get the erase block attributes.
+ //
+ Status = GetEraseBlockAttribute (
+ Instance,
+ FlashRegion,
+ CurrentAddress,
+ TotalEraseLength - ByteCounter,
+ &BlockSizeToErase,
+ &BlockCountToErase,
+ &BlockEraseCommand
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, " Failed to get erase block attribute.\n"));
+ ASSERT (FALSE);
+ }
+
+ Opcode = BlockEraseCommand;
+ Dummy = SPI_FLASH_BE_DUMMY;
+ EraseLength = BlockCountToErase * BlockSizeToErase;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " Erase command 0x%02x at adddress 0x%08x for length 0x%08x.\n",
+ BlockEraseCommand,
+ CurrentAddress,
+ EraseLength
+ ));
+ }
+
+ //
+ // Process the erase command.
+ //
+
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (Instance->WriteEnableLatchRequired) {
+ // Set Write Enable
+ Status = SetWel (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ // Check not WIP & WEL enabled
+ Status = WaitWelNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ // Erase Block
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ Opcode,
+ Dummy,
+ (UINT8)Instance->SfdpBasicFlash->AddressBytes,
+ TRUE,
+ CurrentAddress,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_ONLY,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ 0,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ break;
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "Erase command sucessfully.\n"));
+ }
+
+ if (Instance->WriteEnableLatchRequired) {
+ // Check not WIP & not WEL
+ Status = WaitNotWelNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ } else {
+ Status = WaitNotWip (Instance);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ ByteCounter += EraseLength;
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c
new file mode 100644
index 00000000000..00ba0a62a51
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c
@@ -0,0 +1,1772 @@
+/** @file
+ SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+ common functions.
+
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Revision Reference:
+ - JEDEC Standard, JESD216F.02
+ https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+
+ @par Glossary:
+ - SFDP - Serial Flash Discoverable Parameters
+ - PTP - Parameter Table Pointer
+**/
+
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/SpiConfiguration.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiNorFlash.h"
+#include "SpiNorFlashJedecSfdpInternal.h"
+
+/**
+ Build up the Fast Read capability entry and link it to
+ the linked list.
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+ @param[in] FastReadInstruction The string of fast read instruction.
+ @param[in] FastReadModeClk The string of fast read mode clock.
+ @param[in] FastReadDummyClk The string of fast read dummy clock.
+
+**/
+VOID
+CreateSpiFastReadTableEntry (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN UINT32 FastReadInstruction,
+ IN UINT32 FastReadModeClk,
+ IN UINT32 FastReadDummyClk
+ )
+{
+ SFPD_FAST_READ_CAPBILITY_RECORD *CapabilityEntry;
+
+ CapabilityEntry = AllocateZeroPool (sizeof (SFPD_FAST_READ_CAPBILITY_RECORD));
+ if (CapabilityEntry == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to create fast read table\n", __func__));
+ ASSERT (FALSE);
+ return;
+ }
+
+ InitializeListHead (&CapabilityEntry->NextFastReadCap);
+ CapabilityEntry->FastReadInstruction = (UINT8)FastReadInstruction;
+ CapabilityEntry->ModeClocks = (UINT8)FastReadModeClk;
+ CapabilityEntry->WaitStates = (UINT8)FastReadDummyClk;
+ InsertTailList (&Instance->FastReadTableList, &CapabilityEntry->NextFastReadCap);
+ DEBUG ((DEBUG_VERBOSE, "%a: Create and link table.\n", __func__));
+ DEBUG ((DEBUG_VERBOSE, " Instruction : 0x%x\n", FastReadInstruction));
+ DEBUG ((DEBUG_VERBOSE, " Mode bits : 0x%x\n", FastReadModeClk));
+ DEBUG ((DEBUG_VERBOSE, " Wait States (Dummy Clocks): 0x%x\n", FastReadDummyClk));
+}
+
+/**
+ Calculate erase type typical time.
+
+ @param[in] SfdpEraseTypicalTime Erase type typical time indicated in
+ Basic Flash Parameter Table.
+ EraseTypicalTime [0:4] - Count
+ EraseTypicalTime [5:6] - Unit
+ 00b: 1ms
+ 01b: 16ms
+ 10b: 128ms
+ 11b: 1s
+ @param[in] SfdpEraseTimeMultiplier Multiplier from erase typical time.
+ @param[out] EraseTypicalTime Pointer to receive Erase typical time in milliseconds.
+ @param[out] EraseTimeout Pointer to receive Erase timeout in milliseconds.
+
+ @retval Erase time in milliseconds.
+**/
+VOID
+CalculateEraseTiming (
+ IN UINT32 SfdpEraseTypicalTime,
+ IN UINT32 SfdpEraseTimeMultiplier,
+ OUT UINT32 *EraseTypicalTime,
+ OUT UINT64 *EraseTimeout
+ )
+{
+ UINT32 UnitInMs;
+
+ UnitInMs = (SfdpEraseTypicalTime & ERASE_TYPICAL_TIME_UNITS_MASK) >> ERASE_TYPICAL_TIME_BIT_POSITION;
+ switch (UnitInMs) {
+ case ERASE_TYPICAL_TIME_UNIT_1_MS_BITMAP:
+ UnitInMs = ERASE_TYPICAL_TIME_UNIT_1_MS;
+ break;
+
+ case ERASE_TYPICAL_TIME_UNIT_16_MS_BITMAP:
+ UnitInMs = ERASE_TYPICAL_TIME_UNIT_16_MS;
+ break;
+
+ case ERASE_TYPICAL_TIME_UNIT_128_MS_BITMAP:
+ UnitInMs = ERASE_TYPICAL_TIME_UNIT_128_MS;
+ break;
+
+ case ERASE_TYPICAL_TIME_UNIT_1000_MS_BITMAP:
+ UnitInMs = ERASE_TYPICAL_TIME_UNIT_1000_MS;
+ break;
+ default:
+ DEBUG ((DEBUG_ERROR, "%a: Unsupported Erase Typical time.\n", __func__));
+ ASSERT (FALSE);
+ }
+
+ *EraseTypicalTime = UnitInMs * ((SfdpEraseTypicalTime & ERASE_TYPICAL_TIME_COUNT_MASK) + 1);
+ *EraseTimeout = 2 * (SfdpEraseTimeMultiplier + 1) * *EraseTypicalTime;
+ return;
+}
+
+/**
+ Print out the erase type information.
+
+ @param[in] SupportedEraseType Pointer to SFDP_SUPPORTED_ERASE_TYPE_RECORD.
+**/
+VOID
+DebugPrintEraseType (
+ IN SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType
+ )
+{
+ DEBUG ((DEBUG_VERBOSE, " Erase Type %d\n", SupportedEraseType->EraseType));
+ DEBUG ((DEBUG_VERBOSE, " Erase Type instruction: 0x%x\n", SupportedEraseType->EraseInstruction));
+ DEBUG ((DEBUG_VERBOSE, " Erase size: 0x%x bytes\n", SupportedEraseType->EraseSizeInByte));
+ DEBUG ((DEBUG_VERBOSE, " Erase time: %d Milliseconds\n", SupportedEraseType->EraseTypicalTime));
+ DEBUG ((DEBUG_VERBOSE, " Erase timeout: %d Milliseconds:\n", SupportedEraseType->EraseTimeout));
+}
+
+/**
+ Insert supported erase type entry.
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+ @param[in] SupportedEraseType Pointer to SFDP_SUPPORTED_ERASE_TYPE_RECORD.
+**/
+VOID
+CreateEraseTypeEntry (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType
+ )
+{
+ InitializeListHead (&SupportedEraseType->NextEraseType);
+ InsertTailList (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType);
+
+ DEBUG ((DEBUG_VERBOSE, "%a: Erase Type 0x%x is supported:\n", __func__, SupportedEraseType->EraseType));
+ DebugPrintEraseType (SupportedEraseType);
+}
+
+/**
+ Build up the erase type tables.
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+
+**/
+VOID
+BuildUpEraseTypeTable (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType;
+
+ // Build up erase type 1 entry.
+ if (Instance->SfdpBasicFlash->Erase1Size != 0) {
+ SupportedEraseType = AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_TYPE_RECORD));
+ if (SupportedEraseType != NULL) {
+ SupportedEraseType->EraseType = SFDP_ERASE_TYPE_1;
+ SupportedEraseType->EraseInstruction = (UINT8)Instance->SfdpBasicFlash->Erase1Instr;
+ SupportedEraseType->EraseSizeInByte = (UINT32)1 << Instance->SfdpBasicFlash->Erase1Size;
+ CalculateEraseTiming (
+ Instance->SfdpBasicFlash->Erase1Time,
+ Instance->SfdpBasicFlash->EraseMultiplier,
+ &SupportedEraseType->EraseTypicalTime,
+ &SupportedEraseType->EraseTimeout
+ );
+ CreateEraseTypeEntry (Instance, SupportedEraseType);
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED_ERASE_TYPE_RECORD (Type 1).\n", __func__));
+ ASSERT (FALSE);
+ }
+ }
+
+ // Build up erase type 2 entry.
+ if (Instance->SfdpBasicFlash->Erase2Size != 0) {
+ SupportedEraseType = AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_TYPE_RECORD));
+ if (SupportedEraseType != NULL) {
+ SupportedEraseType->EraseType = SFDP_ERASE_TYPE_2;
+ SupportedEraseType->EraseInstruction = (UINT8)Instance->SfdpBasicFlash->Erase2Instr;
+ SupportedEraseType->EraseSizeInByte = (UINT32)1 << Instance->SfdpBasicFlash->Erase2Size;
+ CalculateEraseTiming (
+ Instance->SfdpBasicFlash->Erase2Time,
+ Instance->SfdpBasicFlash->EraseMultiplier,
+ &SupportedEraseType->EraseTypicalTime,
+ &SupportedEraseType->EraseTimeout
+ );
+ CreateEraseTypeEntry (Instance, SupportedEraseType);
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED_ERASE_TYPE_RECORD (Type 2).\n", __func__));
+ ASSERT (FALSE);
+ }
+ }
+
+ // Build up erase type 3 entry.
+ if (Instance->SfdpBasicFlash->Erase3Size != 0) {
+ SupportedEraseType = AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_TYPE_RECORD));
+ if (SupportedEraseType != NULL) {
+ SupportedEraseType->EraseType = SFDP_ERASE_TYPE_3;
+ SupportedEraseType->EraseInstruction = (UINT8)Instance->SfdpBasicFlash->Erase3Instr;
+ SupportedEraseType->EraseSizeInByte = (UINT32)1 << Instance->SfdpBasicFlash->Erase3Size;
+ CalculateEraseTiming (
+ Instance->SfdpBasicFlash->Erase3Time,
+ Instance->SfdpBasicFlash->EraseMultiplier,
+ &SupportedEraseType->EraseTypicalTime,
+ &SupportedEraseType->EraseTimeout
+ );
+ CreateEraseTypeEntry (Instance, SupportedEraseType);
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED_ERASE_TYPE_RECORD (Type 3).\n", __func__));
+ ASSERT (FALSE);
+ }
+ }
+
+ // Build up erase type 4 entry.
+ if (Instance->SfdpBasicFlash->Erase4Size != 0) {
+ SupportedEraseType = AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_TYPE_RECORD));
+ if (SupportedEraseType != NULL) {
+ SupportedEraseType->EraseType = SFDP_ERASE_TYPE_4;
+ SupportedEraseType->EraseInstruction = (UINT8)Instance->SfdpBasicFlash->Erase4Instr;
+ SupportedEraseType->EraseSizeInByte = (UINT32)1 << Instance->SfdpBasicFlash->Erase4Size;
+ CalculateEraseTiming (
+ Instance->SfdpBasicFlash->Erase4Time,
+ Instance->SfdpBasicFlash->EraseMultiplier,
+ &SupportedEraseType->EraseTypicalTime,
+ &SupportedEraseType->EraseTimeout
+ );
+ CreateEraseTypeEntry (Instance, SupportedEraseType);
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED_ERASE_TYPE_RECORD (Type 4).\n", __func__));
+ ASSERT (FALSE);
+ }
+ }
+}
+
+/**
+ This function check if the erase type is one of the target erase types.
+
+ @param[in] EraseType The erase type.
+ @param[in] TargetTypeNum Number of target search types.
+ @param[in] TargetTypes Target types.
+
+
+ @retval TRUE Yes, this is the target erase type.
+ @retval FALSE No, this is not the target erase type.
+
+**/
+BOOLEAN
+IsTargetEraseType (
+ IN UINT16 EraseType,
+ IN UINT8 TargetTypeNum,
+ IN UINT8 *TargetTypes
+ )
+{
+ UINT8 Index;
+
+ for (Index = 0; Index < TargetTypeNum; Index++) {
+ if (EraseType == *(TargetTypes + Index)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Search the erase type record according to the given search type and value.
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+ @param[in] SearchType Search type.
+ @param[in] SearchValue The value of according to search type.
+ - For SearchEraseTypeByCommand:
+ SearchValue is the erase instruction.
+ - For SearchEraseTypeBySize:
+ SearchValue is the erase block size.
+ - For SearchEraseTypeBySmallestSize:
+ SearchValue is not used.
+ - For SearchEraseTypeByBiggestSize:
+ SearchValue is not used.
+ @param[in] SupportedTypeTargetNum Only search the specific erase types.
+ @param[in] SupportedTypeTarget Pointer to SupportedTypeTargetNum of
+ supported erase types.
+ @param[out] EraseTypeRecord Pointer to receive the erase type record.
+
+ @retval EFI_SUCCESS Pointer to erase type record is returned.
+ EFI_INVALID_PARAMETER Invalid SearchType.
+ EFI_NOT_FOUND Erase type not found.
+**/
+EFI_STATUS
+GetEraseTypeRecord (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN SFDP_SEARCH_ERASE_TYPE SearchType,
+ IN UINT32 SearchValue,
+ IN UINT8 SupportedTypeTargetNum,
+ IN UINT8 *SupportedTypeTarget OPTIONAL,
+ OUT SFDP_SUPPORTED_ERASE_TYPE_RECORD **EraseTypeRecord
+ )
+{
+ SFDP_SUPPORTED_ERASE_TYPE_RECORD *EraseType;
+ UINT32 ValueToCompare;
+ BOOLEAN ExitSearching;
+
+ if (IsListEmpty (&Instance->SupportedEraseTypes)) {
+ return EFI_NOT_FOUND;
+ }
+
+ *EraseTypeRecord = NULL;
+
+ //
+ // Initial the comapre value.
+ //
+ switch (SearchType) {
+ case SearchEraseTypeByType:
+ case SearchEraseTypeByCommand:
+ case SearchEraseTypeBySize:
+ break;
+ case SearchEraseTypeBySmallestSize:
+ ValueToCompare = (UINT32)-1;
+ break;
+ case SearchEraseTypeByBiggestSize:
+ ValueToCompare = 0;
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ExitSearching = FALSE;
+ EraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetFirstNode (&Instance->SupportedEraseTypes);
+ while (TRUE) {
+ if ((SupportedTypeTarget == NULL) || IsTargetEraseType (EraseType->EraseType, SupportedTypeTargetNum, SupportedTypeTarget)) {
+ switch (SearchType) {
+ case SearchEraseTypeByType:
+ if (EraseType->EraseType == SearchValue) {
+ *EraseTypeRecord = EraseType;
+ ExitSearching = TRUE;
+ }
+
+ break;
+
+ case SearchEraseTypeBySize:
+ if (EraseType->EraseSizeInByte == SearchValue) {
+ *EraseTypeRecord = EraseType;
+ ExitSearching = TRUE;
+ }
+
+ break;
+
+ case SearchEraseTypeByCommand:
+ if (EraseType->EraseInstruction == (UINT8)SearchValue) {
+ *EraseTypeRecord = EraseType;
+ ExitSearching = TRUE;
+ }
+
+ break;
+
+ case SearchEraseTypeBySmallestSize:
+ if (EraseType->EraseSizeInByte < ValueToCompare) {
+ ValueToCompare = EraseType->EraseSizeInByte;
+ *EraseTypeRecord = EraseType;
+ }
+
+ break;
+
+ case SearchEraseTypeByBiggestSize:
+ if (EraseType->EraseSizeInByte > ValueToCompare) {
+ ValueToCompare = EraseType->EraseSizeInByte;
+ *EraseTypeRecord = EraseType;
+ }
+
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (IsNodeAtEnd (&Instance->SupportedEraseTypes, &EraseType->NextEraseType) || ExitSearching) {
+ break;
+ }
+
+ EraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNextNode (&Instance->SupportedEraseTypes, &EraseType->NextEraseType);
+ }
+
+ if (*EraseTypeRecord == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the erase block attribute for the target address.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+ @param[in] FlashRegion The region the flash address belong.
+ @param[in] FlashAddress The target flash address.
+ @param[in] RemainingSize Remaining size to erase.
+ @param[in, out] BlockSizeToErase Input - The block erase size for this continious blocks.
+ Output - The determined block size for erasing.
+ @param[in, out] BlockCountToErase Input - The expected blocks to erase.
+ Output - The determined number of blocks to erase.
+ @param[out] BlockEraseCommand The erase command used for this continious blocks.
+
+ @retval EFI_SUCCESS The erase block attribute is returned.
+ @retval EFI_DEVICE_ERROR No valid SFDP discovered.
+ @retval EFI_NOT_FOUND No valud erase block attribute found.
+
+**/
+EFI_STATUS
+GetEraseBlockAttribute (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN SFDP_SECTOR_REGION_RECORD *FlashRegion,
+ IN UINT32 FlashAddress,
+ IN UINT32 RemainingSize,
+ IN OUT UINT32 *BlockSizeToErase,
+ IN OUT UINT32 *BlockCountToErase,
+ OUT UINT8 *BlockEraseCommand
+ )
+{
+ EFI_STATUS Status;
+ SFDP_SUPPORTED_ERASE_TYPE_RECORD *EraseType;
+ UINT32 EraseSize;
+
+ DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__));
+
+ for (EraseSize = SIZE_2GB; EraseSize != 0; EraseSize = EraseSize >> 1) {
+ Status = GetEraseTypeRecord (Instance, SearchEraseTypeBySize, EraseSize, 0, NULL, &EraseType);
+ if (!EFI_ERROR (Status)) {
+ // Validate this erase type.
+ if (((FlashAddress & (EraseType->EraseSizeInByte - 1)) == 0) &&
+ (RemainingSize >= EraseType->EraseSizeInByte))
+ {
+ *BlockSizeToErase = EraseType->EraseSizeInByte;
+ *BlockCountToErase = 1;
+ *BlockEraseCommand = EraseType->EraseInstruction;
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ }
+
+ if (EraseType == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, " Erase address at 0x%08x.\n", FlashAddress));
+ DEBUG ((DEBUG_VERBOSE, " - Erase block size : 0x%08x.\n", *BlockSizeToErase));
+ DEBUG ((DEBUG_VERBOSE, " - Erase block count : 0x%08x.\n", *BlockCountToErase));
+ DEBUG ((DEBUG_VERBOSE, " - Erase block command: 0x%02x.\n", *BlockEraseCommand));
+ DEBUG ((DEBUG_VERBOSE, " - Remaining size to erase: 0x%08x.\n", RemainingSize));
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the erase block attribute for the target address.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+ @param[in] FlashAddress The target flash address.
+ @param[out] FlashRegion The target flash address.
+
+ @retval EFI_SUCCESS The region is returned.
+ @retval EFI_INVALID_PARAMETER FlashAddress is not belong to any region.
+ @retval Otherwise Other errors.
+
+**/
+EFI_STATUS
+GetRegionByFlashAddress (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN UINT32 FlashAddress,
+ OUT SFDP_SECTOR_REGION_RECORD **FlashRegion
+ )
+{
+ SFDP_SECTOR_MAP_RECORD *SectorMapRecord;
+ SFDP_SECTOR_REGION_RECORD *RegionRecord;
+
+ DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__));
+
+ SectorMapRecord = Instance->CurrentSectorMap;
+ if (SectorMapRecord == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ RegionRecord = (SFDP_SECTOR_REGION_RECORD *)GetFirstNode (&SectorMapRecord->RegionList);
+ while (TRUE) {
+ if ((FlashAddress >= RegionRecord->RegionAddress) &&
+ (FlashAddress < RegionRecord->RegionAddress + RegionRecord->RegionTotalSize))
+ {
+ *FlashRegion = RegionRecord;
+ return EFI_SUCCESS;
+ }
+
+ if (IsNodeAtEnd (&SectorMapRecord->RegionList, &RegionRecord->NextRegion)) {
+ break;
+ }
+
+ RegionRecord = (SFDP_SECTOR_REGION_RECORD *)GetNextNode (&SectorMapRecord->RegionList, &RegionRecord->NextRegion);
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ Build up the Fast Read capability tables. The earlier linked table
+ in the linked list has the faster transfer.
+ NOTE: 1. The Quad input instructions mentioned in 21th DWOWRD
+ are not considered yet.
+ 2. Maximum speed options for certain Fast Read modes are
+ not considered yet. (e.g., 8D-8D-8D or 4S-4D-4D)
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+
+**/
+VOID
+BuildUpFastReadTable (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ // Build up the standard Fast Read
+ // This will be first picked for the ReadData.
+ // TODO: The mechanism to choose the advance fast read
+ // is not determined yet in this version of
+ // SpiNorFlash driver.
+ CreateSpiFastReadTableEntry (
+ Instance,
+ SPI_FLASH_FAST_READ,
+ 0,
+ SPI_FLASH_FAST_READ_DUMMY * 8
+ );
+
+ // Build up Fast Read table 1S-1S-4S
+ if (Instance->SfdpBasicFlash->FastRead114 != 0) {
+ CreateSpiFastReadTableEntry (
+ Instance,
+ Instance->SfdpBasicFlash->FastRead114Instr,
+ Instance->SfdpBasicFlash->FastRead114ModeClk,
+ Instance->SfdpBasicFlash->FastRead114Dummy
+ );
+ }
+
+ // Build up Fast Read table 1S-2S-2S
+ if (Instance->SfdpBasicFlash->FastRead122 != 0) {
+ CreateSpiFastReadTableEntry (
+ Instance,
+ Instance->SfdpBasicFlash->FastRead122Instr,
+ Instance->SfdpBasicFlash->FastRead122ModeClk,
+ Instance->SfdpBasicFlash->FastRead122Dummy
+ );
+ }
+
+ // Build up Fast Read table 2S-2S-2S
+ if (Instance->SfdpBasicFlash->FastRead222 != 0) {
+ CreateSpiFastReadTableEntry (
+ Instance,
+ Instance->SfdpBasicFlash->FastRead222Instr,
+ Instance->SfdpBasicFlash->FastRead222ModeClk,
+ Instance->SfdpBasicFlash->FastRead222Dummy
+ );
+ }
+
+ // Build up Fast Read table 1S-4S-4S
+ if (Instance->SfdpBasicFlash->FastRead144 != 0) {
+ CreateSpiFastReadTableEntry (
+ Instance,
+ Instance->SfdpBasicFlash->FastRead144Instr,
+ Instance->SfdpBasicFlash->FastRead144ModeClk,
+ Instance->SfdpBasicFlash->FastRead144Dummy
+ );
+ }
+
+ // Build up Fast Read table 4S-4S-4S
+ if (Instance->SfdpBasicFlash->FastRead444 != 0) {
+ CreateSpiFastReadTableEntry (
+ Instance,
+ Instance->SfdpBasicFlash->FastRead444Instr,
+ Instance->SfdpBasicFlash->FastRead444ModeClk,
+ Instance->SfdpBasicFlash->FastRead444Dummy
+ );
+ }
+
+ // Build up Fast Read table 1S-1S-8S
+ if (Instance->SfdpBasicFlash->FastRead118Instr != 0) {
+ CreateSpiFastReadTableEntry (
+ Instance,
+ Instance->SfdpBasicFlash->FastRead118Instr,
+ Instance->SfdpBasicFlash->FastRead118ModeClk,
+ Instance->SfdpBasicFlash->FastRead118Dummy
+ );
+ }
+
+ // Build up Fast Read table 1S-8S-8S
+ if (Instance->SfdpBasicFlash->FastRead188Instr != 0) {
+ CreateSpiFastReadTableEntry (
+ Instance,
+ Instance->SfdpBasicFlash->FastRead188Instr,
+ Instance->SfdpBasicFlash->FastRead188ModeClk,
+ Instance->SfdpBasicFlash->FastRead188Dummy
+ );
+ }
+}
+
+/**
+ This function sets up the erase types supported
+ by this region.
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+ @param[in] RegionRecord Pointer to SFDP_SECTOR_REGION_RECORD of this
+ regions.
+ @retval EFI_SUCCESS Current sector map configuration is determined.
+ EFI_DEVICE_ERROR Current sector map configuration is not found.
+
+**/
+EFI_STATUS
+SetupRegionEraseInfo (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN SFDP_SECTOR_REGION_RECORD *RegionRecord
+ )
+{
+ SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType;
+ UINT32 MinimumEraseSize;
+
+ if (IsListEmpty (&Instance->SupportedEraseTypes)) {
+ DEBUG ((DEBUG_ERROR, "%a: No erase type suppoted on the flash device.\n", __func__));
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ MinimumEraseSize = (UINT32)-1;
+ SupportedEraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetFirstNode (&Instance->SupportedEraseTypes);
+ while (TRUE) {
+ RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = (UINT8)SupportedEraseType->EraseType;
+ RegionRecord->SupportedEraseTypeNum++;
+ RegionRecord->EraseTypeBySizeBitmap |= SupportedEraseType->EraseSizeInByte;
+ if (MinimumEraseSize > SupportedEraseType->EraseSizeInByte) {
+ MinimumEraseSize = SupportedEraseType->EraseSizeInByte;
+ }
+
+ if (IsNodeAtEnd (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType)) {
+ break;
+ }
+
+ SupportedEraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNextNode (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType);
+ }
+
+ RegionRecord->SectorSize = MinimumEraseSize;
+ RegionRecord->RegionTotalSize = Instance->FlashDeviceSize;
+ RegionRecord->RegionSectors = RegionRecord->RegionTotalSize / RegionRecord->SectorSize;
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a single flash sector map.
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+ @retval EFI_SUCCESS Current sector map configuration is determined.
+ EFI_DEVICE_ERROR Current sector map configuration is not found.
+
+**/
+EFI_STATUS
+CreateSingleFlashSectorMap (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ SFDP_SECTOR_MAP_RECORD *SectorMapRecord;
+ SFDP_SECTOR_REGION_RECORD *RegionRecord;
+ UINTN EraseIndex;
+
+ DEBUG ((DEBUG_VERBOSE, "%a: Entry:\n", __func__));
+ SectorMapRecord = (SFDP_SECTOR_MAP_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_MAP_RECORD));
+ if (SectorMapRecord == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DETECTION_RECORD.\n", __func__));
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Create SFDP_SECTOR_MAP_RECORD.
+ InitializeListHead (&SectorMapRecord->NextDescriptor);
+ InitializeListHead (&SectorMapRecord->RegionList);
+ SectorMapRecord->ConfigurationId = 0;
+ SectorMapRecord->RegionCount = 1;
+ InsertTailList (&Instance->ConfigurationMapList, &SectorMapRecord->NextDescriptor);
+ DEBUG ((DEBUG_VERBOSE, " Sector map configurations ID : 0x%x\n", SectorMapRecord->ConfigurationId));
+ DEBUG ((DEBUG_VERBOSE, " Sector map configurations regions: %d\n", SectorMapRecord->RegionCount));
+
+ // Create SFDP_SECTOR_MAP_RECORD region record.
+ RegionRecord = (SFDP_SECTOR_REGION_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_REGION_RECORD));
+ if (RegionRecord == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_REGION_RECORD.\n", __func__));
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeListHead (&RegionRecord->NextRegion);
+
+ RegionRecord->RegionAddress = 0;
+ //
+ // Setup erase information in the region record.
+ //
+ SetupRegionEraseInfo (Instance, RegionRecord);
+
+ InsertTailList (&SectorMapRecord->RegionList, &RegionRecord->NextRegion);
+
+ Instance->CurrentSectorMap = SectorMapRecord;
+
+ DEBUG ((DEBUG_VERBOSE, " Region totoal size : 0x%x\n", RegionRecord->RegionTotalSize));
+ DEBUG ((DEBUG_VERBOSE, " Region sector size : 0x%x\n", RegionRecord->SectorSize));
+ DEBUG ((DEBUG_VERBOSE, " Region sectors : 0x%x\n", RegionRecord->RegionSectors));
+
+ for (EraseIndex = 0; EraseIndex < RegionRecord->SupportedEraseTypeNum; EraseIndex++) {
+ DEBUG ((DEBUG_VERBOSE, " Region erase type supported: 0x%x\n", RegionRecord->SupportedEraseType[EraseIndex]));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set EraseBlockBytes in SPI NOR Flash Protocol
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS The erase block size is returned.
+ @retval Otherwise Failed to get erase block size.
+
+**/
+EFI_STATUS
+SetSectorEraseBlockSize (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ SFDP_SUPPORTED_ERASE_TYPE_RECORD *EraseTypeRecord;
+
+ // Use the smallest size for the sector erase.
+ Status = GetEraseTypeRecord (Instance, SearchEraseTypeBySmallestSize, 0, 0, NULL, &EraseTypeRecord);
+ if (!EFI_ERROR (Status)) {
+ Instance->Protocol.EraseBlockBytes = EraseTypeRecord->EraseSizeInByte;
+ DEBUG ((DEBUG_VERBOSE, " Erase block size = 0x%08x\n", EraseTypeRecord->EraseSizeInByte));
+ }
+
+ return Status;
+}
+
+/**
+ Get the current sector map configuration.
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS Current sector map configuration is determined.
+ EFI_DEVICE_ERROR Current sector map configuration is not found.
+
+**/
+EFI_STATUS
+GetCurrentSectorMapConfiguration (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TransactionBufferLength;
+ UINT8 AddressLength;
+ BOOLEAN UseAddress;
+ UINT32 DummyBytes;
+ UINT8 ReturnByte;
+ UINT8 ConfigurationId;
+ SFDP_SECTOR_MAP_RECORD *SectorMap;
+ SFDP_SECTOR_MAP_DETECTION_RECORD *CommandEntry;
+
+ Instance->CurrentSectorMap = NULL;
+ if (!Instance->ConfigurationCommandsNeeded) {
+ // No command needed measn only one configuration for the flash device sector map.
+ Instance->CurrentSectorMap = (SFDP_SECTOR_MAP_RECORD *)GetFirstNode (&Instance->ConfigurationMapList);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Send the command to collect interest bit.
+ //
+ ConfigurationId = 0;
+ CommandEntry = (SFDP_SECTOR_MAP_DETECTION_RECORD *)GetFirstNode (&Instance->ConfigurationCommandList);
+ while (TRUE) {
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+
+ // Read configuration byte.
+ AddressLength = SPI_ADDR_3BYTE_ONLY;
+ DummyBytes = 1;
+ if (CommandEntry->CommandAddressLength == SpdfConfigurationCommandAddress4Byte) {
+ AddressLength = SPI_ADDR_4BYTE_ONLY;
+ DummyBytes = 0;
+ }
+
+ UseAddress = TRUE;
+ if (CommandEntry->CommandAddress == SpdfConfigurationCommandAddressNone) {
+ UseAddress = FALSE;
+ }
+
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ CommandEntry->CommandInstruction,
+ DummyBytes,
+ AddressLength,
+ UseAddress,
+ CommandEntry->CommandAddress,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_THEN_READ,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ 1,
+ &ReturnByte
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fails to read the configuration byte.\n", __func__));
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Retrieve the interest bit.
+ //
+ if ((ReturnByte & CommandEntry->ConfigurationBitMask) != 0) {
+ ConfigurationId |= 0x01;
+ }
+
+ if (IsNodeAtEnd (&Instance->ConfigurationCommandList, &CommandEntry->NextCommand)) {
+ break;
+ }
+
+ CommandEntry = (SFDP_SECTOR_MAP_DETECTION_RECORD *)GetNextNode (&Instance->ConfigurationCommandList, &CommandEntry->NextCommand);
+ ConfigurationId = ConfigurationId << 1;
+ }
+
+ //
+ // Now we have current activated configuration ID in ConfigurationId.
+ // Walk through ConfigurationMapList to record the activated flash sector
+ // map configuration.
+ //
+ SectorMap = (SFDP_SECTOR_MAP_RECORD *)GetFirstNode (&Instance->ConfigurationMapList);
+ while (TRUE) {
+ if (SectorMap->ConfigurationId == ConfigurationId) {
+ Instance->CurrentSectorMap = SectorMap;
+ break;
+ }
+
+ if (IsNodeAtEnd (&Instance->ConfigurationMapList, &SectorMap->NextDescriptor)) {
+ break;
+ }
+
+ SectorMap = (SFDP_SECTOR_MAP_RECORD *)GetNextNode (&Instance->ConfigurationMapList, &SectorMap->NextDescriptor);
+ }
+
+ if (Instance->CurrentSectorMap == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Activated flash sector map is not found!\n", __func__));
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build sector map configurations.
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS Records of sector map configuration command and map
+ descriptor are built up successfully.
+ EFI_OUT_OF_RESOURCES Not enough memory resource.
+ EFI_DEVICE_ERROR SFDP Sector Map Parameter is not
+ constructed correctly.
+
+**/
+EFI_STATUS
+BuildSectorMapCommandAndMap (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ SFDP_SECTOR_MAP_TABLE *SfdpSectorMapTable;
+ SFDP_SECTOR_CONFIGURATION_COMMAND *SfdpDetectionCommand;
+ SFDP_SECTOR_MAP_DETECTION_RECORD *CommandEntry;
+ SFDP_SECTOR_CONFIGURATION_MAP *SfdpConfigurationMap;
+ SFDP_SECTOR_MAP_RECORD *SectorMapRecord;
+ SFDP_SECTOR_REGION *SpdfSectorRegion;
+ SFDP_SECTOR_REGION_RECORD *RegionRecord;
+ SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType;
+ UINT8 RegionCount;
+ UINT8 EraseTypeCount;
+ UINT32 MinimumEraseSize;
+ UINT32 RegionAddress;
+
+ SfdpSectorMapTable = Instance->SfdpFlashSectorMap;
+ SfdpConfigurationMap = &SfdpSectorMapTable->ConfigurationMap;
+ SfdpDetectionCommand = &SfdpSectorMapTable->ConfigurationCommand;
+
+ if (SfdpSectorMapTable->GenericHeader.DescriptorType == SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_MAP) {
+ // No configuration detection commands are needs.
+ Instance->ConfigurationCommandsNeeded = FALSE;
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "%a: Sector map configuration detection command is needed\n", __func__));
+ Instance->ConfigurationCommandsNeeded = TRUE;
+
+ // Go through the section map detection commands.
+ while (TRUE) {
+ CommandEntry = (SFDP_SECTOR_MAP_DETECTION_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_MAP_DETECTION_RECORD));
+ if (CommandEntry == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DETECTION_RECORD.\n", __func__));
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeListHead (&CommandEntry->NextCommand);
+ CommandEntry->CommandAddress = SfdpDetectionCommand->CommandAddress;
+ CommandEntry->CommandAddressLength = (SPDF_CONFIGURATION_COMMAND_ADDR_LENGTH)SfdpDetectionCommand->DetectionCommandAddressLen;
+ CommandEntry->CommandInstruction = (UINT8)SfdpDetectionCommand->DetectionInstruction;
+ CommandEntry->ConfigurationBitMask = (UINT8)SfdpDetectionCommand->ReadDataMask;
+ CommandEntry->LatencyInClock = (UINT8)SfdpDetectionCommand->DetectionLatency;
+ InsertTailList (&Instance->ConfigurationCommandList, &CommandEntry->NextCommand);
+ DEBUG ((DEBUG_VERBOSE, " Command instruction : 0x%x\n", CommandEntry->CommandInstruction));
+ DEBUG ((DEBUG_VERBOSE, " Bit selection : 0x%x\n", CommandEntry->ConfigurationBitMask));
+ DEBUG ((DEBUG_VERBOSE, " Command address : 0x%x\n", CommandEntry->CommandAddress));
+ DEBUG ((DEBUG_VERBOSE, " Command address length: %d\n", CommandEntry->CommandAddressLength));
+ DEBUG ((DEBUG_VERBOSE, " Command latency clocks: %d\n\n", CommandEntry->LatencyInClock));
+ if (SfdpDetectionCommand->DescriptorEnd == SFDP_SECTOR_MAP_TABLE_ENTRY_LAST) {
+ break;
+ }
+
+ SfdpDetectionCommand++;
+ }
+
+ SfdpConfigurationMap = (SFDP_SECTOR_CONFIGURATION_MAP *)SfdpDetectionCommand++;
+ }
+
+ //
+ // Go through the region table pointed in SfdpConfigurationMap.
+ //
+ if (SfdpConfigurationMap->DescriptorType != SFDP_SECTOR_MAP_TABLE_ENTRY_TYPE_MAP) {
+ DEBUG ((DEBUG_ERROR, "%a: Incorrect format of Sector Map Parameter.\n", __func__));
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ while (TRUE) {
+ DEBUG ((DEBUG_VERBOSE, "%a: Sector map configurations:\n", __func__));
+ SectorMapRecord = (SFDP_SECTOR_MAP_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_MAP_RECORD));
+ if (SectorMapRecord == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DETECTION_RECORD.\n", __func__));
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeListHead (&SectorMapRecord->NextDescriptor);
+ InitializeListHead (&SectorMapRecord->RegionList);
+ SectorMapRecord->ConfigurationId = (UINT8)SfdpConfigurationMap->ConfigurationID;
+ SectorMapRecord->RegionCount = (UINT8)SfdpConfigurationMap->RegionCount;
+ InsertTailList (&Instance->ConfigurationMapList, &SectorMapRecord->NextDescriptor);
+ DEBUG ((DEBUG_VERBOSE, " Sector map configurations ID : 0x%x\n", SectorMapRecord->ConfigurationId));
+ DEBUG ((DEBUG_VERBOSE, " Sector map configurations regions: %d\n", SectorMapRecord->RegionCount));
+ SpdfSectorRegion = (SFDP_SECTOR_REGION *)SfdpConfigurationMap + 1;
+ RegionAddress = 0;
+ for (RegionCount = 0; RegionCount < SectorMapRecord->RegionCount; RegionCount++) {
+ RegionRecord = (SFDP_SECTOR_REGION_RECORD *)AllocateZeroPool (sizeof (SFDP_SECTOR_REGION_RECORD));
+ if (RegionRecord == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DETECTION_RECORD.\n", __func__));
+ ASSERT (FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ InitializeListHead (&RegionRecord->NextRegion);
+ RegionRecord->RegionTotalSize = (SpdfSectorRegion->RegionSize + 1) * SFDP_SECTOR_REGION_SIZE_UNIT;
+ //
+ // Construct erase type supported for this region.
+ //
+ if (SpdfSectorRegion->EraseType1 != 0) {
+ RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = SFDP_ERASE_TYPE_1;
+ RegionRecord->SupportedEraseTypeNum++;
+ }
+
+ if (SpdfSectorRegion->EraseType2 != 0) {
+ RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = SFDP_ERASE_TYPE_2;
+ RegionRecord->SupportedEraseTypeNum++;
+ }
+
+ if (SpdfSectorRegion->EraseType3 != 0) {
+ RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = SFDP_ERASE_TYPE_3;
+ RegionRecord->SupportedEraseTypeNum++;
+ }
+
+ if (SpdfSectorRegion->EraseType4 != 0) {
+ RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = SFDP_ERASE_TYPE_4;
+ RegionRecord->SupportedEraseTypeNum++;
+ }
+
+ //
+ // Calculate the sector size and total sectors.
+ //
+ if (IsListEmpty (&Instance->SupportedEraseTypes)) {
+ DEBUG ((DEBUG_ERROR, "%a: No erase type suppoted on the flash device.\n", __func__));
+ ASSERT (FALSE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ MinimumEraseSize = (UINT32)-1;
+ for (EraseTypeCount = 0; EraseTypeCount < RegionRecord->SupportedEraseTypeNum++; EraseTypeCount++) {
+ //
+ // Walk through Instance->SupportedEraseTypes to find the matching erase type and
+ // Use the minimum erase size as the sector size;
+ //
+ SupportedEraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetFirstNode (&Instance->SupportedEraseTypes);
+ while (TRUE) {
+ if (RegionRecord->SupportedEraseType[EraseTypeCount] == SupportedEraseType->EraseType) {
+ // Set erase size bitmap.
+ RegionRecord->EraseTypeBySizeBitmap |= SupportedEraseType->EraseSizeInByte;
+
+ if (MinimumEraseSize > SupportedEraseType->EraseSizeInByte) {
+ MinimumEraseSize = SupportedEraseType->EraseSizeInByte;
+ break;
+ }
+ }
+
+ if (IsNodeAtEnd (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType)) {
+ break;
+ }
+
+ SupportedEraseType = (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNextNode (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType);
+ }
+ }
+
+ RegionRecord->SectorSize = MinimumEraseSize;
+ RegionRecord->RegionSectors = RegionRecord->RegionTotalSize / RegionRecord->SectorSize;
+ RegionRecord->RegionAddress = RegionAddress;
+
+ // Insert to link.
+ InsertTailList (&SectorMapRecord->RegionList, &RegionRecord->NextRegion);
+ DEBUG ((DEBUG_VERBOSE, " Region: %d\n", RegionCount));
+ DEBUG ((DEBUG_VERBOSE, " Region totoal size: 0x%x\n", RegionRecord->RegionTotalSize));
+ DEBUG ((DEBUG_VERBOSE, " Region sector size: 0x%x\n", RegionRecord->SectorSize));
+ DEBUG ((DEBUG_VERBOSE, " Region sectors : 0x%x\n", RegionRecord->RegionSectors));
+ DEBUG ((DEBUG_VERBOSE, " Region erase supported bitmap: 0x%x\n", RegionRecord->EraseTypeBySizeBitmap));
+
+ SpdfSectorRegion++;
+ RegionAddress += RegionRecord->RegionTotalSize;
+ }
+
+ if (SfdpConfigurationMap->DescriptorEnd == SFDP_SECTOR_MAP_TABLE_ENTRY_LAST) {
+ break;
+ }
+
+ SfdpConfigurationMap = (SFDP_SECTOR_CONFIGURATION_MAP *)SpdfSectorRegion;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This routine get Write Enable latch command.
+
+ @param[in] Instance SPI Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+
+**/
+VOID
+GetWriteEnableCommand (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ //
+ // Set Wrtie Enable command.
+ //
+ Instance->WriteEnableLatchRequired = TRUE;
+ Instance->WriteEnableLatchCommand = SPI_FLASH_WREN;
+ if (Instance->SfdpBasicFlash->VolatileStatusBlockProtect == 1) {
+ if (Instance->SfdpBasicFlash->WriteEnableVolatileStatus == 0) {
+ Instance->WriteEnableLatchCommand = SPI_FLASH_WREN_50H;
+ }
+ }
+
+ DEBUG ((DEBUG_ERROR, "%a: Use Write Enable Command 0x%x.\n", __func__, Instance->WriteEnableLatchCommand));
+}
+
+/**
+ This routine returns the desired Fast Read mode.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+ @param[in,out] FastReadInstruction Fast Read instruction, the input is
+ the default value.
+ @param[in,out] FastReadModeBits The operational mode bits.
+ @param[in,out] FastReadDummyClocks Fast Read wait state (Dummy clocks), the
+ input is the default value.
+ @param[out] FastReadStr Pointer to retrieve the human readable string
+ of fast read mode.
+ @retval EFI_SUCCESS The parameters are updated.
+ @retval EFI_NOT_FOUND No desired Fas Read mode found.
+
+**/
+EFI_STATUS
+GetFastReadParameter (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN OUT UINT8 *FastReadInstruction,
+ IN OUT UINT8 *FastReadModeBits,
+ IN OUT UINT8 *FastReadDummyClocks
+ )
+{
+ SFPD_FAST_READ_CAPBILITY_RECORD *FastReadEntry;
+
+ if (IsListEmpty (&Instance->FastReadTableList)) {
+ return EFI_NOT_FOUND;
+ }
+
+ FastReadEntry = (SFPD_FAST_READ_CAPBILITY_RECORD *)GetFirstNode (&Instance->FastReadTableList);
+ *FastReadInstruction = FastReadEntry->FastReadInstruction;
+ *FastReadDummyClocks = FastReadEntry->WaitStates;
+ *FastReadModeBits = FastReadEntry->ModeClocks;
+
+ //
+ // *FastReadOperationClock may be replaced by 8D-8D-8D or 4S-4D-4D Fast Read
+ // mode clock operation mode. Which is not cosidered in the implementation yet.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the flash device size from SFDP Basic Flash Parameter Table DWORD 2
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and
+ EFI_SPI_IO_PROTOCOL.
+
+ @retval UINT32 Flash device size in byte, zero indicates error.
+
+**/
+UINT32
+SfdpGetFlashSize (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ if (Instance == NULL) {
+ return 0;
+ }
+
+ if ((Instance->SfdpBasicFlash->Density & SFDP_FLASH_MEMORY_DENSITY_4GBIT) == 0) {
+ //
+ // The flash device size is <= 256MB.
+ //
+ return (Instance->SfdpBasicFlash->Density + 1) / 8;
+ }
+
+ //
+ // The flash deivce size is >= 512MB.
+ // Bit [0:30] defines 'N' where the density is computed as 2^N bits.
+ // N must be >=32 according to the SFDP specification.
+ //
+ if ((Instance->SfdpBasicFlash->Density & ~SFDP_FLASH_MEMORY_DENSITY_4GBIT) < 32) {
+ return 0;
+ }
+
+ return (UINT32)RShiftU64 (LShiftU64 (1, Instance->SfdpBasicFlash->Density & ~SFDP_FLASH_MEMORY_DENSITY_4GBIT), 3);
+}
+
+/**
+ Read SFDP Header
+
+ This routine reads the JEDEC SPI Flash Discoverable Parameter header from the
+ SPI chip. Fails if Major Revision is not = 1
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS Header is filled in
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadSfdpHeader (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TransactionBufferLength;
+
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+
+ // Read SFDP Header
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ SPI_FLASH_RDSFDP,
+ SPI_FLASH_RDSFDP_DUMMY,
+ SPI_FLASH_RDSFDP_ADDR_BYTES,
+ TRUE,
+ 0,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_THEN_READ,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ sizeof (SFDP_HEADER),
+ (UINT8 *)&Instance->SfdpHeader
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (!EFI_ERROR (Status)) {
+ // Read Basic Flash Parameter Header
+ if ((Instance->SfdpHeader.Signature != SFDP_HEADER_SIGNATURE) ||
+ (Instance->SfdpHeader.MajorRev != SFDP_SUPPORTED_MAJOR_REVISION))
+ {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "Total %d parameter headers\n", Instance->SfdpHeader.NumParameterHeaders + 1));
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read SFDP
+ This routine reads the JEDEC SPI Flash Discoverable Parameters. We just
+ read the necessary tables in this routine.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS Header is filled in
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdp (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ SFDP_SUPPORTED_ERASE_TYPE_RECORD *EraseTypeRecord;
+
+ InitializeListHead (&Instance->FastReadTableList);
+ InitializeListHead (&Instance->SupportedEraseTypes);
+ InitializeListHead (&Instance->ConfigurationCommandList);
+ InitializeListHead (&Instance->ConfigurationMapList);
+
+ DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__));
+
+ Status = ReadSfdpHeader (Instance);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to read SFDP header\n", __func__));
+ ASSERT (FALSE);
+ return Status;
+ }
+
+ Status = ReadSfdpBasicParameterTable (Instance);
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to read SFDP Basic Parameter Table\n", __func__));
+ ASSERT (FALSE);
+ return Status;
+ }
+
+ Instance->FlashDeviceSize = SfdpGetFlashSize (Instance);
+ DEBUG ((DEBUG_VERBOSE, "%a: Flash Size=0x%X\n", __func__, Instance->FlashDeviceSize));
+ if (Instance->FlashDeviceSize == 0) {
+ ASSERT (FALSE);
+ return Status;
+ }
+
+ Status = ReadSfdpSectorMapParameterTable (Instance);
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to read SFDP Sector Map Parameter Table\n", __func__));
+ ASSERT (FALSE);
+ } else if (Status == EFI_NOT_FOUND) {
+ DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device doesn't have SFDP Sector Map Parameter Table implemented:\n", __func__));
+
+ //
+ // No SFDP Sector Map Parameter Table exist.
+ // Check if device support the uniform 4K erase size.
+ //
+ Instance->Uniform4KEraseSupported = FALSE;
+ if (Instance->SfdpBasicFlash->EraseSizes == SPI_UNIFORM_4K_ERASE_SUPPORTED) {
+ DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device supports uniform 4K erase.\n", __func__));
+
+ // Check if 4K erase type supported?
+ Status = GetEraseTypeRecord (Instance, SearchEraseTypeBySize, SIZE_4KB, 0, NULL, &EraseTypeRecord);
+ if (Status == EFI_NOT_FOUND) {
+ DEBUG ((DEBUG_ERROR, "However, no corresponding 4K size erase type found.\n", __func__));
+ ASSERT (FALSE);
+ }
+
+ Instance->Uniform4KEraseSupported = TRUE;
+ } else {
+ // Uniform 4K erase unsupported, get the smallest erase block size.
+ DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device doesn't support uniform 4K erase.\n", __func__));
+ }
+
+ //
+ // Build flash map
+ // Instance->ConfigurationMapList is an empty list because no FDP Sector Map Parameter Table.
+ //
+ CreateSingleFlashSectorMap (Instance);
+ Status = EFI_SUCCESS;
+ }
+
+ return Status;
+}
+
+/**
+ Read SFDP Specific Parameter Header
+
+ This routine reads the JEDEC SPI Flash Discoverable Parameter header from the
+ SPI chip. Fails if Major Revision is not = SFDP_SUPPORTED_MAJOR_REVISION.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+ @param[in] SfdpHeader SFDP Header Buffer Pointer
+ @param[in] ParameterIdMsb Most significant byte of parameter ID.
+ @param[in] ParameterIdLsb Lowest significant byte of parameter ID.
+
+ @retval EFI_SUCCESS Header is filled in
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+ @retval EFI_NOT_FOUND Unsupported Parameter Header.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadSfdpParameterHeader (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN SFDP_PARAMETER_HEADER *SfdpParameterHeader,
+ IN UINT8 ParameterIdMsb,
+ IN UINT8 ParameterIdLsb
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ SFDP_PARAMETER_HEADER LocalSfdpParameterHeader;
+ UINT32 TransactionBufferLength;
+
+ DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__));
+ DEBUG ((DEBUG_VERBOSE, " Looking for Parameter Header %02x:%02x\n", ParameterIdMsb, ParameterIdLsb));
+
+ //
+ // Parse Parameter Headers Starting at size eof SFDP_HEADER.
+ // SfdpHeader.NumParameterHeaders is zero based, 0 means 1 parameter header.
+ //
+ ZeroMem (SfdpParameterHeader, sizeof (SFDP_PARAMETER_HEADER));
+ for (Index = 0; Index < Instance->SfdpHeader.NumParameterHeaders + 1; Index++) {
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+ if (!EFI_ERROR (Status)) {
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ SPI_FLASH_RDSFDP,
+ SPI_FLASH_RDSFDP_DUMMY,
+ SPI_FLASH_RDSFDP_ADDR_BYTES,
+ TRUE,
+ sizeof (SFDP_HEADER) + Index * 8, // Parameter Header Index
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_THEN_READ,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ sizeof (LocalSfdpParameterHeader),
+ (UINT8 *)&LocalSfdpParameterHeader
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (!EFI_ERROR (Status)) {
+ // Break if SfdParamHeader is Type 0, Basic SPI Protocol Parameters
+ DEBUG ((
+ DEBUG_VERBOSE,
+ " #%d Parameter Header: %02x:%02x, revision: %d.%d\n",
+ Index,
+ LocalSfdpParameterHeader.IdMsb,
+ LocalSfdpParameterHeader.IdLsb,
+ LocalSfdpParameterHeader.MajorRev,
+ LocalSfdpParameterHeader.MinorRev >= SfdpParameterHeader->MinorRev
+ ));
+ if ((LocalSfdpParameterHeader.IdLsb == ParameterIdLsb) &&
+ (LocalSfdpParameterHeader.IdMsb == ParameterIdMsb) &&
+ (LocalSfdpParameterHeader.MajorRev == (UINT32)SFDP_SUPPORTED_MAJOR_REVISION) &&
+ (LocalSfdpParameterHeader.MinorRev >= SfdpParameterHeader->MinorRev))
+ {
+ CopyMem (
+ (VOID **)SfdpParameterHeader,
+ (VOID **)&LocalSfdpParameterHeader,
+ sizeof (SFDP_PARAMETER_HEADER)
+ );
+ }
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ if (Status != EFI_DEVICE_ERROR) {
+ if ((SfdpParameterHeader->IdLsb != ParameterIdLsb) ||
+ (SfdpParameterHeader->IdMsb != ParameterIdMsb))
+ {
+ DEBUG ((DEBUG_ERROR, " Parameter Header: %02x:%02x is not found.\n", ParameterIdMsb, ParameterIdLsb));
+ Status = EFI_NOT_FOUND;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read from SFDP table pointer
+
+ This routine sends SPI_FLASH_RDSFDP command and reads parameter from the
+ given TablePointer.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+ @param[in] TablePointer Pointer to read data from SFDP.
+ @param[in] DestBuffer Destination buffer.
+ @param[in] LengthInBytes Length to read.
+
+ @retval EFI_SUCCESS The SPI part size is filled.
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+ @retval Other errors
+
+**/
+EFI_STATUS
+EFIAPI
+SpiReadSfdpPtp (
+ IN SPI_NOR_FLASH_INSTANCE *Instance,
+ IN UINT32 TablePointer,
+ IN VOID *DestBuffer,
+ IN UINT32 LengthInBytes
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Length;
+ UINT8 *CurrentBuffer;
+ UINT32 ByteCounter;
+ UINT32 CurrentAddress;
+ UINT32 MaximumTransferBytes;
+ UINT32 TransactionBufferLength;
+
+ Length = 0;
+ MaximumTransferBytes = Instance->SpiIo->MaximumTransferBytes;
+ CurrentBuffer = (UINT8 *)DestBuffer;
+ for (ByteCounter = 0; ByteCounter < LengthInBytes; ByteCounter += Length) {
+ CurrentAddress = TablePointer + ByteCounter;
+ Length = LengthInBytes - ByteCounter;
+
+ // Length must be MaximumTransferBytes or less
+ if (Length > MaximumTransferBytes) {
+ Length = MaximumTransferBytes;
+ }
+
+ // Check not WIP
+ Status = WaitNotWip (Instance);
+
+ // Read Data
+ if (!EFI_ERROR (Status)) {
+ TransactionBufferLength = FillWriteBuffer (
+ Instance,
+ SPI_FLASH_RDSFDP,
+ SPI_FLASH_RDSFDP_DUMMY,
+ SPI_FLASH_RDSFDP_ADDR_BYTES,
+ TRUE,
+ CurrentAddress,
+ 0,
+ NULL
+ );
+ Status = Instance->SpiIo->Transaction (
+ Instance->SpiIo,
+ SPI_TRANSACTION_WRITE_THEN_READ,
+ FALSE,
+ 0,
+ 1,
+ 8,
+ TransactionBufferLength,
+ Instance->SpiTransactionWriteBuffer,
+ Length,
+ CurrentBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fails to read SFDP parameter.\n", __func__));
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ CurrentBuffer += Length;
+ } else {
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read SFDP Sector Map Parameter into buffer
+
+ This routine reads the JEDEC SPI Flash Discoverable Parameters from the SPI
+ chip.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS The SPI part size is filled.
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+
+**/
+EFI_STATUS
+ReadSfdpSectorMapParameterTable (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ SFDP_PARAMETER_HEADER SfdpParamHeader;
+
+ Status = ReadSfdpParameterHeader (
+ Instance,
+ &SfdpParamHeader,
+ SFDP_SECTOR_MAP_PARAMETER_ID_MSB,
+ SFDP_SECTOR_MAP_PARAMETER_ID_LSB
+ );
+ if (!EFI_ERROR (Status)) {
+ // Read Sector Map Parameters. Already know it is MajorRev = SFDP_SUPPORTED_MAJOR_REVISION
+ Instance->SfdpSectorMapByteCount = SfdpParamHeader.Length * sizeof (UINT32);
+ Instance->SfdpFlashSectorMap = AllocateZeroPool (Instance->SfdpSectorMapByteCount);
+ if (Instance->SfdpFlashSectorMap != NULL) {
+ // Read from SFDP Parameter Table Pointer (PTP).
+ Status = SpiReadSfdpPtp (
+ Instance,
+ SfdpParamHeader.TablePointer,
+ (VOID *)Instance->SfdpFlashSectorMap,
+ Instance->SfdpSectorMapByteCount
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = BuildSectorMapCommandAndMap (Instance);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fails to build sector map command and descriptor.\n", __func__));
+ ASSERT (FALSE);
+ Status = GetCurrentSectorMapConfiguration (Instance);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fails to get current sector map configuration.\n", __func__));
+ ASSERT (FALSE);
+ }
+ }
+ } else {
+ FreePool (Instance->SfdpFlashSectorMap);
+ Instance->SfdpFlashSectorMap = NULL;
+ DEBUG ((DEBUG_ERROR, "%a: Fails to read SFDP Sector Map Parameter.\n", __func__));
+ ASSERT (FALSE);
+ }
+ } else {
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fails to allocate memory for reading SFDP Sector Map Parameter.\n", __func__));
+ ASSERT (FALSE);
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Read SFDP Basic Parameters into buffer
+
+ This routine reads the JEDEC SPI Flash Discoverable Parameters from the SPI
+ chip.
+
+ @param[in] Instance Spi Nor Flash Instance data with pointer to
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS The SPI part size is filled.
+ @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part.
+ @retval EFI_NOT_FOUND Parameter header is not found.
+
+**/
+EFI_STATUS
+ReadSfdpBasicParameterTable (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ SFDP_PARAMETER_HEADER SfdpBasicFlashParamHeader;
+
+ Status = ReadSfdpParameterHeader (
+ Instance,
+ &SfdpBasicFlashParamHeader,
+ SFDP_BASIC_PARAMETER_ID_MSB,
+ SFDP_BASIC_PARAMETER_ID_LSB
+ );
+ if (!EFI_ERROR (Status)) {
+ // Read Basic Flash Parameters. Already know it is MajorRev = SFDP_SUPPORTED_MAJOR_REVISION
+ Instance->SfdpBasicFlashByteCount = SfdpBasicFlashParamHeader.Length * sizeof (UINT32);
+ Instance->SfdpBasicFlash = AllocateZeroPool (Instance->SfdpBasicFlashByteCount);
+ if (Instance->SfdpBasicFlash != NULL) {
+ // Read from SFDP Parameter Table Pointer (PTP).
+ Status = SpiReadSfdpPtp (
+ Instance,
+ SfdpBasicFlashParamHeader.TablePointer,
+ (VOID *)Instance->SfdpBasicFlash,
+ Instance->SfdpBasicFlashByteCount
+ );
+ if (!EFI_ERROR (Status)) {
+ GetWriteEnableCommand (Instance);
+ //
+ // Build the Fast Read capability table according to
+ // the Basic Flash Parameter Table.
+ //
+ BuildUpFastReadTable (Instance);
+ BuildUpEraseTypeTable (Instance); // Build up erase type and size.
+
+ // Set current address bytes to 3-Bytes.
+ Instance->CurrentAddressBytes = 3;
+ } else {
+ FreePool (Instance->SfdpBasicFlash);
+ Instance->SfdpBasicFlash = NULL;
+ DEBUG ((DEBUG_ERROR, "%a: Fails to read SFDP Basic Parameter.\n", __func__));
+ ASSERT (FALSE);
+ }
+ } else {
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fails to allocate memory for reading SFDP Basic Parameter.\n", __func__));
+ ASSERT (FALSE);
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Initial SPI_NOR_FLASH_INSTANCE structure.
+
+ @param[in] Instance Pointer to SPI_NOR_FLASH_INSTANCE.
+ EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL
+
+ @retval EFI_SUCCESS SPI_NOR_FLASH_INSTANCE is initialized according to
+ SPI NOR Flash SFDP specification.
+ @retval EFI_INVALID_PARAMETER Instance = NULL or
+ Instance->SpiIo == NULL or
+ Instance->SpiIo->SpiPeripheral == NULL or
+ Instance->SpiIo->SpiPeripheral->SpiBus == NULL or
+ Instance->SpiIo->SpiPeripheral->SpiBus->ControllerPath.
+ @retval Otherwise Failed to initial SPI_NOR_FLASH_INSTANCE structure.
+
+**/
+EFI_STATUS
+InitialSpiNorFlashSfdpInstance (
+ IN SPI_NOR_FLASH_INSTANCE *Instance
+ )
+{
+ EFI_STATUS Status;
+ EFI_SPI_NOR_FLASH_PROTOCOL *Protocol;
+
+ if (Instance == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Instance is NULL.\n", __func__));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Instance->SpiIo == NULL) ||
+ (Instance->SpiIo->SpiPeripheral == NULL) ||
+ (Instance->SpiIo->SpiPeripheral->SpiBus == NULL)
+ )
+ {
+ DEBUG ((DEBUG_ERROR, "%a: One of SpiIo, SpiPeripheral and SpiBus is NULL.\n", __func__));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Instance->Signature = SPI_NOR_FLASH_SIGNATURE;
+
+ // Allocate write buffer for SPI IO transactions with extra room for Opcode
+ // and Address with 10 bytes extra room.
+ Instance->SpiTransactionWriteBuffer =
+ AllocatePool (Instance->SpiIo->MaximumTransferBytes + 10);
+
+ Protocol = &Instance->Protocol;
+ Protocol->SpiPeripheral = Instance->SpiIo->SpiPeripheral;
+ Protocol->GetFlashid = GetFlashId;
+ Protocol->ReadData = ReadData; // Fast Read transfer
+ Protocol->LfReadData = LfReadData; // Normal Read transfer
+ Protocol->ReadStatus = ReadStatus;
+ Protocol->WriteStatus = WriteStatus;
+ Protocol->WriteData = WriteData;
+ Protocol->Erase = Erase;
+ Status = Protocol->GetFlashid (Protocol, (UINT8 *)&Protocol->Deviceid);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Flash ID: Manufacturer=0x%02X, Device=0x%02X%02X\n",
+ __func__,
+ Protocol->Deviceid[0],
+ Protocol->Deviceid[1],
+ Protocol->Deviceid[2]
+ )
+ );
+
+ Status = ReadSfdp (Instance);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to Read SFDP\n", __func__));
+ ASSERT (FALSE);
+ }
+
+ // Get flash deivce size from SFDP.
+ Protocol->FlashSize = SfdpGetFlashSize (Instance);
+ DEBUG ((DEBUG_VERBOSE, "%a: Flash Size=0x%X\n", __func__, Protocol->FlashSize));
+ if (Protocol->FlashSize == 0) {
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ // Set flash erase block size.
+ Status = SetSectorEraseBlockSize (Instance);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fails to get the smallest erase block size.\n", __func__));
+ ASSERT (FALSE);
+ }
+
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
new file mode 100644
index 00000000000..88d5c2ac96a
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
@@ -0,0 +1,261 @@
+/** @file
+ SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+ DXE driver.
+
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Revision Reference:
+ - JEDEC Standard, JESD216F.02
+ https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+
+ @par Glossary:
+ - SFDP - Serial Flash Discoverable Parameters
+ - PTP - Parameter Table Pointer
+**/
+
+#include <Base.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/SpiConfiguration.h>
+#include <Protocol/SpiNorFlash.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiNorFlash.h"
+#include "SpiNorFlashJedecSfdpInternal.h"
+
+/**
+ Function to create SPI_NOR_FLASH_INSTANCE for this SPI part.
+
+ @param[in] SpiIoHandle The handle with SPI I/O protocol installed.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to create SPI_NOR_FLASH_INSTANCE.
+ @retval otherwise Fail to create SPI NOR Flash SFDP Instance
+**/
+EFI_STATUS
+CreateSpiNorFlashSfdpInstance (
+ IN EFI_HANDLE SpiIoHandle
+ )
+{
+ EFI_STATUS Status;
+ SPI_NOR_FLASH_INSTANCE *Instance;
+
+ // Allocate SPI_NOR_FLASH_INSTANCE Instance.
+ Instance = AllocateZeroPool (sizeof (SPI_NOR_FLASH_INSTANCE));
+ ASSERT (Instance != NULL);
+ if (Instance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Locate the SPI IO Protocol
+ Status = gBS->HandleProtocol (
+ SpiIoHandle,
+ &gEdk2JedecSfdpSpiDxeDriverGuid,
+ (VOID **)&Instance->SpiIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to locate SPI I/O protocol\n", __func__));
+ FreePool (Instance);
+ } else {
+ Status = InitialSpiNorFlashSfdpInstance (Instance);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to initial SPI_NOR_FLASH_INSTANCE.\n", __func__));
+ FreePool (Instance);
+ } else {
+ // Install SPI NOR Flash Protocol.
+ Status = gBS->InstallProtocolInterface (
+ &Instance->Handle,
+ &gEfiSpiNorFlashProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Instance->Protocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to Install gEfiSpiNorFlashProtocolGuid protocol.\n", __func__));
+ FreePool (Instance);
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Callback function executed when the EFI_SPI_IO_PROTOCOL
+ protocol interface is installed.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[out] Context Pointer to SPI I/O protocol GUID.
+
+**/
+VOID
+EFIAPI
+SpiIoProtocolInstalledCallback (
+ IN EFI_EVENT Event,
+ OUT VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN InstanceBufferSize;
+ EFI_HANDLE InstanceBuffer;
+
+ DEBUG ((DEBUG_INFO, "%a: Entry.\n", __func__));
+ InstanceBufferSize = sizeof (EFI_HANDLE);
+ Status = gBS->LocateHandle (
+ ByRegisterNotify,
+ (EFI_GUID *)Context,
+ NULL,
+ &InstanceBufferSize,
+ &InstanceBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Can't locate SPI I/O protocol.\n", __func__));
+ DEBUG ((DEBUG_INFO, "%a: Exit.\n", __func__));
+ return;
+ }
+
+ CreateSpiNorFlashSfdpInstance (InstanceBuffer);
+ DEBUG ((DEBUG_INFO, "%a: Exit.\n", __func__));
+ return;
+}
+
+/**
+ Register for the later installed SPI I/O protocol notification.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval otherwise Fail to register SPI I/O protocol installed
+ notification.
+**/
+EFI_STATUS
+RegisterSpioProtocolNotification (
+ VOID
+ )
+{
+ EFI_EVENT Event;
+ EFI_STATUS Status;
+ VOID *Registration;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ SpiIoProtocolInstalledCallback,
+ NULL,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to create event for the SPI I/O Protocol installation.", __func__));
+ return Status;
+ }
+
+ Status = gBS->RegisterProtocolNotify (
+ &gEdk2JedecSfdpSpiDxeDriverGuid,
+ Event,
+ &Registration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the SPI I/O Protocol installation.", __func__));
+ } else {
+ DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installation was registered.", __func__));
+ }
+
+ return Status;
+}
+
+/**
+ Entry point of the Macronix SPI NOR Flash driver.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_NOT_FOUND No gEdk2JedecSfdpSpiSmmDriverGuid installed on
+ system yet.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for SPI NOR Flash JEDEC SFDP
+ initialization.
+ @retval Otherwise Other errors.
+**/
+EFI_STATUS
+EFIAPI
+SpiNorFlashJedecSfdpDxeEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *InstanceBuffer;
+ UINTN InstanceIndex;
+ UINTN InstanceBufferSize;
+
+ DEBUG ((DEBUG_INFO, "%a - ENTRY\n", __func__));
+
+ //
+ // Register notification for the later SPI I/O protocol installation.
+ //
+ RegisterSpioProtocolNotification ();
+ DEBUG ((DEBUG_INFO, "Check if there were already some gEdk2JedecSfdpSpiDxeDriverGuid handles installed.\n"));
+
+ //
+ // Check if there were already some gEdk2JedecSfdpSpiDxeDriverGuid
+ // handles installed.
+ //
+ // Locate the SPI I/O Protocol for the SPI flash part
+ // that supports JEDEC SFDP specification.
+ //
+ InstanceBufferSize = 0;
+ InstanceBuffer = NULL;
+ Status = gBS->LocateHandle (
+ ByProtocol,
+ &gEdk2JedecSfdpSpiDxeDriverGuid,
+ NULL,
+ &InstanceBufferSize,
+ InstanceBuffer
+ );
+ if (Status == EFI_NOT_FOUND) {
+ DEBUG ((
+ DEBUG_INFO,
+ "No gEdk2JedecSfdpSpiSmmDriverGuid handles found at the moment, wait for the notification of SPI I/O protocol installation.\n"
+ ));
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return EFI_SUCCESS;
+ } else if (Status == EFI_BUFFER_TOO_SMALL) {
+ InstanceBuffer = (EFI_HANDLE *)AllocateZeroPool (InstanceBufferSize);
+ ASSERT (InstanceBuffer != NULL);
+ if (InstanceBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "Not enough resource for gEdk2JedecSfdpSpiDxeDriverGuid handles.\n"));
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error to locate gEdk2JedecSfdpSpiDxeDriverGuid - Status = %r.\n", Status));
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return Status;
+ }
+
+ Status = gBS->LocateHandle (
+ ByProtocol,
+ &gEdk2JedecSfdpSpiDxeDriverGuid,
+ NULL,
+ &InstanceBufferSize,
+ InstanceBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Fail to locate all gEdk2JedecSfdpSpiDxeDriverGuid handles.\n"));
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiDxeDriverGuid are found.\n", InstanceBufferSize / sizeof (EFI_HANDLE)));
+ for (InstanceIndex = 0; InstanceIndex < InstanceBufferSize / sizeof (EFI_HANDLE); InstanceIndex++) {
+ Status = CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + InstanceIndex));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Fail to create SPI NOR Flash SFDP instance #%d.\n", InstanceIndex));
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c
new file mode 100644
index 00000000000..18b69dcfb16
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c
@@ -0,0 +1,234 @@
+/** @file
+ SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
+ SMM driver.
+
+ Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Revision Reference:
+ - JEDEC Standard, JESD216F.02
+ https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
+
+ @par Glossary:
+ - SFDP - Serial Flash Discoverable Parameters
+ - PTP - Parameter Table Pointer
+**/
+#include <Base.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Protocol/SpiSmmConfiguration.h>
+#include <Protocol/SpiSmmNorFlash.h>
+#include <Protocol/SpiIo.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiNorFlash.h"
+#include "SpiNorFlashJedecSfdpInternal.h"
+
+/**
+ Function to create SPI_NOR_FLASH_INSTANCE for this SPI part.
+
+ @param[in] SpiIoHandle The handle with SPI I/O protocol installed.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to create SPI_NOR_FLASH_INSTANCE.
+ @retval otherwise Fail to create SPI NOR Flash SFDP Instance
+**/
+EFI_STATUS
+CreateSpiNorFlashSfdpInstance (
+ IN EFI_HANDLE SpiIoHandle
+ )
+{
+ EFI_STATUS Status;
+ SPI_NOR_FLASH_INSTANCE *Instance;
+
+ // Allocate SPI_NOR_FLASH_INSTANCE Instance.
+ Instance = AllocateZeroPool (sizeof (SPI_NOR_FLASH_INSTANCE));
+ ASSERT (Instance != NULL);
+ if (Instance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Locate the SPI IO Protocol.
+ Status = gSmst->SmmHandleProtocol (
+ SpiIoHandle,
+ &gEdk2JedecSfdpSpiSmmDriverGuid,
+ (VOID **)&Instance->SpiIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to locate SPI I/O protocol.\n", __func__));
+ FreePool (Instance);
+ } else {
+ Status = InitialSpiNorFlashSfdpInstance (Instance);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to initial SPI_NOR_FLASH_INSTANCE.\n", __func__));
+ FreePool (Instance);
+ } else {
+ // Install SPI NOR Flash Protocol.
+ Status = gSmst->SmmInstallProtocolInterface (
+ &Instance->Handle,
+ &gEfiSpiSmmNorFlashProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Instance->Protocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to Install gEfiSpiSmmNorFlashProtocolGuid protocol.\n", __func__));
+ FreePool (Instance);
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Callback function executed when the EFI_SPI_IO_PROTOCOL
+ protocol interface is installed.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @return Status Code
+
+**/
+EFI_STATUS
+EFIAPI
+SpiIoProtocolInstalledCallback (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO, "%a: Entry.\n", __func__));
+ Status = CreateSpiNorFlashSfdpInstance (Handle);
+ return Status;
+}
+
+/**
+ Register notification for the later installed SPI I/O protocol.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval otherwise Fail to register the notification of
+ SPI I/O protocol installation.
+
+**/
+EFI_STATUS
+RegisterSpioProtocolNotification (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEdk2JedecSfdpSpiSmmDriverGuid,
+ SpiIoProtocolInstalledCallback,
+ &Registration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the SPI I/O Protocol installation.", __func__));
+ } else {
+ DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installation was registered.", __func__));
+ }
+
+ return Status;
+}
+
+/**
+ Entry point of the SPI NOR Flash SFDP SMM driver.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_NOT_FOUND No gEdk2JedecSfdpSpiSmmDriverGuid installed on
+ system yet.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for SPI NOR Flash JEDEC SFDP
+ initialization.
+ @retval Otherwise Other errors.
+**/
+EFI_STATUS
+EFIAPI
+SpiNorFlashJedecSfdpSmmEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *InstanceBuffer;
+ UINTN InstanceIndex;
+ UINTN InstanceBufferSize;
+
+ DEBUG ((DEBUG_INFO, "%a - ENTRY.\n", __func__));
+
+ //
+ // Register notification for the later SPI I/O protocol installation.
+ //
+ RegisterSpioProtocolNotification ();
+ DEBUG ((DEBUG_INFO, "Check if there were already some gEdk2JedecSfdpSpiSmmDriverGuid handles installed.\n"));
+ //
+ // Check if there were already some gEdk2JedecSfdpSpiSmmDriverGuid
+ // handles installed.
+ //
+ // Locate the SPI I/O Protocol for the SPI flash part
+ // that supports JEDEC SFDP specification.
+ //
+ InstanceBufferSize = 0;
+ InstanceBuffer = NULL;
+ Status = gSmst->SmmLocateHandle (
+ ByProtocol,
+ &gEdk2JedecSfdpSpiSmmDriverGuid,
+ NULL,
+ &InstanceBufferSize,
+ InstanceBuffer
+ );
+ if (Status == EFI_NOT_FOUND) {
+ DEBUG ((
+ DEBUG_INFO,
+ "No gEdk2JedecSfdpSpiSmmDriverGuid handles found at the moment, wait for the notification of SPI I/O protocol installation.\n"
+ ));
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return EFI_SUCCESS;
+ } else if (Status == EFI_BUFFER_TOO_SMALL) {
+ InstanceBuffer = (EFI_HANDLE *)AllocateZeroPool (InstanceBufferSize);
+ ASSERT (InstanceBuffer != NULL);
+ if (InstanceBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "Not enough resource for gEdk2JedecSfdpSpiSmmDriverGuid handles.\n"));
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Error to locate gEdk2JedecSfdpSpiSmmDriverGuid - Status = %r.\n", Status));
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return Status;
+ }
+
+ Status = gSmst->SmmLocateHandle (
+ ByProtocol,
+ &gEdk2JedecSfdpSpiSmmDriverGuid,
+ NULL,
+ &InstanceBufferSize,
+ InstanceBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Fail to locate all gEdk2JedecSfdpSpiSmmDriverGuid handles.\n"));
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiSmmDriverGuid handles are found.\n", InstanceBufferSize / sizeof (EFI_HANDLE)));
+ for (InstanceIndex = 0; InstanceIndex < InstanceBufferSize / sizeof (EFI_HANDLE); InstanceIndex++) {
+ Status = CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + InstanceIndex));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Fail to create SPI NOR Flash SFDP instance #%d.\n", InstanceIndex));
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni
new file mode 100644
index 00000000000..4e091f6850d
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni
@@ -0,0 +1,13 @@
+// /** @file
+// SPI NOR Flash SFDP Localized Strings and Content.
+//
+// Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "EDK2 SPI NOR FLASH SFDP DXE driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver provides SPI NOR FLASH Serial Flash Discoverable Parameter (SFDP) compatible flash device capability discovery."
+
--git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni
new file mode 100644
index 00000000000..0efea67b9e4
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni
@@ -0,0 +1,11 @@
+// /** @file
+// SPI NOR Flash SFDP Localized Strings and Content.
+//
+// Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US "SPI NOR Flash driver for JEDEC Serial Flash Discoverable Parameters (SFDP) compliant SPI Flash Memory"
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni
new file mode 100644
index 00000000000..b487ec71a12
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni
@@ -0,0 +1,13 @@
+// /** @file
+// SPI NOR Flash SFDP Localized Strings and Content.
+//
+// Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "EDK2 SPI NOR FLASH SFDP SMM driver"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver provides SPI NOR FLASH Serial Flash Discoverable Parameter (SFDP) compatible flash device capability discovery."
+
--
2.37.1.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#107225): https://edk2.groups.io/g/devel/message/107225
Mute This Topic: https://groups.io/mt/100345726/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [edk2-devel] [PATCH 5/5] MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC
2023-07-25 7:10 [edk2-devel] [PATCH 0/5] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
` (3 preceding siblings ...)
2023-07-25 7:10 ` [edk2-devel] [PATCH 4/5] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Chang, Abner via groups.io
@ 2023-07-25 7:10 ` Chang, Abner via groups.io
4 siblings, 0 replies; 6+ messages in thread
From: Chang, Abner via groups.io @ 2023-07-25 7:10 UTC (permalink / raw)
To: devel; +Cc: Jian J Wang, Liming Gao, Abdul Lateef Attar
From: abnchang <abnchang@amd.com>
BZ#: 4473
SPI NOR Flash JEDEC Serial Flash Discoverable Driver
implementation.
Signed-off-by: Abner Chang <abner.chang@amd.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Abdul Lateef Attar <abdattar@amd.com>
---
MdeModulePkg/MdeModulePkg.dsc | 2 ++
1 file changed, 2 insertions(+)
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index db3b5af5379..137e88aa7ed 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -285,6 +285,8 @@
MdeModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.inf
MdeModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf
MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
+ MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
+ MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
MdeModulePkg/Core/Pei/PeiMain.inf
--
2.37.1.windows.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#107224): https://edk2.groups.io/g/devel/message/107224
Mute This Topic: https://groups.io/mt/100345724/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2023-07-25 7:11 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-25 7:10 [edk2-devel] [PATCH 0/5] SPI NOR Flash Driver for SFDP flash device Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 1/5] MdePkg/Include: Update definitions of SPI related header files Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 2/5] MdePkg/Include: Add SPI NOR Flash JEDEC SFDP header file Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 3/5] MdePkg: Add definitions in DEC for SPI NOR Flash SPDF driver Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 4/5] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Chang, Abner via groups.io
2023-07-25 7:10 ` [edk2-devel] [PATCH 5/5] MdeModulePkg: Add SPI NOR FLash SFDP drivers to DSC Chang, Abner via groups.io
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox