public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [edk2-platforms][PATCH V1 0/5] Enable non volatile storage on N1SDP
@ 2023-11-16 11:45 sahil
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 1/5] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region sahil
                   ` (4 more replies)
  0 siblings, 5 replies; 17+ messages in thread
From: sahil @ 2023-11-16 11:45 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Sahil

N1SDP uses an emulated variable storage on DDR memory for the variable
storage. But this emulated variable storage is a volatile memory and so
the values of variable cant persist on next reboot or in power cycle. In
N1SDP platform, the SoC is connected to IOFPGA which has a Cadence Quad
SPI (QSPI) controller. This QSPI controller manages the flash chip
device (NOR Flash with 32 MB memory capacity, 4KB block size) via QSPI
bus. With these changes we use this NOR flash device for persistent
variable storage.


Link to branch with the patches in this series -
https://github.com/sah01Kaushal/edk2-platforms/tree/n1sdp_persistent_storage

sahil (5):
  Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region
  Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp
  Platform/ARM/N1Sdp: NOR flash Dxe Driver for N1Sdp
  Platform/ARM/N1Sdp: Persistent storage for N1Sdp
  Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver for N1Sdp

 Platform/ARM/N1Sdp/N1SdpPlatform.dec                           |    5 +-
 Platform/ARM/N1Sdp/N1SdpPlatform.dsc                           |   25 +-
 Platform/ARM/N1Sdp/N1SdpPlatform.fdf                           |    5 +-
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf   |   72 ++
 Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf  |   36 +
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h     |   33 +
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h           |  491 +++++++++
 Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h              |    6 +-
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c     |  409 ++++++++
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c           | 1100 ++++++++++++++++++++
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c        |  647 ++++++++++++
 Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c    |   52 +
 Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c |   10 +-
 13 files changed, 2880 insertions(+), 11 deletions(-)
 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
 create mode 100644 Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c
 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c
 create mode 100644 Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c

-- 
2.25.1



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



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

* [edk2-devel] [edk2-platforms][PATCH V1 1/5] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region
  2023-11-16 11:45 [edk2-devel] [edk2-platforms][PATCH V1 0/5] Enable non volatile storage on N1SDP sahil
@ 2023-11-16 11:45 ` sahil
  2023-12-07 10:59   ` Thomas Abraham
  2023-12-18 15:12   ` Sami Mujawar
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 2/5] Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp sahil
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 17+ messages in thread
From: sahil @ 2023-11-16 11:45 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Sahil

Enable SCP QSPI flash region access by adding it in the PlatformLibMem

Signed-off-by: sahil <sahil@arm.com>
---
 Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h              |  6 +++++-
 Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c | 10 ++++++++--
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h b/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
index 097160c7e2d1..92b8c9c45775 100644
--- a/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
+++ b/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
@@ -1,6 +1,6 @@
 /** @file
 *
-* Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
+* Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-2-Clause-Patent
 *
@@ -41,6 +41,10 @@
 #define NEOVERSEN1SOC_EXP_PERIPH_BASE0               0x1C000000
 #define NEOVERSEN1SOC_EXP_PERIPH_BASE0_SZ            0x1300000
 
+// SCP QSPI flash device
+#define NEOVERSEN1SOC_SCP_QSPI_AHB_BASE              0x18000000
+#define NEOVERSEN1SOC_SCP_QSPI_AHB_SZ                0x2000000
+
 // Base address to a structure of type NEOVERSEN1SOC_PLAT_INFO which is
 // pre-populated by a earlier boot stage
 #define NEOVERSEN1SOC_PLAT_INFO_STRUCT_BASE          (NEOVERSEN1SOC_NON_SECURE_SRAM_BASE + \
diff --git a/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c b/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
index 9e8a1efc557d..eb099953fe29 100644
--- a/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
+++ b/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
@@ -1,6 +1,6 @@
 /** @file
 
-  Copyright (c) 2018 - 2021, ARM Limited. All rights reserved.<BR>
+  Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
@@ -13,7 +13,7 @@
 #include <NeoverseN1Soc.h>
 
 // The total number of descriptors, including the final "end-of-table" descriptor.
-#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 19
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 20
 
 /**
   Returns the Virtual Memory Map of the platform.
@@ -184,6 +184,12 @@ ArmPlatformGetVirtualMemoryMap (
   VirtualMemoryTable[Index].Length          = NEOVERSEN1SOC_EXP_PERIPH_BASE0_SZ;
   VirtualMemoryTable[Index].Attributes      = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
 
+  // SCP QSPI flash device
+  VirtualMemoryTable[++Index].PhysicalBase  = NEOVERSEN1SOC_SCP_QSPI_AHB_BASE;
+  VirtualMemoryTable[Index].VirtualBase     = NEOVERSEN1SOC_SCP_QSPI_AHB_BASE;
+  VirtualMemoryTable[Index].Length          = NEOVERSEN1SOC_SCP_QSPI_AHB_SZ;
+  VirtualMemoryTable[Index].Attributes      = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
+
   if (PlatInfo->MultichipMode == 1) {
     //Remote DDR (2GB)
     VirtualMemoryTable[++Index].PhysicalBase  = PcdGet64 (PcdExtMemorySpace) +
-- 
2.25.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111308): https://edk2.groups.io/g/devel/message/111308
Mute This Topic: https://groups.io/mt/102625033/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] 17+ messages in thread

* [edk2-devel] [edk2-platforms][PATCH V1 2/5] Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp
  2023-11-16 11:45 [edk2-devel] [edk2-platforms][PATCH V1 0/5] Enable non volatile storage on N1SDP sahil
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 1/5] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region sahil
@ 2023-11-16 11:45 ` sahil
  2023-12-07 12:01   ` Thomas Abraham
  2023-12-18 15:12   ` Sami Mujawar
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver " sahil
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 17+ messages in thread
From: sahil @ 2023-11-16 11:45 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Sahil

Add NOR flash library, this library provides APIs for getting the list
of NOR flash devices on the platform.

Signed-off-by: sahil <sahil@arm.com>
---
 Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf | 36 ++++++++++++++
 Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c   | 52 ++++++++++++++++++++
 2 files changed, 88 insertions(+)

diff --git a/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
new file mode 100644
index 000000000000..14f81125c4e1
--- /dev/null
+++ b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
@@ -0,0 +1,36 @@
+## @file
+#  NOR flash lib for ARM Neoverse N1 platform.
+#
+#  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = NorFlashNeoverseN1SocLib
+  FILE_GUID                      = 7006fcf1-a585-4272-92e3-b286b1dff5bb
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = NorFlashPlatformLib
+
+[Sources.common]
+  NorFlashLib.c
+
+[Packages]
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Platform/ARM/ARM.dec
+  Silicon/ARM/NeoverseN1Soc/NeoverseN1Soc.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  IoLib
+
+[FixedPcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
diff --git a/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c
new file mode 100644
index 000000000000..a508d7d77373
--- /dev/null
+++ b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c
@@ -0,0 +1,52 @@
+/** @file
+*  NOR flash lib for ARM Neoverse N1 platform
+*
+*  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
+*
+*  SPDX-License-Identifier: BSD-2-Clause-Patent
+*
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/NorFlashPlatformLib.h>
+#include <NeoverseN1Soc.h>
+#include <PiDxe.h>
+
+#define FW_ENV_REGION_BASE  FixedPcdGet32 (PcdFlashNvStorageVariableBase)
+#define FW_ENV_REGION_SIZE  (FixedPcdGet32 (PcdFlashNvStorageVariableSize) +           \
+                                      FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + \
+                                      FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize))
+
+STATIC NOR_FLASH_DESCRIPTION  mNorFlashDevices[] = {
+  {
+    /// Environment variable region
+    NEOVERSEN1SOC_SCP_QSPI_AHB_BASE,                    ///< device base
+    FW_ENV_REGION_BASE,                                 ///< region base
+    FW_ENV_REGION_SIZE,                                 ///< region size
+    SIZE_4KB,                                           ///< block size
+  },
+};
+
+/**
+  Get NOR flash region info
+
+  @param[out]    NorFlashDevices    NOR flash regions info.
+  @param[out]    Count              number of flash instance.
+
+  @retval        EFI_SUCCESS        Success.
+**/
+EFI_STATUS
+NorFlashPlatformGetDevices (
+  OUT NOR_FLASH_DESCRIPTION  **NorFlashDevices,
+  OUT UINT32                 *Count
+  )
+{
+  if ((NorFlashDevices == NULL) || (Count == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *NorFlashDevices = mNorFlashDevices;
+  *Count           = ARRAY_SIZE (mNorFlashDevices);
+  return EFI_SUCCESS;
+}
-- 
2.25.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111309): https://edk2.groups.io/g/devel/message/111309
Mute This Topic: https://groups.io/mt/102625034/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] 17+ messages in thread

* [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver for N1Sdp
  2023-11-16 11:45 [edk2-devel] [edk2-platforms][PATCH V1 0/5] Enable non volatile storage on N1SDP sahil
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 1/5] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region sahil
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 2/5] Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp sahil
@ 2023-11-16 11:45 ` sahil
  2023-12-07 14:46   ` Thomas Abraham
                     ` (2 more replies)
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 4/5] Platform/ARM/N1Sdp: Persistent storage " sahil
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 5/5] Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver " sahil
  4 siblings, 3 replies; 17+ messages in thread
From: sahil @ 2023-11-16 11:45 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Sahil

Add NOR flash DXE driver, this brings up NV storage on
QSPI's flash device using FVB protocol.

Signed-off-by: sahil <sahil@arm.com>
---
 Platform/ARM/N1Sdp/N1SdpPlatform.dec                         |    5 +-
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf |   72 ++
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h   |   33 +
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h         |  491 +++++++++
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c   |  409 ++++++++
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c         | 1100 ++++++++++++++++++++
 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c      |  647 ++++++++++++
 7 files changed, 2756 insertions(+), 1 deletion(-)

diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dec b/Platform/ARM/N1Sdp/N1SdpPlatform.dec
index 16937197b8e8..67b5f4c871b6 100644
--- a/Platform/ARM/N1Sdp/N1SdpPlatform.dec
+++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dec
@@ -1,7 +1,7 @@
 ## @file
 #  Describes the N1Sdp configuration.
 #
-#  Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
+#  Copyright (c) 2021-2023, ARM Limited. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 ##
@@ -89,3 +89,6 @@
   # unmapped reserved region results in a DECERR response.
   #
   gArmN1SdpTokenSpaceGuid.PcdCsComponentSize|0x1000|UINT32|0x00000049
+
+  # Base address of Cadence QSPI controller configuration registers
+  gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress|0x1C0C0000|UINT32|0x0000004A
diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
new file mode 100644
index 000000000000..62a4944c95db
--- /dev/null
+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
@@ -0,0 +1,72 @@
+## @file
+#  NOR flash DXE
+#
+#  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = CadenceQspiDxe
+  FILE_GUID                      = CC8A9713-4442-4A6C-B389-8B46490A0641
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 0.1
+  ENTRY_POINT                    = NorFlashInitialise
+
+[Sources]
+  CadenceQspiDxe.c
+  CadenceQspiReg.h
+  NorFlash.c
+  NorFlash.h
+  NorFlashFvb.c
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Platform/ARM/ARM.dec
+  Platform/ARM/N1Sdp/N1SdpPlatform.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  DevicePathLib
+  DxeServicesTableLib
+  HobLib
+  IoLib
+  MemoryAllocationLib
+  NorFlashInfoLib
+  NorFlashPlatformLib
+  TimerLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  UefiRuntimeLib
+  UefiRuntimeServicesTableLib
+
+[Guids]
+  gEdkiiNvVarStoreFormattedGuid
+  gEfiAuthenticatedVariableGuid
+  gEfiEventVirtualAddressChangeGuid
+  gEfiSystemNvDataFvGuid
+  gEfiVariableGuid
+  gEfiGlobalVariableGuid
+
+[Protocols]
+  gEfiDevicePathProtocolGuid
+  gEfiFirmwareVolumeBlockProtocolGuid
+
+[FixedPcd]
+  gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+[Depex]
+  gEfiCpuArchProtocolGuid
diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
new file mode 100644
index 000000000000..535e6d738d31
--- /dev/null
+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
@@ -0,0 +1,33 @@
+/** @file
+
+  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CADENCE_QSPI_REG_H_
+#define CADENCE_QSPI_REG_H_
+
+// QSPI Controller defines
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET             0x90
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE            0x01
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE        0x01
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS       19
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS  16
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT         0x02
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS     24
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE        0x01
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_BYTE_3B       0x02
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS     23
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS   20
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C           0x8
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_BIT_POS      7
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES(x)  ((x - 1) << CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS)
+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES(x)  ((x - 1) << CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS)
+
+#define CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET  0xA0
+
+#define CDNS_QSPI_FLASH_CMD_ADDR_REG_OFFSET  0x94
+
+#endif /* CADENCE_QSPI_REG_H_ */
diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
new file mode 100644
index 000000000000..38ae1c2fae89
--- /dev/null
+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
@@ -0,0 +1,491 @@
+/** @file
+
+  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef NOR_FLASH_DXE_H_
+#define NOR_FLASH_DXE_H_
+
+#include <Guid/EventGroup.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/NorFlashPlatformLib.h>
+#include <PiDxe.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include "CadenceQspiReg.h"
+
+#define NOR_FLASH_ERASE_RETRY  10
+
+#define GET_NOR_BLOCK_ADDRESS(BaseAddr, Lba, LbaSize) \
+                                      ((BaseAddr) + (UINTN)((Lba) * (LbaSize)))
+
+#define NOR_FLASH_SIGNATURE  SIGNATURE_32('S', 'n', 'o', 'r')
+#define INSTANCE_FROM_FVB_THIS(a)  CR(a, NOR_FLASH_INSTANCE, FvbProtocol,   \
+                                        NOR_FLASH_SIGNATURE)
+
+#define NOR_FLASH_POLL_FSR  BIT0
+
+typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE;
+
+typedef EFI_STATUS (*NOR_FLASH_INITIALIZE)        (
+  NOR_FLASH_INSTANCE  *Instance
+  );
+
+#pragma pack(1)
+typedef struct {
+  VENDOR_DEVICE_PATH          Vendor;
+  UINT8                       Index;
+  EFI_DEVICE_PATH_PROTOCOL    End;
+} NOR_FLASH_DEVICE_PATH;
+#pragma pack()
+
+struct _NOR_FLASH_INSTANCE {
+  UINT32                                 Signature;
+  EFI_HANDLE                             Handle;
+
+  BOOLEAN                                Initialized;
+  NOR_FLASH_INITIALIZE                   Initialize;
+
+  UINTN                                  HostRegisterBaseAddress;
+  UINTN                                  DeviceBaseAddress;
+  UINTN                                  RegionBaseAddress;
+  UINTN                                  Size;
+  UINTN                                  BlockSize;
+  UINTN                                  LastBlock;
+  EFI_LBA                                StartLba;
+  EFI_LBA                                OffsetLba;
+
+  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL    FvbProtocol;
+  VOID                                   *ShadowBuffer;
+
+  NOR_FLASH_DEVICE_PATH                  DevicePath;
+
+  UINT32                                 Flags;
+};
+
+typedef struct {
+  EFI_TPL    OriginalTPL;
+  BOOLEAN    InterruptsEnabled;
+} NOR_FLASH_LOCK_CONTEXT;
+
+/**
+  Lock all pending read/write to Nor flash device
+
+  @param[in]     Context     Nor flash device context structure.
+**/
+VOID
+EFIAPI
+NorFlashLock (
+  IN NOR_FLASH_LOCK_CONTEXT  *Context
+  );
+
+/**
+  Unlock all pending read/write to Nor flash device
+
+  @param[in]     Context     Nor flash device context structure.
+**/
+VOID
+EFIAPI
+NorFlashUnlock (
+  IN NOR_FLASH_LOCK_CONTEXT  *Context
+  );
+
+extern UINTN  mFlashNvStorageVariableBase;
+
+/**
+  Create Nor flash Instance for given region.
+
+  @param[in]    HostRegisterBase      Base address of Nor flash controller.
+  @param[in]    NorFlashDeviceBase    Base address of flash device.
+  @param[in]    NorFlashRegionBase    Base address of flash region on device.
+  @param[in]    NorFlashSize          Size of flash region.
+  @param[in]    Index                 Index of given flash region.
+  @param[in]    BlockSize             Block size of NOR flash device.
+  @param[in]    HasVarStore           Boolean set for VarStore on given region.
+  @param[out]   NorFlashInstance      Instance of given flash region.
+
+  @retval       EFI_SUCCESS           On successful creation of NOR flash instance.
+**/
+EFI_STATUS
+NorFlashCreateInstance (
+  IN UINTN                HostRegisterBase,
+  IN UINTN                NorFlashDeviceBase,
+  IN UINTN                NorFlashRegionBase,
+  IN UINTN                NorFlashSize,
+  IN UINT32               Index,
+  IN UINT32               BlockSize,
+  IN BOOLEAN              HasVarStore,
+  OUT NOR_FLASH_INSTANCE  **NorFlashInstance
+  );
+
+/**
+  Install Fv block on to variable store region
+
+  @param[in]   Instance         Instance of Nor flash variable region.
+
+  @retval      EFI_SUCCESS      The entry point is executed successfully.
+**/
+EFI_STATUS
+EFIAPI
+NorFlashFvbInitialize (
+  IN NOR_FLASH_INSTANCE  *Instance
+  );
+
+/**
+  Check the integrity of firmware volume header.
+
+  @param[in]  Instance        Instance of Nor flash variable region.
+
+  @retval     EFI_SUCCESS     The firmware volume is consistent.
+  @retval     EFI_NOT_FOUND   The firmware volume has been corrupted.
+
+**/
+EFI_STATUS
+ValidateFvHeader (
+  IN  NOR_FLASH_INSTANCE  *Instance
+  );
+
+/**
+  Initialize the FV Header and Variable Store Header
+  to support variable operations.
+
+  @param[in]  Instance      Location to Initialize the headers
+
+  @retval     EFI_SUCCESS   Fv init is done
+
+**/
+EFI_STATUS
+InitializeFvAndVariableStoreHeaders (
+  IN NOR_FLASH_INSTANCE  *Instance
+  );
+
+/**
+ Retrieves the attributes and current settings of the block.
+
+ @param[in]   This         Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[out]  Attributes   Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
+                           current settings are returned.
+                           Type EFI_FVB_ATTRIBUTES_2 is defined in
+                           EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval      EFI_SUCCESS  The firmware volume attributes were returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbGetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes
+  );
+
+/**
+ Sets configurable firmware volume attributes and returns the
+ new settings of the firmware volume.
+
+
+ @param[in]         This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[in, out]    Attributes               On input, Attributes is a pointer to
+                                             EFI_FVB_ATTRIBUTES_2 that contains the desired
+                                             firmware volume settings.
+                                             On successful return, it contains the new
+                                             settings of the firmware volume.
+
+ @retval            EFI_UNSUPPORTED          The firmware volume attributes are not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbSetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
+  );
+
+/**
+ Retrieves the base address of a memory-mapped firmware volume.
+ This function should be called only for memory-mapped firmware volumes.
+
+ @param[in]     This               EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[out]    Address            Pointer to a caller-allocated
+                                   EFI_PHYSICAL_ADDRESS that, on successful
+                                   return from GetPhysicalAddress(), contains the
+                                   base address of the firmware volume.
+
+ @retval        EFI_SUCCESS        The firmware volume base address was returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_PHYSICAL_ADDRESS                 *Address
+  );
+
+/**
+ Retrieves the size of the requested block.
+ It also returns the number of additional blocks with the identical size.
+ The GetBlockSize() function is used to retrieve the block map
+ (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+ @param[in]     This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[in]     Lba                      Indicates the block whose size to return
+
+ @param[out]    BlockSize                Pointer to a caller-allocated UINTN in which
+                                         the size of the block is returned.
+
+ @param[out]    NumberOfBlocks           Pointer to a caller-allocated UINTN in
+                                         which the number of consecutive blocks,
+                                         starting with Lba, is returned. All
+                                         blocks in this range have a size of
+                                         BlockSize.
+
+ @retval        EFI_SUCCESS              The firmware volume base address was returned.
+
+ @retval        EFI_INVALID_PARAMETER    The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  OUT       UINTN                                *BlockSize,
+  OUT       UINTN                                *NumberOfBlocks
+  );
+
+/**
+ Reads the specified number of bytes into a buffer from the specified block.
+
+ The Read() function reads the requested number of bytes from the
+ requested block and stores them in the provided buffer.
+
+ @param[in]       This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[in]       Lba                  The starting logical block index from which to read
+
+ @param[in]       Offset               Offset into the block at which to begin reading.
+
+ @param[in, out]  NumBytes             Pointer to a UINTN.
+                                       At entry, *NumBytes contains the total size of the
+                                       buffer. *NumBytes should have a non zero value.
+                                       At exit, *NumBytes contains the total number of
+                                       bytes read.
+
+ @param[in out]   Buffer               Pointer to a caller-allocated buffer that will be
+                                       used to hold the data that is read.
+
+ @retval          EFI_SUCCESS          The firmware volume was read successfully, and
+                                       contents are in Buffer.
+
+ @retval          EFI_BAD_BUFFER_SIZE  Read attempted across an LBA boundary.
+
+ @retval          EFI_DEVICE_ERROR     The block device is not functioning correctly and
+                                       could not be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbRead (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN OUT    UINT8                                *Buffer
+  );
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ @param[in]        This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[in]        Lba                  The starting logical block index to write to.
+
+ @param[in]        Offset               Offset into the block at which to begin writing.
+
+ @param[in, out]   NumBytes             The pointer to a UINTN.
+                                        At entry, *NumBytes contains the total size of the
+                                        buffer.
+                                        At exit, *NumBytes contains the total number of
+                                        bytes actually written.
+
+ @param[in]        Buffer               The pointer to a caller-allocated buffer that
+                                        contains the source for the write.
+
+ @retval           EFI_SUCCESS          The firmware volume was written successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbWrite (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN        UINT8                                *Buffer
+  );
+
+/**
+ Erases and initialises a firmware volume block.
+
+ @param[in]   This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
+
+ @param[in]   ...                      The variable argument list is a list of tuples.
+                                       Each tuple describes a range of LBAs to erase
+                                       and consists of the following:
+                                       - An EFI_LBA that indicates the starting LBA
+                                       - A UINTN that indicates the number of blocks
+                                       to erase.
+
+                                       The list is terminated with an
+                                       EFI_LBA_LIST_TERMINATOR.
+
+ @retval      EFI_SUCCESS              The erase request successfully completed.
+
+ @retval      EFI_ACCESS_DENIED        The firmware volume is in the WriteDisabled
+                                       state.
+
+ @retval      EFI_DEVICE_ERROR         The block device is not functioning correctly
+                                       and could not be written.
+                                       The firmware device may have been partially
+                                       erased.
+
+ @retval      EFI_INVALID_PARAMETER    One or more of the LBAs listed in the variable
+                                       argument list do not exist in the firmware
+                                       volume.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  ...
+  );
+
+/**
+  This function unlock and erase an entire NOR Flash block.
+
+  @param[in]     Instance       NOR flash Instance of variable store region.
+  @param[in]     BlockAddress   Block address within the variable store region.
+
+  @retval        EFI_SUCCESS    The erase and unlock successfully completed.
+**/
+EFI_STATUS
+NorFlashUnlockAndEraseSingleBlock (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               BlockAddress
+  );
+
+/**
+  Write a full or portion of a block.
+
+  @param[in]        Instance     NOR flash Instance of variable store region.
+  @param[in]        Lba          The starting logical block index to write to.
+  @param[in]        Offset       Offset into the block at which to begin writing.
+  @param[in,out]    NumBytes     The total size of the buffer.
+  @param[in]        Buffer       The pointer to a caller-allocated buffer that
+                                 contains the source for the write.
+
+  @retval           EFI_SUCCESS  The write is completed.
+**/
+EFI_STATUS
+NorFlashWriteSingleBlock (
+  IN        NOR_FLASH_INSTANCE  *Instance,
+  IN        EFI_LBA             Lba,
+  IN        UINTN               Offset,
+  IN OUT    UINTN               *NumBytes,
+  IN        UINT8               *Buffer
+  );
+
+/**
+  Write a full  block.
+
+  @param[in]    Instance             NOR flash Instance of variable store region.
+  @param[in]    Lba                  The starting logical block index to write to.
+  @param[in]    BufferSizeInBytes    The number of bytes to write.
+  @param[in]    Buffer               The pointer to a caller-allocated buffer that
+                                     contains the source for the write.
+
+  @retval       EFI_SUCCESS          The write is completed.
+**/
+EFI_STATUS
+NorFlashWriteBlocks (
+  IN  NOR_FLASH_INSTANCE  *Instance,
+  IN  EFI_LBA             Lba,
+  IN  UINTN               BufferSizeInBytes,
+  IN  VOID                *Buffer
+  );
+
+/**
+  Read a full  block.
+
+  @param[in]     Instance           NOR flash Instance of variable store region.
+  @param[in]     Lba                The starting logical block index to read from.
+  @param[in]     BufferSizeInBytes  The number of bytes to read.
+  @param[out]    Buffer             The pointer to a caller-allocated buffer that
+                                    should be copied with read data.
+
+  @retval        EFI_SUCCESS        The read is completed.
+**/
+EFI_STATUS
+NorFlashReadBlocks (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN EFI_LBA             Lba,
+  IN UINTN               BufferSizeInBytes,
+  OUT VOID               *Buffer
+  );
+
+/**
+  Read from nor flash.
+
+  @param[in]     Instance           NOR flash Instance of variable store region.
+  @param[in]     Lba                The starting logical block index to read from.
+  @param[in]     Offset             Offset into the block at which to begin reading.
+  @param[in]     BufferSizeInBytes  The number of bytes to read.
+  @param[out]    Buffer             The pointer to a caller-allocated buffer that
+                                    should copied with read data.
+
+  @retval        EFI_SUCCESS        The read is completed.
+**/
+EFI_STATUS
+NorFlashRead (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN EFI_LBA             Lba,
+  IN UINTN               Offset,
+  IN UINTN               BufferSizeInBytes,
+  OUT VOID               *Buffer
+  );
+
+/**
+  Read JEDEC ID of NOR flash device.
+
+  @param[in]     Instance     NOR flash Instance of variable store region.
+  @param[out]    JedecId      JEDEC ID of NOR flash device.
+
+  @retval        EFI_SUCCESS  The write is completed.
+**/
+EFI_STATUS
+NorFlashReadID (
+  IN  NOR_FLASH_INSTANCE  *Instance,
+  OUT UINT8               JedecId[3]
+  );
+
+#define SPINOR_SR_WIP  BIT0                 // Write in progress
+
+#define SPINOR_OP_WREN   0x06               // Write enable
+#define SPINOR_OP_BE_4K  0x20               // Erase 4KiB block
+#define SPINOR_OP_RDID   0x9f               // Read JEDEC ID
+#define SPINOR_OP_RDSR   0x05               // Read status register
+
+#define SPINOR_SR_WIP_POLL_TIMEOUT_MS  1000u // Status Register read timeout
+
+#endif /* NOR_FLASH_DXE_H_ */
diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c
new file mode 100644
index 000000000000..fffe689161a6
--- /dev/null
+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c
@@ -0,0 +1,409 @@
+/** @file
+  NOR flash DXE
+
+  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NorFlashInfoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include "NorFlash.h"
+
+STATIC NOR_FLASH_INSTANCE  **mNorFlashInstances;
+STATIC UINT32              mNorFlashDeviceCount;
+
+STATIC EFI_EVENT  mNorFlashVirtualAddrChangeEvent;
+
+/**
+  Install Fv block onto variable store region
+
+  @param[in]   Instance         Instance of Nor flash variable region.
+
+  @retval      EFI_SUCCESS      The entry point is executed successfully.
+**/
+EFI_STATUS
+EFIAPI
+NorFlashFvbInitialize (
+  IN NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         FvbNumLba;
+  EFI_BOOT_MODE  BootMode;
+  UINTN          RuntimeMmioRegionSize;
+  UINTN          RuntimeMmioDeviceSize;
+  UINTN          BlockSize;
+
+  DEBUG ((DEBUG_INFO, "NorFlashFvbInitialize\n"));
+
+  BlockSize = Instance->BlockSize;
+
+  // FirmwareVolumeHeader->FvLength is declared to have the Variable area
+  // AND the FTW working area AND the FTW Spare contiguous.
+  ASSERT (
+    PcdGet32 (PcdFlashNvStorageVariableBase) +
+    PcdGet32 (PcdFlashNvStorageVariableSize) ==
+    PcdGet32 (PcdFlashNvStorageFtwWorkingBase)
+    );
+  ASSERT (
+    PcdGet32 (PcdFlashNvStorageFtwWorkingBase) +
+    PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ==
+    PcdGet32 (PcdFlashNvStorageFtwSpareBase)
+    );
+
+  // Check if the size of the area is at least one block size.
+  ASSERT (
+    (PcdGet32 (PcdFlashNvStorageVariableSize) > 0) &&
+    (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0)
+    );
+  ASSERT (
+    (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) &&
+    (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0)
+    );
+  ASSERT (
+    (PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) &&
+    (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0)
+    );
+
+  // Ensure the Variable areas are aligned on block size boundaries.
+  ASSERT ((PcdGet32 (PcdFlashNvStorageVariableBase) % BlockSize) == 0);
+  ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) % BlockSize) == 0);
+  ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareBase) % BlockSize) == 0);
+
+  Instance->Initialized       = TRUE;
+  mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
+
+  // Set the index of the first LBA for the FVB.
+  Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) -
+                        Instance->RegionBaseAddress) / BlockSize;
+
+  BootMode = GetBootModeHob ();
+  if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+    Status = EFI_INVALID_PARAMETER;
+  } else {
+    // Determine if there is a valid header at the beginning of the NorFlash.
+    Status = ValidateFvHeader (Instance);
+  }
+
+  // Install the Default FVB header if required.
+  if (EFI_ERROR (Status)) {
+    // There is no valid header, so time to install one.
+    DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __func__));
+    DEBUG ((
+      DEBUG_INFO,
+      "%a: Installing a correct one for this volume.\n",
+      __func__
+      ));
+
+    // Erase all the NorFlash that is reserved for variable storage.
+    FvbNumLba = (PcdGet32 (PcdFlashNvStorageVariableSize) +
+                 PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+                 PcdGet32 (PcdFlashNvStorageFtwSpareSize)) /
+                Instance->BlockSize;
+
+    Status = FvbEraseBlocks (
+               &Instance->FvbProtocol,
+               (EFI_LBA)0,
+               FvbNumLba,
+               EFI_LBA_LIST_TERMINATOR
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    // Install all appropriate headers.
+    Status = InitializeFvAndVariableStoreHeaders (Instance);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    // validate FV header again if FV was created successfully.
+    Status = ValidateFvHeader (Instance);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "ValidateFvHeader is failed \n"));
+      return Status;
+    }
+  }
+
+  // The driver implementing the variable read service can now be dispatched;
+  // the varstore headers are in place.
+  Status = gBS->InstallProtocolInterface (
+                  &gImageHandle,
+                  &gEdkiiNvVarStoreFormattedGuid,
+                  EFI_NATIVE_INTERFACE,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Failed to install gEdkiiNvVarStoreFormattedGuid\n",
+      __func__
+      ));
+    return Status;
+  }
+
+  // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME.
+  RuntimeMmioRegionSize = Instance->Size;
+  RuntimeMmioDeviceSize = Instance->RegionBaseAddress - Instance->DeviceBaseAddress;
+
+  Status = gDS->AddMemorySpace (
+                  EfiGcdMemoryTypeMemoryMappedIo,
+                  Instance->RegionBaseAddress,
+                  RuntimeMmioRegionSize,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gDS->AddMemorySpace (
+                  EfiGcdMemoryTypeMemoryMappedIo,
+                  Instance->DeviceBaseAddress,
+                  RuntimeMmioDeviceSize,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  Instance->RegionBaseAddress,
+                  RuntimeMmioRegionSize,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  Instance->DeviceBaseAddress,
+                  RuntimeMmioDeviceSize,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  Fixup internal data so that EFI can be called in virtual mode.
+  convert any pointers in lib to virtual mode.
+
+  @param[in]    Event   The Event that is being processed
+  @param[in]    Context Event Context
+**/
+STATIC
+VOID
+EFIAPI
+NorFlashVirtualNotifyEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  UINTN  Index;
+
+  EfiConvertPointer (0x0, (VOID **)&mFlashNvStorageVariableBase);
+
+  for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->HostRegisterBaseAddress
+      );
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress
+      );
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress
+      );
+
+    // Convert Fvb.
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks
+      );
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes
+      );
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize
+      );
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress
+      );
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read
+      );
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes
+      );
+    EfiConvertPointer (
+      0x0,
+      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write
+      );
+
+    if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
+      EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowBuffer);
+    }
+  }
+}
+
+/**
+  Entrypoint of Platform Nor flash DXE driver
+
+  @param[in]  ImageHandle       The firmware allocated handle for the EFI image.
+  @param[in]  SystemTable       A pointer to the EFI System Table.
+
+  @retval     EFI_SUCCESS       The entry point is executed successfully.
+**/
+EFI_STATUS
+EFIAPI
+NorFlashInitialise (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS             Status;
+  EFI_PHYSICAL_ADDRESS   HostRegisterBaseAddress;
+  UINT32                 Index;
+  NOR_FLASH_DESCRIPTION  *NorFlashDevices;
+  BOOLEAN                ContainVariableStorage;
+
+  HostRegisterBaseAddress = PcdGet32 (PcdCadenceQspiDxeRegBaseAddress);
+
+  Status = gDS->AddMemorySpace (
+                  EfiGcdMemoryTypeMemoryMappedIo,
+                  HostRegisterBaseAddress,
+                  SIZE_64KB,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  HostRegisterBaseAddress,
+                  SIZE_64KB,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  // Initialize NOR flash instances.
+  Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to get Nor Flash devices\n"));
+    return Status;
+  }
+
+  mNorFlashInstances = AllocateRuntimePool (
+                         sizeof (NOR_FLASH_INSTANCE *) *
+                         mNorFlashDeviceCount
+                         );
+
+  if (mNorFlashInstances == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "NorFlashInitialise: Failed to allocate mem for NorFlashInstance\n"
+      ));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
+    // Check if this NOR Flash device contain the variable storage region.
+    ContainVariableStorage =
+      (NorFlashDevices[Index].RegionBaseAddress <=
+       PcdGet32 (PcdFlashNvStorageVariableBase)) &&
+      (PcdGet32 (PcdFlashNvStorageVariableBase) +
+       PcdGet32 (PcdFlashNvStorageVariableSize) <=
+       NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
+
+    Status = NorFlashCreateInstance (
+               HostRegisterBaseAddress,
+               NorFlashDevices[Index].DeviceBaseAddress,
+               NorFlashDevices[Index].RegionBaseAddress,
+               NorFlashDevices[Index].Size,
+               Index,
+               NorFlashDevices[Index].BlockSize,
+               ContainVariableStorage,
+               &mNorFlashInstances[Index]
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",
+        Index
+        ));
+      continue;
+    }
+
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &mNorFlashInstances[Index]->Handle,
+                    &gEfiDevicePathProtocolGuid,
+                    &mNorFlashInstances[Index]->DevicePath,
+                    &gEfiFirmwareVolumeBlockProtocolGuid,
+                    &mNorFlashInstances[Index]->FvbProtocol,
+                    NULL
+                    );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  // Register for the virtual address change event.
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  NorFlashVirtualNotifyEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &mNorFlashVirtualAddrChangeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  Lock all pending read/write to Nor flash device
+
+  @param[in]     Context     Nor flash device context structure.
+**/
+VOID
+EFIAPI
+NorFlashLock (
+  IN NOR_FLASH_LOCK_CONTEXT  *Context
+  )
+{
+  if (!EfiAtRuntime ()) {
+    // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
+    Context->OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+  } else {
+    Context->InterruptsEnabled = SaveAndDisableInterrupts ();
+  }
+}
+
+/**
+  Unlock all pending read/write to Nor flash device
+
+  @param[in]     Context     Nor flash device context structure.
+**/
+VOID
+EFIAPI
+NorFlashUnlock (
+  IN NOR_FLASH_LOCK_CONTEXT  *Context
+  )
+{
+  if (!EfiAtRuntime ()) {
+    // Interruptions can resume.
+    gBS->RestoreTPL (Context->OriginalTPL);
+  } else if (Context->InterruptsEnabled) {
+    SetInterruptState (TRUE);
+  }
+}
diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
new file mode 100644
index 000000000000..be7b626c5697
--- /dev/null
+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
@@ -0,0 +1,1100 @@
+/** @file
+
+  Copyright (c) 2023 ARM Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/NorFlashInfoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include "NorFlash.h"
+
+STATIC CONST NOR_FLASH_INSTANCE  mNorFlashInstanceTemplate = {
+  NOR_FLASH_SIGNATURE, // Signature
+  NULL,                // Handle
+
+  FALSE, // Initialized
+  NULL,  // Initialize
+
+  0, // HostRegisterBaseAddress
+  0, // DeviceBaseAddress
+  0, // RegionBaseAddress
+  0, // Size
+  0, // BlockSize
+  0, // LastBlock
+  0, // StartLba
+  0, // OffsetLba
+
+  {
+    FvbGetAttributes,      // GetAttributes
+    FvbSetAttributes,      // SetAttributes
+    FvbGetPhysicalAddress, // GetPhysicalAddress
+    FvbGetBlockSize,       // GetBlockSize
+    FvbRead,               // Read
+    FvbWrite,              // Write
+    FvbEraseBlocks,        // EraseBlocks
+    NULL,                  // ParentHandle
+  },    //  FvbProtoccol;
+  NULL, // ShadowBuffer
+
+  {
+    {
+      {
+        HARDWARE_DEVICE_PATH,
+        HW_VENDOR_DP,
+        {
+          (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),
+          (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)
+        }
+      },
+      { 0x0,                               0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
+      },
+    },
+    0, // Index
+
+    {
+      END_DEVICE_PATH_TYPE,
+      END_ENTIRE_DEVICE_PATH_SUBTYPE,
+      { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+    }
+  }, // DevicePath
+  0  // Flags
+};
+
+/**
+  Execute Flash cmd ctrl and Read Status.
+
+  @param[in]      Instance         NOR flash Instance.
+  @param[in]      Val              Value to be written to Flash cmd ctrl Register.
+
+  @retval         EFI_SUCCESS      Request is executed successfully.
+
+**/
+STATIC
+EFI_STATUS
+CdnsQspiExecuteCommand (
+  IN  NOR_FLASH_INSTANCE  *Instance,
+  IN  UINT32              Val
+  )
+{
+  // Set the command
+  MmioWrite32 (
+    Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET,
+    Val
+    );
+  // Execute the command
+  MmioWrite32 (
+    Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET,
+    Val | CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE
+    );
+
+  // Wait until command has been executed
+  while ((MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET)
+          & CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT) == CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT)
+  {
+    continue;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Create Nor flash Instance for given region.
+
+  @param[in]    HostRegisterBase      Base address of Nor flash controller.
+  @param[in]    NorFlashDeviceBase    Base address of flash device.
+  @param[in]    NorFlashRegionBase    Base address of flash region on device.
+  @param[in]    NorFlashSize          Size of flash region.
+  @param[in]    Index                 Index of given flash region.
+  @param[in]    BlockSize             Block size of NOR flash device.
+  @param[in]    HasVarStore           Boolean set for VarStore on given region.
+  @param[out]   NorFlashInstance      Instance of given flash region.
+
+  @retval       EFI_SUCCESS           On successful creation of NOR flash instance.
+**/
+EFI_STATUS
+NorFlashCreateInstance (
+  IN UINTN                HostRegisterBase,
+  IN UINTN                NorFlashDeviceBase,
+  IN UINTN                NorFlashRegionBase,
+  IN UINTN                NorFlashSize,
+  IN UINT32               Index,
+  IN UINT32               BlockSize,
+  IN BOOLEAN              HasVarStore,
+  OUT NOR_FLASH_INSTANCE  **NorFlashInstance
+  )
+{
+  EFI_STATUS          Status;
+  NOR_FLASH_INSTANCE  *Instance;
+  NOR_FLASH_INFO      *FlashInfo;
+  UINT8               JedecId[3];
+
+  ASSERT (NorFlashInstance != NULL);
+  Instance = AllocateRuntimeCopyPool (
+               sizeof (mNorFlashInstanceTemplate),
+               &mNorFlashInstanceTemplate
+               );
+  if (Instance == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Instance->HostRegisterBaseAddress = HostRegisterBase;
+  Instance->DeviceBaseAddress       = NorFlashDeviceBase;
+  Instance->RegionBaseAddress       = NorFlashRegionBase;
+  Instance->Size                    = NorFlashSize;
+  Instance->BlockSize               = BlockSize;
+  Instance->LastBlock               = (NorFlashSize / BlockSize) - 1;
+
+  Instance->OffsetLba = (NorFlashRegionBase - NorFlashDeviceBase) / BlockSize;
+
+  CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);
+  Instance->DevicePath.Index = (UINT8)Index;
+
+  Status = NorFlashReadID (Instance, JedecId);
+  if (EFI_ERROR (Status)) {
+    goto FreeInstance;
+  }
+
+  Status = NorFlashGetInfo (JedecId, &FlashInfo, TRUE);
+  if (EFI_ERROR (Status)) {
+    goto FreeInstance;
+  }
+
+  NorFlashPrintInfo (FlashInfo);
+
+  Instance->Flags = 0;
+  if (FlashInfo->Flags & NOR_FLASH_WRITE_FSR) {
+    Instance->Flags = NOR_FLASH_POLL_FSR;
+  }
+
+  Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);
+  if (Instance->ShadowBuffer == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto FreeInstance;
+  }
+
+  if (HasVarStore) {
+    Instance->Initialize = NorFlashFvbInitialize;
+  }
+
+  *NorFlashInstance = Instance;
+  FreePool (FlashInfo);
+  return EFI_SUCCESS;
+
+FreeInstance:
+  FreePool (Instance);
+  return Status;
+}
+
+/**
+  Converts milliseconds into number of ticks of the performance counter.
+
+  @param[in] Milliseconds  Milliseconds to convert into ticks.
+
+  @retval Milliseconds expressed as number of ticks.
+
+**/
+STATIC
+UINT64
+MilliSecondsToTicks (
+  IN UINTN  Milliseconds
+  )
+{
+  CONST UINT64  NanoSecondsPerTick = GetTimeInNanoSecond (1);
+
+  return (Milliseconds * 1000000) / NanoSecondsPerTick;
+}
+
+/**
+  Poll Status register for NOR flash erase/write completion.
+
+  @param[in]      Instance           NOR flash Instance.
+
+  @retval         EFI_SUCCESS        Request is executed successfully.
+  @retval         EFI_TIMEOUT        Operation timed out.
+  @retval         EFI_DEVICE_ERROR   Controller operartion failed.
+
+**/
+STATIC
+EFI_STATUS
+NorFlashPollStatusRegister (
+  IN NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  BOOLEAN  SRegDone;
+  UINT32   val;
+
+  val = SPINOR_OP_RDSR << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
+        CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS |
+        CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES (1) |
+        CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C << CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_BIT_POS;
+
+  CONST UINT64  TickOut =
+    GetPerformanceCounter () + MilliSecondsToTicks (SPINOR_SR_WIP_POLL_TIMEOUT_MS);
+
+  do {
+    if (GetPerformanceCounter () > TickOut) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "NorFlashPollStatusRegister: Timeout waiting for erase/write.\n"
+        ));
+      return EFI_TIMEOUT;
+    }
+
+    if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
+      return EFI_DEVICE_ERROR;
+    }
+
+    SRegDone =
+      (MmioRead8 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET)
+       & SPINOR_SR_WIP) == 0;
+  } while (!SRegDone);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Check whether NOR flash opertions are Locked.
+
+  @param[in]     Instance         NOR flash Instance.
+  @param[in]     BlockAddress     BlockAddress in NOR flash device.
+
+  @retval        FALSE            If NOR flash is not locked.
+**/
+STATIC
+BOOLEAN
+NorFlashBlockIsLocked (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               BlockAddress
+  )
+{
+  return FALSE;
+}
+
+/**
+  Unlock NOR flash operations on given block.
+
+  @param[in]      Instance         NOR flash instance.
+  @param[in]      BlockAddress     BlockAddress in NOR flash device.
+
+  @retval         EFI_SUCCESS      NOR flash operations is unlocked.
+**/
+STATIC
+EFI_STATUS
+NorFlashUnlockSingleBlock (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               BlockAddress
+  )
+{
+  return EFI_SUCCESS;
+}
+
+/**
+  Unlock NOR flash operations if it is necessary.
+
+  @param[in]      Instance         NOR flash instance.
+  @param[in]      BlockAddress     BlockAddress in NOR flash device.
+
+  @retval         EFI_SUCCESS      Request is executed successfully.
+**/
+STATIC
+EFI_STATUS
+NorFlashUnlockSingleBlockIfNecessary (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               BlockAddress
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  if (!NorFlashBlockIsLocked (Instance, BlockAddress)) {
+    Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
+  }
+
+  return Status;
+}
+
+/**
+  Enable write to NOR flash device.
+
+  @param[in]      Instance         NOR flash instance.
+
+  @retval         EFI_SUCCESS      Request is executed successfully.
+**/
+STATIC
+EFI_STATUS
+NorFlashEnableWrite (
+  IN  NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  UINT32  val;
+
+  DEBUG ((DEBUG_INFO, "NorFlashEnableWrite()\n"));
+  val = (SPINOR_OP_WREN << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS);
+  if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  The following function presumes that the block has already been unlocked.
+
+  @param[in]      Instance         NOR flash instance.
+  @param[in]      BlockAddress     Block address within the variable region.
+
+  @retval         EFI_SUCCESS      Request is executed successfully.
+ **/
+EFI_STATUS
+NorFlashEraseSingleBlock (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               BlockAddress
+  )
+{
+  UINT32  DevConfigVal;
+  UINT32  EraseOffset;
+
+  EraseOffset = 0x0;
+
+  DEBUG ((
+    DEBUG_INFO,
+    "NorFlashEraseSingleBlock(BlockAddress=0x%08x)\n",
+    BlockAddress
+    ));
+
+  if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  EraseOffset = BlockAddress - Instance->DeviceBaseAddress;
+
+  MmioWrite32 (
+    Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_ADDR_REG_OFFSET,
+    EraseOffset
+    );
+
+  DevConfigVal = SPINOR_OP_BE_4K << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
+                 CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS |
+                 CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES (3);
+
+  if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, DevConfigVal))) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function unlock and erase an entire NOR Flash block.
+
+  @param[in]     Instance       NOR flash Instance of variable store region.
+  @param[in]     BlockAddress   Block address within the variable store region.
+
+  @retval        EFI_SUCCESS    The erase and unlock successfully completed.
+**/
+EFI_STATUS
+NorFlashUnlockAndEraseSingleBlock (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               BlockAddress
+  )
+{
+  EFI_STATUS              Status;
+  UINTN                   Index;
+  NOR_FLASH_LOCK_CONTEXT  Lock;
+
+  NorFlashLock (&Lock);
+
+  Index = 0;
+  do {
+    // Unlock the block if we have to
+    Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    Index++;
+  } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
+
+  if (Index == NOR_FLASH_ERASE_RETRY) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n",
+      BlockAddress,
+      Index
+      ));
+  }
+
+  NorFlashUnlock (&Lock);
+
+  return Status;
+}
+
+/**
+  Write a single word to given location.
+
+  @param[in]    Instance     NOR flash Instance of variable store region.
+  @param[in]    WordAddress  The address in NOR flash to write given word.
+  @param[in]    WriteData    The data to write into NOR flash location.
+
+  @retval       EFI_SUCCESS  The write is completed.
+**/
+STATIC
+EFI_STATUS
+NorFlashWriteSingleWord (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               WordAddress,
+  IN UINT32              WriteData
+  )
+{
+  DEBUG ((
+    DEBUG_INFO,
+    "NorFlashWriteSingleWord(WordAddress=0x%08x, WriteData=0x%08x)\n",
+    WordAddress,
+    WriteData
+    ));
+
+  if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  MmioWrite32 (WordAddress, WriteData);
+  if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Write a full block to given location.
+
+  @param[in]    Instance           NOR flash Instance of variable store region.
+  @param[in]    Lba                The logical block address in NOR flash.
+  @param[in]    DataBuffer         The data to write into NOR flash location.
+  @param[in]    BlockSizeInWords   The number of bytes to write.
+
+  @retval       EFI_SUCCESS        The write is completed.
+**/
+STATIC
+EFI_STATUS
+NorFlashWriteFullBlock (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN EFI_LBA             Lba,
+  IN UINT32              *DataBuffer,
+  IN UINT32              BlockSizeInWords
+  )
+{
+  EFI_STATUS              Status;
+  UINTN                   WordAddress;
+  UINT32                  WordIndex;
+  UINTN                   BlockAddress;
+  NOR_FLASH_LOCK_CONTEXT  Lock;
+
+  Status = EFI_SUCCESS;
+
+  // Get the physical address of the block
+  BlockAddress = GET_NOR_BLOCK_ADDRESS (
+                   Instance->RegionBaseAddress,
+                   Lba,
+                   BlockSizeInWords * 4
+                   );
+
+  // Start writing from the first address at the start of the block
+  WordAddress = BlockAddress;
+
+  NorFlashLock (&Lock);
+
+  Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n",
+      BlockAddress
+      ));
+    goto EXIT;
+  }
+
+  for (WordIndex = 0;
+       WordIndex < BlockSizeInWords;
+       WordIndex++, DataBuffer++, WordAddress += 4)
+  {
+    Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
+    if (EFI_ERROR (Status)) {
+      goto EXIT;
+    }
+  }
+
+EXIT:
+  NorFlashUnlock (&Lock);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = %r.\n",
+      WordAddress,
+      Status
+      ));
+  }
+
+  return Status;
+}
+
+/**
+  Write a full  block.
+
+  @param[in]    Instance           NOR flash Instance of variable store region.
+  @param[in]    Lba                The starting logical block index.
+  @param[in]    BufferSizeInBytes  The number of bytes to read.
+  @param[in]    Buffer             The pointer to a caller-allocated buffer that
+                                   contains the source for the write.
+
+  @retval       EFI_SUCCESS        The write is completed.
+**/
+EFI_STATUS
+NorFlashWriteBlocks (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN EFI_LBA             Lba,
+  IN UINTN               BufferSizeInBytes,
+  IN VOID                *Buffer
+  )
+{
+  UINT32      *pWriteBuffer;
+  EFI_STATUS  Status;
+  EFI_LBA     CurrentBlock;
+  UINT32      BlockSizeInWords;
+  UINT32      NumBlocks;
+  UINT32      BlockCount;
+
+  Status = EFI_SUCCESS;
+  // The buffer must be valid
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // We must have some bytes to read
+  DEBUG ((
+    DEBUG_INFO,
+    "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n",
+    BufferSizeInBytes
+    ));
+  if (BufferSizeInBytes == 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // The size of the buffer must be a multiple of the block size
+  DEBUG ((
+    DEBUG_INFO,
+    "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n",
+    Instance->BlockSize
+    ));
+  if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // All blocks must be within the device
+  NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
+
+  DEBUG ((
+    DEBUG_INFO,
+    "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n",
+    NumBlocks,
+    Instance->LastBlock,
+    Lba
+    ));
+
+  if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"
+      ));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  ASSERT (((UINTN)Buffer % sizeof (UINT32)) == 0);
+
+  BlockSizeInWords = Instance->BlockSize / 4;
+
+  // Because the target *Buffer is a pointer to VOID, we must put
+  // all the data into a pointer to a proper data type, so use *ReadBuffer
+  pWriteBuffer = (UINT32 *)Buffer;
+
+  CurrentBlock = Lba;
+  for (BlockCount = 0;
+       BlockCount < NumBlocks;
+       BlockCount++, CurrentBlock++, pWriteBuffer += BlockSizeInWords)
+  {
+    DEBUG ((
+      DEBUG_INFO,
+      "NorFlashWriteBlocks: Writing block #%d\n",
+      (UINTN)CurrentBlock
+      ));
+
+    Status = NorFlashWriteFullBlock (
+               Instance,
+               CurrentBlock,
+               pWriteBuffer,
+               BlockSizeInWords
+               );
+
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+  }
+
+  DEBUG ((DEBUG_INFO, "NorFlashWriteBlocks: Exit Status = %r.\n", Status));
+  return Status;
+}
+
+/**
+  Read a full  block.
+
+  @param[in]     Instance           NOR flash Instance of variable store region.
+  @param[in]     Lba                The starting logical block index to read from.
+  @param[in]     BufferSizeInBytes  The number of bytes to read.
+  @param[out]    Buffer             The pointer to a caller-allocated buffer that
+                                    should be copied with read data.
+
+  @retval        EFI_SUCCESS        The read is completed.
+**/
+EFI_STATUS
+NorFlashReadBlocks (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN EFI_LBA             Lba,
+  IN UINTN               BufferSizeInBytes,
+  OUT VOID               *Buffer
+  )
+{
+  UINT32  NumBlocks;
+  UINTN   StartAddress;
+
+  DEBUG ((
+    DEBUG_INFO,
+    "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
+    BufferSizeInBytes,
+    Instance->BlockSize,
+    Instance->LastBlock,
+    Lba
+    ));
+
+  // The buffer must be valid
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Return if we do not have any byte to read
+  if (BufferSizeInBytes == 0) {
+    return EFI_SUCCESS;
+  }
+
+  // The size of the buffer must be a multiple of the block size
+  if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
+
+  if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "NorFlashReadBlocks: ERROR - Read will exceed last block\n"
+      ));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get the address to start reading from
+  StartAddress = GET_NOR_BLOCK_ADDRESS (
+                   Instance->RegionBaseAddress,
+                   Lba,
+                   Instance->BlockSize
+                   );
+
+  // Readout the data
+  CopyMem (Buffer, (UINTN *)StartAddress, BufferSizeInBytes);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Read from nor flash.
+
+  @param[in]     Instance           NOR flash Instance of variable store region.
+  @param[in]     Lba                The starting logical block index to read from.
+  @param[in]     Offset             Offset into the block at which to begin reading.
+  @param[in]     BufferSizeInBytes  The number of bytes to read.
+  @param[out]    Buffer             The pointer to a caller-allocated buffer that
+                                    should copied with read data.
+
+  @retval        EFI_SUCCESS        The read is completed.
+**/
+EFI_STATUS
+NorFlashRead (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN EFI_LBA             Lba,
+  IN UINTN               Offset,
+  IN UINTN               BufferSizeInBytes,
+  OUT VOID               *Buffer
+  )
+{
+  UINTN  StartAddress;
+
+  // The buffer must be valid
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Return if we do not have any byte to read
+  if (BufferSizeInBytes == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if (((Lba * Instance->BlockSize) + Offset + BufferSizeInBytes) >
+      Instance->Size)
+  {
+    DEBUG ((
+      DEBUG_ERROR,
+      "NorFlashRead: ERROR - Read will exceed device size.\n"
+      ));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Get the address to start reading from
+  StartAddress = GET_NOR_BLOCK_ADDRESS (
+                   Instance->RegionBaseAddress,
+                   Lba,
+                   Instance->BlockSize
+                   );
+
+  // Readout the data
+  CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Write a full or portion of a block.
+
+  @param[in]         Instance     NOR flash Instance of variable store region.
+  @param[in]         Lba          The starting logical block index to write to.
+  @param[in]         Offset       Offset into the block at which to begin writing.
+  @param[in, out]    NumBytes     The total size of the buffer.
+  @param[in]         Buffer       The pointer to a caller-allocated buffer that
+                                  contains the source for the write.
+
+  @retval            EFI_SUCCESS  The write is completed.
+**/
+EFI_STATUS
+NorFlashWriteSingleBlock (
+  IN        NOR_FLASH_INSTANCE  *Instance,
+  IN        EFI_LBA             Lba,
+  IN        UINTN               Offset,
+  IN OUT    UINTN               *NumBytes,
+  IN        UINT8               *Buffer
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      Tmp;
+  UINT32      TmpBuf;
+  UINT32      WordToWrite;
+  UINT32      Mask;
+  BOOLEAN     DoErase;
+  UINTN       BytesToWrite;
+  UINTN       CurOffset;
+  UINTN       WordAddr;
+  UINTN       BlockSize;
+  UINTN       BlockAddress;
+  UINTN       PrevBlockAddress;
+
+  if (Buffer == NULL) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "NorFlashWriteSingleBlock: ERROR - Buffer is invalid\n"
+      ));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  PrevBlockAddress = 0;
+  if (!Instance->Initialized && Instance->Initialize) {
+    Instance->Initialize (Instance);
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n",
+    Lba,
+    Offset,
+    *NumBytes,
+    Buffer
+    ));
+
+  // Localise the block size to avoid de-referencing pointers all the time
+  BlockSize = Instance->BlockSize;
+
+  // The write must not span block boundaries.
+  // We need to check each variable individually because adding two large
+  // values together overflows.
+  if ((Offset               >= BlockSize) ||
+      (*NumBytes            >  BlockSize) ||
+      ((Offset + *NumBytes) >  BlockSize))
+  {
+    DEBUG ((
+      DEBUG_ERROR,
+      "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
+      Offset,
+      *NumBytes,
+      BlockSize
+      ));
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // We must have some bytes to write
+  if (*NumBytes == 0) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
+      Offset,
+      *NumBytes,
+      BlockSize
+      ));
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // Pick 128bytes as a good start for word operations as opposed to erasing the
+  // block and writing the data regardless if an erase is really needed.
+  // It looks like most individual NV variable writes are smaller than 128bytes.
+  if (*NumBytes <= 128) {
+    // Check to see if we need to erase before programming the data into NOR.
+    // If the destination bits are only changing from 1s to 0s we can just write.
+    // After a block is erased all bits in the block is set to 1.
+    // If any byte requires us to erase we just give up and rewrite all of it.
+    DoErase      = FALSE;
+    BytesToWrite = *NumBytes;
+    CurOffset    = Offset;
+
+    while (BytesToWrite > 0) {
+      // Read full word from NOR, splice as required. A word is the smallest
+      // unit we can write.
+      Status = NorFlashRead (
+                 Instance,
+                 Lba,
+                 CurOffset & ~(0x3),
+                 sizeof (Tmp),
+                 &Tmp
+                 );
+      if (EFI_ERROR (Status)) {
+        return EFI_DEVICE_ERROR;
+      }
+
+      // Physical address of word in NOR to write.
+      WordAddr = (CurOffset & ~(0x3)) +
+                 GET_NOR_BLOCK_ADDRESS (
+                   Instance->RegionBaseAddress,
+                   Lba,
+                   BlockSize
+                   );
+
+      // The word of data that is to be written.
+      TmpBuf = ReadUnaligned32 ((UINT32 *)(Buffer + (*NumBytes - BytesToWrite)));
+
+      // First do word aligned chunks.
+      if ((CurOffset & 0x3) == 0) {
+        if (BytesToWrite >= 4) {
+          // Is the destination still in 'erased' state?
+          if (~Tmp != 0) {
+            // Check to see if we are only changing bits to zero.
+            if ((Tmp ^ TmpBuf) & TmpBuf) {
+              DoErase = TRUE;
+              break;
+            }
+          }
+
+          // Write this word to NOR
+          WordToWrite   = TmpBuf;
+          CurOffset    += sizeof (TmpBuf);
+          BytesToWrite -= sizeof (TmpBuf);
+        } else {
+          // BytesToWrite < 4. Do small writes and left-overs
+          Mask = ~((~0) << (BytesToWrite * 8));
+          // Mask out the bytes we want.
+          TmpBuf &= Mask;
+          // Is the destination still in 'erased' state?
+          if ((Tmp & Mask) != Mask) {
+            // Check to see if we are only changing bits to zero.
+            if ((Tmp ^ TmpBuf) & TmpBuf) {
+              DoErase = TRUE;
+              break;
+            }
+          }
+
+          // Merge old and new data. Write merged word to NOR
+          WordToWrite  = (Tmp & ~Mask) | TmpBuf;
+          CurOffset   += BytesToWrite;
+          BytesToWrite = 0;
+        }
+      } else {
+        // Do multiple words, but starting unaligned.
+        if (BytesToWrite > (4 - (CurOffset & 0x3))) {
+          Mask = ((~0) << ((CurOffset & 0x3) * 8));
+          // Mask out the bytes we want.
+          TmpBuf &= Mask;
+          // Is the destination still in 'erased' state?
+          if ((Tmp & Mask) != Mask) {
+            // Check to see if we are only changing bits to zero.
+            if ((Tmp ^ TmpBuf) & TmpBuf) {
+              DoErase = TRUE;
+              break;
+            }
+          }
+
+          // Merge old and new data. Write merged word to NOR
+          WordToWrite   = (Tmp & ~Mask) | TmpBuf;
+          BytesToWrite -= (4 - (CurOffset & 0x3));
+          CurOffset    += (4 - (CurOffset & 0x3));
+        } else {
+          // Unaligned and fits in one word.
+          Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8);
+          // Mask out the bytes we want.
+          TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;
+          // Is the destination still in 'erased' state?
+          if ((Tmp & Mask) != Mask) {
+            // Check to see if we are only changing bits to zero.
+            if ((Tmp ^ TmpBuf) & TmpBuf) {
+              DoErase = TRUE;
+              break;
+            }
+          }
+
+          // Merge old and new data. Write merged word to NOR
+          WordToWrite  = (Tmp & ~Mask) | TmpBuf;
+          CurOffset   += BytesToWrite;
+          BytesToWrite = 0;
+        }
+      }
+
+      BlockAddress = GET_NOR_BLOCK_ADDRESS (
+                       Instance->RegionBaseAddress,
+                       Lba,
+                       BlockSize
+                       );
+      if (BlockAddress != PrevBlockAddress) {
+        Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
+        if (EFI_ERROR (Status)) {
+          return EFI_DEVICE_ERROR;
+        }
+
+        PrevBlockAddress = BlockAddress;
+      }
+
+      Status = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite);
+      if (EFI_ERROR (Status)) {
+        return EFI_DEVICE_ERROR;
+      }
+    }
+
+    // Exit if we got here and could write all the data. Otherwise do the
+    // Erase-Write cycle.
+    if (!DoErase) {
+      return EFI_SUCCESS;
+    }
+  }
+
+  // Check we did get some memory. Buffer is BlockSize.
+  if (Instance->ShadowBuffer == NULL) {
+    DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Read NOR Flash data into shadow buffer
+  Status = NorFlashReadBlocks (
+             Instance,
+             Lba,
+             BlockSize,
+             Instance->ShadowBuffer
+             );
+  if (EFI_ERROR (Status)) {
+    // Return one of the pre-approved error statuses
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Put the data at the appropriate location inside the buffer area
+  CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
+
+  // Write the modified buffer back to the NorFlash
+  Status = NorFlashWriteBlocks (
+             Instance,
+             Lba,
+             BlockSize,
+             Instance->ShadowBuffer
+             );
+  if (EFI_ERROR (Status)) {
+    // Return one of the pre-approved error statuses
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Read JEDEC ID of NOR flash device.
+
+  @param[in]     Instance     NOR flash Instance of variable store region.
+  @param[out]    JedecId      JEDEC ID of NOR flash device.
+
+  @retval        EFI_SUCCESS  The write is completed.
+**/
+EFI_STATUS
+NorFlashReadID (
+  IN  NOR_FLASH_INSTANCE  *Instance,
+  OUT UINT8               JedecId[3]
+  )
+{
+  UINT32  val;
+
+  if ((Instance == NULL) || (JedecId == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  val = SPINOR_OP_RDID << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
+        CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS |
+        CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES (3);
+
+  if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  val = MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET);
+
+  // Manu.ID field
+  JedecId[0] = (UINT8)val;
+  // Type field
+  JedecId[1] = (UINT8)(val >> 8);
+  // Capacity field
+  JedecId[2] = (UINT8)(val >> 16);
+
+  DEBUG ((
+    DEBUG_INFO,
+    "Nor flash detected, Jedec ID, Manu.Id=%x Type=%x Capacity=%x \n",
+    JedecId[0],
+    JedecId[1],
+    JedecId[2]
+    ));
+
+  return EFI_SUCCESS;
+}
diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c
new file mode 100644
index 000000000000..8281d4825dc9
--- /dev/null
+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c
@@ -0,0 +1,647 @@
+/** @file
+
+  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Guid/VariableFormat.h>
+#include <Guid/SystemNvDataGuid.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <PiDxe.h>
+
+#include "NorFlash.h"
+
+UINTN  mFlashNvStorageVariableBase;
+
+/**
+  Initialize the FV Header and Variable Store Header
+  to support variable operations.
+
+  @param[in]  Instance      Location to initialise the headers.
+
+  @retval     EFI_SUCCESS   Fv init is done.
+
+**/
+EFI_STATUS
+InitializeFvAndVariableStoreHeaders (
+  IN NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_STATUS                  Status;
+  VOID                        *Headers;
+  UINTN                       HeadersLength;
+  EFI_FIRMWARE_VOLUME_HEADER  *FirmwareVolumeHeader;
+  VARIABLE_STORE_HEADER       *VariableStoreHeader;
+
+  if (!Instance->Initialized && Instance->Initialize) {
+    Instance->Initialize (Instance);
+  }
+
+  HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+                  sizeof (EFI_FV_BLOCK_MAP_ENTRY) +
+                  sizeof (VARIABLE_STORE_HEADER);
+  Headers = AllocateZeroPool (HeadersLength);
+
+  FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Headers;
+  CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
+  FirmwareVolumeHeader->FvLength =
+    PcdGet32 (PcdFlashNvStorageVariableSize) +
+    PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+    PcdGet32 (PcdFlashNvStorageFtwSpareSize);
+  FirmwareVolumeHeader->Signature  = EFI_FVH_SIGNATURE;
+  FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP |
+                                     EFI_FVB2_READ_STATUS |
+                                     EFI_FVB2_STICKY_WRITE |
+                                     EFI_FVB2_MEMORY_MAPPED |
+                                     EFI_FVB2_ERASE_POLARITY |
+                                     EFI_FVB2_WRITE_STATUS |
+                                     EFI_FVB2_WRITE_ENABLED_CAP;
+
+  FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+                                       sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+  FirmwareVolumeHeader->Revision              = EFI_FVH_REVISION;
+  FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->LastBlock + 1;
+  FirmwareVolumeHeader->BlockMap[0].Length    = Instance->BlockSize;
+  FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
+  FirmwareVolumeHeader->BlockMap[1].Length    = 0;
+  FirmwareVolumeHeader->Checksum              = CalculateCheckSum16 (
+                                                  (UINT16 *)FirmwareVolumeHeader,
+                                                  FirmwareVolumeHeader->HeaderLength
+                                                  );
+
+  VariableStoreHeader = (VOID *)((UINTN)Headers +
+                                 FirmwareVolumeHeader->HeaderLength);
+  CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
+  VariableStoreHeader->Size = PcdGet32 (PcdFlashNvStorageVariableSize) -
+                              FirmwareVolumeHeader->HeaderLength;
+  VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
+  VariableStoreHeader->State  = VARIABLE_STORE_HEALTHY;
+
+  // Install the combined super-header in the NorFlash
+  Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
+
+  FreePool (Headers);
+  return Status;
+}
+
+/**
+  Check the integrity of firmware volume header.
+
+  @param[in]  Instance        Instance of Nor flash variable region.
+
+  @retval     EFI_SUCCESS     The firmware volume is consistent.
+  @retval     EFI_NOT_FOUND   The firmware volume has been corrupted.
+
+**/
+EFI_STATUS
+ValidateFvHeader (
+  IN  NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;
+  VARIABLE_STORE_HEADER       *VariableStoreHeader;
+  UINTN                       VariableStoreLength;
+  UINTN                       FvLength;
+
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Instance->RegionBaseAddress;
+
+  FvLength = PcdGet32 (PcdFlashNvStorageVariableSize) +
+             PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+             PcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+  if (  (FwVolHeader->Revision  != EFI_FVH_REVISION)
+     || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)
+     || (FwVolHeader->FvLength  != FvLength)
+        )
+  {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: No Firmware Volume header present\n",
+      __func__
+      ));
+    return EFI_NOT_FOUND;
+  }
+
+  // Check the Firmware Volume Guid
+  if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Firmware Volume Guid non-compatible\n",
+      __func__
+      ));
+    return EFI_NOT_FOUND;
+  }
+
+  VariableStoreHeader = (VOID *)((UINTN)FwVolHeader +
+                                 FwVolHeader->HeaderLength);
+
+  // Check the Variable Store Guid
+  if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
+      !CompareGuid (
+         &VariableStoreHeader->Signature,
+         &gEfiAuthenticatedVariableGuid
+         ))
+  {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Variable Store Guid non-compatible\n",
+      __func__
+      ));
+    return EFI_NOT_FOUND;
+  }
+
+  VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) -
+                        FwVolHeader->HeaderLength;
+  if (VariableStoreHeader->Size != VariableStoreLength) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: Variable Store Length does not match\n",
+      __func__
+      ));
+    return EFI_NOT_FOUND;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the attributes and current settings of the block.
+
+ @param[in]   This         Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[out]  Attributes   Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
+                           current settings are returned.
+                           Type EFI_FVB_ATTRIBUTES_2 is defined in
+                           EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval      EFI_SUCCESS  The firmware volume attributes were returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbGetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes
+  )
+{
+  EFI_FVB_ATTRIBUTES_2  FlashFvbAttributes;
+
+  FlashFvbAttributes = EFI_FVB2_READ_ENABLED_CAP | EFI_FVB2_READ_STATUS |
+                       EFI_FVB2_WRITE_ENABLED_CAP | EFI_FVB2_WRITE_STATUS |
+                       EFI_FVB2_STICKY_WRITE | EFI_FVB2_MEMORY_MAPPED |
+                       EFI_FVB2_ERASE_POLARITY;
+
+  *Attributes = FlashFvbAttributes;
+
+  DEBUG ((DEBUG_INFO, "FvbGetAttributes(0x%X)\n", *Attributes));
+
+  return EFI_SUCCESS;
+}
+
+/**
+ Sets configurable firmware volume attributes and returns the
+ new settings of the firmware volume.
+
+
+ @param[in]         This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[in, out]    Attributes               On input, Attributes is a pointer to
+                                             EFI_FVB_ATTRIBUTES_2 that contains the desired
+                                             firmware volume settings.
+                                             On successful return, it contains the new
+                                             settings of the firmware volume.
+
+ @retval            EFI_UNSUPPORTED          The firmware volume attributes are not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbSetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
+  )
+{
+  DEBUG ((
+    DEBUG_INFO,
+    "FvbSetAttributes(0x%X) is not supported\n",
+    *Attributes
+    ));
+  return EFI_UNSUPPORTED;
+}
+
+/**
+ Retrieves the base address of a memory-mapped firmware volume.
+ This function should be called only for memory-mapped firmware volumes.
+
+ @param[in]     This               EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[out]    Address            Pointer to a caller-allocated
+                                   EFI_PHYSICAL_ADDRESS that, on successful
+                                   return from GetPhysicalAddress(), contains the
+                                   base address of the firmware volume.
+
+ @retval        EFI_SUCCESS        The firmware volume base address was returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_PHYSICAL_ADDRESS                 *Address
+  )
+{
+  NOR_FLASH_INSTANCE  *Instance;
+
+  Instance = INSTANCE_FROM_FVB_THIS (This);
+
+  DEBUG ((
+    DEBUG_INFO,
+    "FvbGetPhysicalAddress(BaseAddress=0x%08x)\n",
+    Instance->RegionBaseAddress
+    ));
+
+  ASSERT (Address != NULL);
+
+  *Address = Instance->RegionBaseAddress;
+  return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the size of the requested block.
+ It also returns the number of additional blocks with the identical size.
+ The GetBlockSize() function is used to retrieve the block map
+ (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+ @param[in]     This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[in]     Lba                      Indicates the block whose size to return
+
+ @param[out]    BlockSize                Pointer to a caller-allocated UINTN in which
+                                         the size of the block is returned.
+
+ @param[out]    NumberOfBlocks           Pointer to a caller-allocated UINTN in
+                                         which the number of consecutive blocks,
+                                         starting with Lba, is returned. All
+                                         blocks in this range have a size of
+                                         BlockSize.
+
+ @retval        EFI_SUCCESS              The firmware volume base address was returned.
+
+ @retval        EFI_INVALID_PARAMETER    The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  OUT       UINTN                                *BlockSize,
+  OUT       UINTN                                *NumberOfBlocks
+  )
+{
+  EFI_STATUS          Status;
+  NOR_FLASH_INSTANCE  *Instance;
+
+  Instance = INSTANCE_FROM_FVB_THIS (This);
+
+  DEBUG ((
+    DEBUG_INFO,
+    "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n",
+    Lba,
+    Instance->BlockSize,
+    Instance->LastBlock
+    ));
+
+  if (Lba > Instance->LastBlock) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (%ld).\n",
+      Lba,
+      Instance->LastBlock
+      ));
+    Status = EFI_INVALID_PARAMETER;
+  } else {
+    // This is easy because in this platform each NorFlash device has equal sized blocks.
+    *BlockSize      = (UINTN)Instance->BlockSize;
+    *NumberOfBlocks = (UINTN)(Instance->LastBlock - Lba + 1);
+
+    DEBUG ((
+      DEBUG_INFO,
+      "FvbGetBlockSize: *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n",
+      *BlockSize,
+      *NumberOfBlocks
+      ));
+
+    Status = EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+/**
+ Reads the specified number of bytes into a buffer from the specified block.
+
+ The Read() function reads the requested number of bytes from the
+ requested block and stores them in the provided buffer.
+
+ @param[in]       This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[in]       Lba                  The starting logical block index from which to read
+
+ @param[in]       Offset               Offset into the block at which to begin reading.
+
+ @param[in, out]  NumBytes             Pointer to a UINTN.
+                                       At entry, *NumBytes contains the total size of the
+                                       buffer. *NumBytes should have a non zero value.
+                                       At exit, *NumBytes contains the total number of
+                                       bytes read.
+
+ @param[in, out]  Buffer               Pointer to a caller-allocated buffer that will be
+                                       used to hold the data that is read.
+
+ @retval          EFI_SUCCESS          The firmware volume was read successfully, and
+                                       contents are in Buffer.
+
+ @retval          EFI_BAD_BUFFER_SIZE  Read attempted across an LBA boundary.
+
+ @retval          EFI_DEVICE_ERROR     The block device is not functioning correctly and
+                                       could not be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbRead (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN OUT    UINT8                                *Buffer
+  )
+{
+  EFI_STATUS          Status;
+  UINTN               BlockSize;
+  NOR_FLASH_INSTANCE  *Instance;
+
+  Instance = INSTANCE_FROM_FVB_THIS (This);
+
+  DEBUG ((
+    DEBUG_INFO,
+    "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n",
+    Instance->StartLba + Lba,
+    Offset,
+    *NumBytes,
+    Buffer
+    ));
+
+  if (!Instance->Initialized && Instance->Initialize) {
+    Instance->Initialize (Instance);
+  }
+
+  BlockSize = Instance->BlockSize;
+
+  DEBUG ((
+    DEBUG_INFO,
+    "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n",
+    Offset,
+    *NumBytes,
+    BlockSize
+    ));
+
+  // The read must not span block boundaries.
+  // We need to check each variable individually because adding two large
+  // values together overflows.
+  if ((Offset               >= BlockSize) ||
+      (*NumBytes            >  BlockSize) ||
+      ((Offset + *NumBytes) >  BlockSize))
+  {
+    DEBUG ((
+      DEBUG_ERROR,
+      "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
+      Offset,
+      *NumBytes,
+      BlockSize
+      ));
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // We must have some bytes to read
+  if (*NumBytes == 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // Decide if we are doing full block reads or not.
+  if (*NumBytes % BlockSize != 0) {
+    Status = NorFlashRead (
+               Instance,
+               Instance->StartLba + Lba,
+               Offset,
+               *NumBytes,
+               Buffer
+               );
+  } else {
+    // Read NOR Flash data into shadow buffer
+    Status = NorFlashReadBlocks (
+               Instance,
+               Instance->StartLba + Lba,
+               BlockSize,
+               Buffer
+               );
+  }
+
+  if (EFI_ERROR (Status)) {
+    // Return one of the pre-approved error statuses
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ @param[in]        This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param[in]        Lba                  The starting logical block index to write to.
+
+ @param[in]        Offset               Offset into the block at which to begin writing.
+
+ @param[in, out]   NumBytes             The pointer to a UINTN.
+                                        At entry, *NumBytes contains the total size of the
+                                        buffer.
+                                        At exit, *NumBytes contains the total number of
+                                        bytes actually written.
+
+ @param[in]        Buffer               The pointer to a caller-allocated buffer that
+                                        contains the source for the write.
+
+ @retval           EFI_SUCCESS          The firmware volume was written successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbWrite (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN        UINT8                                *Buffer
+  )
+{
+  NOR_FLASH_INSTANCE  *Instance;
+
+  Instance = INSTANCE_FROM_FVB_THIS (This);
+
+  return NorFlashWriteSingleBlock (
+           Instance,
+           Instance->StartLba + Lba,
+           Offset,
+           NumBytes,
+           Buffer
+           );
+}
+
+/**
+ Erases and initialises a firmware volume block.
+
+ @param[in]   This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
+
+ @param[in]   ...                      The variable argument list is a list of tuples.
+                                       Each tuple describes a range of LBAs to erase
+                                       and consists of the following:
+                                       - An EFI_LBA that indicates the starting LBA
+                                       - A UINTN that indicates the number of blocks
+                                       to erase.
+
+                                       The list is terminated with an
+                                       EFI_LBA_LIST_TERMINATOR.
+
+ @retval      EFI_SUCCESS              The erase request successfully completed.
+
+ @retval      EFI_ACCESS_DENIED        The firmware volume is in the WriteDisabled
+                                       state.
+
+ @retval      EFI_DEVICE_ERROR         The block device is not functioning correctly
+                                       and could not be written.
+                                       The firmware device may have been partially
+                                       erased.
+
+ @retval      EFI_INVALID_PARAMETER   One or more of the LBAs listed in the variable
+                                      argument list do not exist in the firmware
+                                      volume.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  ...
+  )
+{
+  EFI_STATUS          Status;
+  VA_LIST             Args;
+  UINTN               BlockAddress; // Physical address of Lba to erase
+  EFI_LBA             StartingLba;  // Lba from which we start erasing
+  UINTN               NumOfLba;     // Number of Lba blocks to erase
+  NOR_FLASH_INSTANCE  *Instance;
+
+  Instance = INSTANCE_FROM_FVB_THIS (This);
+
+  DEBUG ((DEBUG_INFO, "FvbEraseBlocks()\n"));
+
+  Status = EFI_SUCCESS;
+
+  // Before erasing, check the entire list of parameters to ensure
+  // all specified blocks are valid
+
+  VA_START (Args, This);
+  do {
+    // Get the Lba from which we start erasing
+    StartingLba = VA_ARG (Args, EFI_LBA);
+
+    // Have we reached the end of the list?
+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+      break;
+    }
+
+    // How many Lba blocks are we requested to erase?
+    NumOfLba = VA_ARG (Args, UINT32);
+
+    // All blocks must be within range
+    DEBUG ((
+      DEBUG_INFO,
+      "FvbEraseBlocks: Check if: ( StartingLba=%ld + NumOfLba=%d - 1 ) > LastBlock=%ld.\n",
+      Instance->StartLba + StartingLba,
+      NumOfLba,
+      Instance->LastBlock
+      ));
+    if ((NumOfLba == 0) ||
+        ((Instance->StartLba + StartingLba + NumOfLba - 1) >
+         Instance->LastBlock))
+    {
+      VA_END (Args);
+      DEBUG ((
+        DEBUG_ERROR,
+        "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"
+        ));
+      return EFI_INVALID_PARAMETER;
+    }
+  } while (TRUE);
+
+  VA_END (Args);
+
+  VA_START (Args, This);
+  do {
+    // Get the Lba from which we start erasing
+    StartingLba = VA_ARG (Args, EFI_LBA);
+
+    // Have we reached the end of the list?
+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+      // Exit the while loop
+      break;
+    }
+
+    // How many Lba blocks are we requested to erase?
+    NumOfLba = VA_ARG (Args, UINT32);
+
+    // Go through each one and erase it
+    while (NumOfLba > 0) {
+      // Get the physical address of Lba to erase
+      BlockAddress = GET_NOR_BLOCK_ADDRESS (
+                       Instance->RegionBaseAddress,
+                       Instance->StartLba + StartingLba,
+                       Instance->BlockSize
+                       );
+
+      // Erase it
+      DEBUG ((
+        DEBUG_INFO,
+        "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n",
+        Instance->StartLba + StartingLba,
+        BlockAddress
+        ));
+      Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
+      if (EFI_ERROR (Status)) {
+        VA_END (Args);
+        return EFI_DEVICE_ERROR;
+      }
+
+      // Move to the next Lba
+      StartingLba++;
+      NumOfLba--;
+    }
+  } while (TRUE);
+
+  VA_END (Args);
+
+  return Status;
+}
-- 
2.25.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111311): https://edk2.groups.io/g/devel/message/111311
Mute This Topic: https://groups.io/mt/102625036/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] 17+ messages in thread

* [edk2-devel] [edk2-platforms][PATCH V1 4/5] Platform/ARM/N1Sdp: Persistent storage for N1Sdp
  2023-11-16 11:45 [edk2-devel] [edk2-platforms][PATCH V1 0/5] Enable non volatile storage on N1SDP sahil
                   ` (2 preceding siblings ...)
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver " sahil
@ 2023-11-16 11:45 ` sahil
  2023-12-07 14:48   ` Thomas Abraham
  2023-12-18 15:13   ` Sami Mujawar
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 5/5] Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver " sahil
  4 siblings, 2 replies; 17+ messages in thread
From: sahil @ 2023-11-16 11:45 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Sahil

Enable persistent storage on QSPI flash device.

Signed-off-by: sahil <sahil@arm.com>
---
 Platform/ARM/N1Sdp/N1SdpPlatform.dsc | 20 ++++++++++++++------
 Platform/ARM/N1Sdp/N1SdpPlatform.fdf |  4 +++-
 2 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
index d04b22d3ef51..10fe2db9e1b1 100644
--- a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
+++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
@@ -4,7 +4,7 @@
 # This provides platform specific component descriptions and libraries that
 # conform to EFI/Framework standards.
 #
-# Copyright (c) 2018 - 2021, ARM Limited. All rights reserved.<BR>
+# Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -44,6 +44,9 @@
   # file explorer library support
   FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
 
+  # NOR flash support
+  NorFlashInfoLib|EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf
+
 [LibraryClasses.common.SEC]
   HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
   MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
@@ -161,11 +164,9 @@
   # ACPI Table Version
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions|0x20
 
-  # Runtime Variable storage
-  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved|0
-  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
-  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
-  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
+  # NOR flash support
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x18F00000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x00020000
 
 ################################################################################
 #
@@ -197,6 +198,12 @@
       gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000000F
   }
 
+  # NOR flash support
+  Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf {
+      <LibraryClasses>
+      NorFlashPlatformLib|Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
+  }
+
   # Architectural Protocols
   ArmPkg/Drivers/CpuDxe/CpuDxe.inf
   ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
@@ -217,6 +224,7 @@
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
     <LibraryClasses>
       NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
+      NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf
       BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
   }
 
diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
index e5e24ea50294..4329f892f7c5 100644
--- a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
+++ b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
@@ -1,7 +1,7 @@
 ## @file
 #  FDF file of N1Sdp
 #
-#  Copyright (c) 2018 - 2021, ARM Limited. All rights reserved.<BR>
+#  Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 ##
@@ -140,6 +140,8 @@ READ_LOCK_STATUS   = TRUE
   INF ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf
   INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
 
+  INF Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
+
   INF Platform/ARM/Drivers/BootMonFs/BootMonFs.inf
   INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
 
-- 
2.25.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111312): https://edk2.groups.io/g/devel/message/111312
Mute This Topic: https://groups.io/mt/102625037/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] 17+ messages in thread

* [edk2-devel] [edk2-platforms][PATCH V1 5/5] Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver for N1Sdp
  2023-11-16 11:45 [edk2-devel] [edk2-platforms][PATCH V1 0/5] Enable non volatile storage on N1SDP sahil
                   ` (3 preceding siblings ...)
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 4/5] Platform/ARM/N1Sdp: Persistent storage " sahil
@ 2023-11-16 11:45 ` sahil
  2023-12-07 14:51   ` Thomas Abraham
  2023-12-18 15:16   ` Sami Mujawar
  4 siblings, 2 replies; 17+ messages in thread
From: sahil @ 2023-11-16 11:45 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Sahil

Signed-off-by: sahil <sahil@arm.com>
---
 Platform/ARM/N1Sdp/N1SdpPlatform.dsc | 5 +++++
 Platform/ARM/N1Sdp/N1SdpPlatform.fdf | 1 +
 2 files changed, 6 insertions(+)

diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
index 10fe2db9e1b1..703829bbac99 100644
--- a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
+++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
@@ -165,6 +165,10 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions|0x20
 
   # NOR flash support
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0x18F40000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x00020000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0x18F20000
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x00020000
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x18F00000
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x00020000
 
@@ -227,6 +231,7 @@
       NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf
       BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
   }
+  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
 
   # ACPI Support
   MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
index 4329f892f7c5..17d370a371cf 100644
--- a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
+++ b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
@@ -90,6 +90,7 @@ READ_LOCK_STATUS   = TRUE
   INF MdeModulePkg/Universal/Metronome/Metronome.inf
   INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
   INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
+  INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
   INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
   INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
   INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
-- 
2.25.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#111313): https://edk2.groups.io/g/devel/message/111313
Mute This Topic: https://groups.io/mt/102625038/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] 17+ messages in thread

* Re: [edk2-devel] [edk2-platforms][PATCH V1 1/5] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 1/5] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region sahil
@ 2023-12-07 10:59   ` Thomas Abraham
  2023-12-18 15:12   ` Sami Mujawar
  1 sibling, 0 replies; 17+ messages in thread
From: Thomas Abraham @ 2023-12-07 10:59 UTC (permalink / raw)
  To: devel@edk2.groups.io, Sahil Kaushal
  Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Chandni Cherukuri


> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of sahil via
> groups.io
> Sent: Thursday, November 16, 2023 11:46 AM
> To: devel@edk2.groups.io
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Leif Lindholm
> <quic_llindhol@quicinc.com>; Sami Mujawar <Sami.Mujawar@arm.com>;
> Sahil Kaushal <Sahil.Kaushal@arm.com>
> Subject: [edk2-devel] [edk2-platforms][PATCH V1 1/5]
> Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region
>
> Enable SCP QSPI flash region access by adding it in the PlatformLibMem
>
> Signed-off-by: sahil <sahil@arm.com>
> ---
>  Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h              |  6 +++++-
>  Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c | 10
> ++++++++--
>  2 files changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
> b/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
> index 097160c7e2d1..92b8c9c45775 100644
> --- a/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
> +++ b/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
> @@ -1,6 +1,6 @@
>  /** @file
>
>  *
>
> -* Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
>
> +* Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.
>
>  *
>
>  * SPDX-License-Identifier: BSD-2-Clause-Patent
>
>  *
>
> @@ -41,6 +41,10 @@
>  #define NEOVERSEN1SOC_EXP_PERIPH_BASE0               0x1C000000
>
>  #define NEOVERSEN1SOC_EXP_PERIPH_BASE0_SZ            0x1300000
>
>
>
> +// SCP QSPI flash device
>
> +#define NEOVERSEN1SOC_SCP_QSPI_AHB_BASE              0x18000000
>
> +#define NEOVERSEN1SOC_SCP_QSPI_AHB_SZ                0x2000000
>
> +
>
>  // Base address to a structure of type NEOVERSEN1SOC_PLAT_INFO which is
>
>  // pre-populated by a earlier boot stage
>
>  #define NEOVERSEN1SOC_PLAT_INFO_STRUCT_BASE
> (NEOVERSEN1SOC_NON_SECURE_SRAM_BASE + \
>
> diff --git a/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
> b/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
> index 9e8a1efc557d..eb099953fe29 100644
> --- a/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
> +++ b/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
> @@ -1,6 +1,6 @@
>  /** @file
>
>
>
> -  Copyright (c) 2018 - 2021, ARM Limited. All rights reserved.<BR>
>
> +  Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.<BR>
>
>
>
>    SPDX-License-Identifier: BSD-2-Clause-Patent
>
>
>
> @@ -13,7 +13,7 @@
>  #include <NeoverseN1Soc.h>
>
>
>
>  // The total number of descriptors, including the final "end-of-table" descriptor.
>
> -#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 19
>
> +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 20
>
>
>
>  /**
>
>    Returns the Virtual Memory Map of the platform.
>
> @@ -184,6 +184,12 @@ ArmPlatformGetVirtualMemoryMap (
>    VirtualMemoryTable[Index].Length          =
> NEOVERSEN1SOC_EXP_PERIPH_BASE0_SZ;
>
>    VirtualMemoryTable[Index].Attributes      =
> ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
>
>
>
> +  // SCP QSPI flash device
>
> +  VirtualMemoryTable[++Index].PhysicalBase  =
> NEOVERSEN1SOC_SCP_QSPI_AHB_BASE;
>
> +  VirtualMemoryTable[Index].VirtualBase     =
> NEOVERSEN1SOC_SCP_QSPI_AHB_BASE;
>
> +  VirtualMemoryTable[Index].Length          =
> NEOVERSEN1SOC_SCP_QSPI_AHB_SZ;
>
> +  VirtualMemoryTable[Index].Attributes      =
> ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
>
> +
>
>    if (PlatInfo->MultichipMode == 1) {
>
>      //Remote DDR (2GB)
>
>      VirtualMemoryTable[++Index].PhysicalBase  = PcdGet64
> (PcdExtMemorySpace) +
>

Reviewed-by: Thomas Abraham <thomas.abraham@arm.com>
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.


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



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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 2/5] Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 2/5] Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp sahil
@ 2023-12-07 12:01   ` Thomas Abraham
  2023-12-18 15:12   ` Sami Mujawar
  1 sibling, 0 replies; 17+ messages in thread
From: Thomas Abraham @ 2023-12-07 12:01 UTC (permalink / raw)
  To: devel@edk2.groups.io, Sahil Kaushal
  Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Chandni Cherukuri,
	nd

Hi Sahil,

> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of sahil via
> groups.io
> Sent: Thursday, November 16, 2023 11:46 AM
> To: devel@edk2.groups.io
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Leif Lindholm
> <quic_llindhol@quicinc.com>; Sami Mujawar <Sami.Mujawar@arm.com>;
> Sahil Kaushal <Sahil.Kaushal@arm.com>
> Subject: [edk2-devel] [edk2-platforms][PATCH V1 2/5]
> Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp
> 
> Add NOR flash library, this library provides APIs for getting the list
> of NOR flash devices on the platform.
> 
> Signed-off-by: sahil <sahil@arm.com>
> ---
>  Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf | 36
> ++++++++++++++
>  Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c   | 52
> ++++++++++++++++++++
>  2 files changed, 88 insertions(+)
> 
> diff --git a/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
> b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
> new file mode 100644
> index 000000000000..14f81125c4e1
> --- /dev/null
> +++ b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
> @@ -0,0 +1,36 @@
> +## @file
> 
> +#  NOR flash lib for ARM Neoverse N1 platform.
> 
> +#
> 
> +#  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
> 
> +#
> 
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +[Defines]
> 
> +  INF_VERSION                    = 0x0001001B
> 
> +  BASE_NAME                      = NorFlashNeoverseN1SocLib
> 
> +  FILE_GUID                      = 7006fcf1-a585-4272-92e3-b286b1dff5bb
> 
> +  MODULE_TYPE                    = DXE_DRIVER
> 
> +  VERSION_STRING                 = 1.0
> 
> +  LIBRARY_CLASS                  = NorFlashPlatformLib
> 
> +
> 
> +[Sources.common]
> 
> +  NorFlashLib.c
> 
> +
> 
> +[Packages]
> 
> +  MdeModulePkg/MdeModulePkg.dec
> 
> +  MdePkg/MdePkg.dec
> 
> +  Platform/ARM/ARM.dec
> 
> +  Silicon/ARM/NeoverseN1Soc/NeoverseN1Soc.dec
> 
> +
> 
> +[LibraryClasses]
> 
> +  BaseLib
> 
> +  DebugLib
> 
> +  IoLib
> 
> +
> 
> +[FixedPcd]
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
> 
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> 
> diff --git a/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c
> b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c
> new file mode 100644
> index 000000000000..a508d7d77373
> --- /dev/null
> +++ b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c
> @@ -0,0 +1,52 @@
> +/** @file
> 
> +*  NOR flash lib for ARM Neoverse N1 platform
> 
> +*
> 
> +*  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
> 
> +*
> 
> +*  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +*
> 
> +**/
> 
> +
> 
> +#include <Library/DebugLib.h>
> 
> +#include <Library/IoLib.h>
> 
> +#include <Library/NorFlashPlatformLib.h>
> 
> +#include <NeoverseN1Soc.h>
> 
> +#include <PiDxe.h>
> 
> +
> 
> +#define FW_ENV_REGION_BASE  FixedPcdGet32
> (PcdFlashNvStorageVariableBase)
> 
> +#define FW_ENV_REGION_SIZE  (FixedPcdGet32
> (PcdFlashNvStorageVariableSize) +           \
> 
> +                                      FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + \
> 
> +                                      FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize))

Why is FtwWorkingSize and FtwSpareSize included in the calculation of the size? Are these not offsets inside a flash region?

> 
> +
> 
> +STATIC NOR_FLASH_DESCRIPTION  mNorFlashDevices[] = {
> 
> +  {
> 
> +    /// Environment variable region
> 
> +    NEOVERSEN1SOC_SCP_QSPI_AHB_BASE,                    ///< device base
> 
> +    FW_ENV_REGION_BASE,                                 ///< region base
> 
> +    FW_ENV_REGION_SIZE,                                 ///< region size
> 
> +    SIZE_4KB,                                           ///< block size
> 
> +  },
> 
> +};
> 
> +
> 
> +/**
> 
> +  Get NOR flash region info
> 
> +
> 
> +  @param[out]    NorFlashDevices    NOR flash regions info.
> 
> +  @param[out]    Count              number of flash instance.
> 
> +
> 
> +  @retval        EFI_SUCCESS        Success.
> 
> +**/
> 
> +EFI_STATUS
> 
> +NorFlashPlatformGetDevices (
> 
> +  OUT NOR_FLASH_DESCRIPTION  **NorFlashDevices,
> 
> +  OUT UINT32                 *Count
> 
> +  )
> 
> +{
> 
> +  if ((NorFlashDevices == NULL) || (Count == NULL)) {
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +
> 
> +  *NorFlashDevices = mNorFlashDevices;
> 
> +  *Count           = ARRAY_SIZE (mNorFlashDevices);
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> --
> 2.25.1



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



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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver for N1Sdp
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver " sahil
@ 2023-12-07 14:46   ` Thomas Abraham
  2023-12-12 12:08   ` levi.yun
  2023-12-18 15:12   ` Sami Mujawar
  2 siblings, 0 replies; 17+ messages in thread
From: Thomas Abraham @ 2023-12-07 14:46 UTC (permalink / raw)
  To: devel@edk2.groups.io, Sahil Kaushal
  Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Chandni Cherukuri,
	nd


> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of sahil via
> groups.io
> Sent: Thursday, November 16, 2023 11:46 AM
> To: devel@edk2.groups.io
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Leif Lindholm
> <quic_llindhol@quicinc.com>; Sami Mujawar <Sami.Mujawar@arm.com>;
> Sahil Kaushal <Sahil.Kaushal@arm.com>
> Subject: [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp:
> NOR flash Dxe Driver for N1Sdp
> 
> Add NOR flash DXE driver, this brings up NV storage on
> QSPI's flash device using FVB protocol.
> 
> Signed-off-by: sahil <sahil@arm.com>
> ---
>  Platform/ARM/N1Sdp/N1SdpPlatform.dec                         |    5 +-
>  Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf |   72 ++
>  Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h   |   33 +
>  Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h         |  491
> +++++++++
>  Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c   |  409
> ++++++++
>  Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c         | 1100
> ++++++++++++++++++++
>  Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c      |  647
> ++++++++++++
>  7 files changed, 2756 insertions(+), 1 deletion(-)


Can this driver be moved to either the edk2-platform drivers/ or the Platform/Arm/Drivers directory?

Otherwise, looks okay.
Reviewed-by: Thomas Abraham <thomas.abraham@arm.com>

[snip]


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



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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 4/5] Platform/ARM/N1Sdp: Persistent storage for N1Sdp
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 4/5] Platform/ARM/N1Sdp: Persistent storage " sahil
@ 2023-12-07 14:48   ` Thomas Abraham
  2023-12-18 15:13   ` Sami Mujawar
  1 sibling, 0 replies; 17+ messages in thread
From: Thomas Abraham @ 2023-12-07 14:48 UTC (permalink / raw)
  To: devel@edk2.groups.io, Sahil Kaushal
  Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Chandni Cherukuri,
	nd


> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of sahil via
> groups.io
> Sent: Thursday, November 16, 2023 11:46 AM
> To: devel@edk2.groups.io
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Leif Lindholm
> <quic_llindhol@quicinc.com>; Sami Mujawar <Sami.Mujawar@arm.com>;
> Sahil Kaushal <Sahil.Kaushal@arm.com>
> Subject: [edk2-devel] [edk2-platforms][PATCH V1 4/5] Platform/ARM/N1Sdp:
> Persistent storage for N1Sdp
> 
> Enable persistent storage on QSPI flash device.
> 
> Signed-off-by: sahil <sahil@arm.com>
> ---
>  Platform/ARM/N1Sdp/N1SdpPlatform.dsc | 20 ++++++++++++++------
>  Platform/ARM/N1Sdp/N1SdpPlatform.fdf |  4 +++-
>  2 files changed, 17 insertions(+), 7 deletions(-)
> 
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> index d04b22d3ef51..10fe2db9e1b1 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> @@ -4,7 +4,7 @@
>  # This provides platform specific component descriptions and libraries that
> 
>  # conform to EFI/Framework standards.
> 
>  #
> 
> -# Copyright (c) 2018 - 2021, ARM Limited. All rights reserved.<BR>
> 
> +# Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.<BR>
> 
>  #
> 
>  # SPDX-License-Identifier: BSD-2-Clause-Patent
> 
>  #
> 
> @@ -44,6 +44,9 @@
>    # file explorer library support
> 
>    FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
> 
> 
> 
> +  # NOR flash support
> 
> +  NorFlashInfoLib|EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf
> 
> +
> 
>  [LibraryClasses.common.SEC]
> 
>    HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
> 
> 
> MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAll
> ocationLib.inf
> 
> @@ -161,11 +164,9 @@
>    # ACPI Table Version
> 
>    gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions|0x20
> 
> 
> 
> -  # Runtime Variable storage
> 
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved|0
> 
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
> 
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
> 
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
> 
> +  # NOR flash support
> 
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x18F0000
> 0
> 
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x0002000
> 0
> 
> 
> 
> 
> ################################################################
> ################
> 
>  #
> 
> @@ -197,6 +198,12 @@
>        gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000000F
> 
>    }
> 
> 
> 
> +  # NOR flash support
> 
> +  Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf {
> 
> +      <LibraryClasses>
> 
> +
> NorFlashPlatformLib|Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlas
> hLib.inf
> 
> +  }
> 
> +
> 
>    # Architectural Protocols
> 
>    ArmPkg/Drivers/CpuDxe/CpuDxe.inf
> 
>    ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
> 
> @@ -217,6 +224,7 @@
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
> 
>      <LibraryClasses>
> 
>        NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
> 
> +
> NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.
> inf
> 
>        BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> 
>    }
> 
> 
> 
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> index e5e24ea50294..4329f892f7c5 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> @@ -1,7 +1,7 @@
>  ## @file
> 
>  #  FDF file of N1Sdp
> 
>  #
> 
> -#  Copyright (c) 2018 - 2021, ARM Limited. All rights reserved.<BR>
> 
> +#  Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.<BR>
> 
>  #
> 
>  #  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
>  ##
> 
> @@ -140,6 +140,8 @@ READ_LOCK_STATUS   = TRUE
>    INF ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf
> 
>    INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
> 
> 
> 
> +  INF Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
> 
> +
> 
>    INF Platform/ARM/Drivers/BootMonFs/BootMonFs.inf
> 
>    INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
> 
> 
> 
> --
> 2.25.1

Reviewed-by: Thomas Abraham <thomas.abraham@arm.com>


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



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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 5/5] Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver for N1Sdp
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 5/5] Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver " sahil
@ 2023-12-07 14:51   ` Thomas Abraham
  2023-12-18 15:16   ` Sami Mujawar
  1 sibling, 0 replies; 17+ messages in thread
From: Thomas Abraham @ 2023-12-07 14:51 UTC (permalink / raw)
  To: devel@edk2.groups.io, Sahil Kaushal
  Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar, Chandni Cherukuri,
	nd


> -----Original Message-----
> From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of sahil via
> groups.io
> Sent: Thursday, November 16, 2023 11:46 AM
> To: devel@edk2.groups.io
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>; Leif Lindholm
> <quic_llindhol@quicinc.com>; Sami Mujawar <Sami.Mujawar@arm.com>;
> Sahil Kaushal <Sahil.Kaushal@arm.com>
> Subject: [edk2-devel] [edk2-platforms][PATCH V1 5/5] Platform/ARM/N1Sdp:
> Enable FaultTolerantWrite Dxe driver for N1Sdp

Add a commit message.

> 
> Signed-off-by: sahil <sahil@arm.com>
> ---
>  Platform/ARM/N1Sdp/N1SdpPlatform.dsc | 5 +++++
>  Platform/ARM/N1Sdp/N1SdpPlatform.fdf | 1 +
>  2 files changed, 6 insertions(+)
> 
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> index 10fe2db9e1b1..703829bbac99 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> @@ -165,6 +165,10 @@
>    gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions|0x20
> 
> 
> 
>    # NOR flash support
> 
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0x18F400
> 00
> 
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x0002000
> 0
> 
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0x18F2
> 0000
> 
> +
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x0002
> 0000
> 
> 
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x18F0000
> 0
> 
> 
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x0002000
> 0
> 
> 
> 
> @@ -227,6 +231,7 @@
> 
> NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.
> inf
> 
>        BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> 
>    }
> 
> +  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
> 
> 
> 
>    # ACPI Support
> 
>    MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
> 
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> index 4329f892f7c5..17d370a371cf 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> @@ -90,6 +90,7 @@ READ_LOCK_STATUS   = TRUE
>    INF MdeModulePkg/Universal/Metronome/Metronome.inf
> 
>    INF
> MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.in
> f
> 
>    INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
> 
> +  INF
> MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
> 
>    INF
> MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterR
> untimeDxe.inf
> 
>    INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
> 
>    INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> 
> --
> 2.25.1

With the commit message included,
Reviewed-by: Thomas Abraham <thomas.abraham@arm.com>


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



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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver for N1Sdp
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver " sahil
  2023-12-07 14:46   ` Thomas Abraham
@ 2023-12-12 12:08   ` levi.yun
  2023-12-18 15:12   ` Sami Mujawar
  2 siblings, 0 replies; 17+ messages in thread
From: levi.yun @ 2023-12-12 12:08 UTC (permalink / raw)
  To: devel, sahil; +Cc: Ard Biesheuvel, Leif Lindholm, Sami Mujawar

Hi Sahil!



On 16/11/2023 11:45, sahil via groups.io wrote:
> Add NOR flash DXE driver, this brings up NV storage on
> QSPI's flash device using FVB protocol.
>
> Signed-off-by: sahil <sahil@arm.com>
> ---
>   Platform/ARM/N1Sdp/N1SdpPlatform.dec                         |    5 +-
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf |   72 ++
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h   |   33 +
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h         |  491 +++++++++
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c   |  409 ++++++++
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c         | 1100 ++++++++++++++++++++
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c      |  647 ++++++++++++
>   7 files changed, 2756 insertions(+), 1 deletion(-)
>
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dec b/Platform/ARM/N1Sdp/N1SdpPlatform.dec
> index 16937197b8e8..67b5f4c871b6 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.dec
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dec
> @@ -1,7 +1,7 @@
>   ## @file
>   #  Describes the N1Sdp configuration.
>   #
> -#  Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
> +#  Copyright (c) 2021-2023, ARM Limited. All rights reserved.<BR>
>   #
>   #  SPDX-License-Identifier: BSD-2-Clause-Patent
>   ##
> @@ -89,3 +89,6 @@
>     # unmapped reserved region results in a DECERR response.
>     #
>     gArmN1SdpTokenSpaceGuid.PcdCsComponentSize|0x1000|UINT32|0x00000049
> +
> +  # Base address of Cadence QSPI controller configuration registers
> +  gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress|0x1C0C0000|UINT32|0x0000004A
> diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
> new file mode 100644
> index 000000000000..62a4944c95db
> --- /dev/null
> +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
> @@ -0,0 +1,72 @@
> +## @file
> +#  NOR flash DXE
> +#
> +#  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = CadenceQspiDxe
> +  FILE_GUID                      = CC8A9713-4442-4A6C-B389-8B46490A0641
> +  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
> +  VERSION_STRING                 = 0.1
> +  ENTRY_POINT                    = NorFlashInitialise
> +
> +[Sources]
> +  CadenceQspiDxe.c
> +  CadenceQspiReg.h
> +  NorFlash.c
> +  NorFlash.h
> +  NorFlashFvb.c
> +
> +[Packages]
> +  EmbeddedPkg/EmbeddedPkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
> +  Platform/ARM/ARM.dec
> +  Platform/ARM/N1Sdp/N1SdpPlatform.dec
> +
> +[LibraryClasses]
> +  BaseLib
> +  BaseMemoryLib
> +  DebugLib
> +  DevicePathLib
> +  DxeServicesTableLib
> +  HobLib
> +  IoLib
> +  MemoryAllocationLib
> +  NorFlashInfoLib
> +  NorFlashPlatformLib
> +  TimerLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiLib
> +  UefiRuntimeLib
> +  UefiRuntimeServicesTableLib
> +
> +[Guids]
> +  gEdkiiNvVarStoreFormattedGuid
> +  gEfiAuthenticatedVariableGuid
> +  gEfiEventVirtualAddressChangeGuid
> +  gEfiSystemNvDataFvGuid
> +  gEfiVariableGuid
> +  gEfiGlobalVariableGuid
> +
> +[Protocols]
> +  gEfiDevicePathProtocolGuid
> +  gEfiFirmwareVolumeBlockProtocolGuid
> +
> +[FixedPcd]
> +  gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> +
> +[Depex]
> +  gEfiCpuArchProtocolGuid
> diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
> new file mode 100644
> index 000000000000..535e6d738d31
> --- /dev/null
> +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
> @@ -0,0 +1,33 @@
> +/** @file
> +
> +  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef CADENCE_QSPI_REG_H_
> +#define CADENCE_QSPI_REG_H_
If you don't mind, would you add some of Reference page to understand
NorFlash in CadenceQspi please with @par?
> +/**
> +  Write a full block to given location.
> +
> +  @param[in]    Instance           NOR flash Instance of variable store region.
> +  @param[in]    Lba                The logical block address in NOR flash.
> +  @param[in]    DataBuffer         The data to write into NOR flash location.
> +  @param[in]    BlockSizeInWords   The number of bytes to write.
> +
> +  @retval       EFI_SUCCESS        The write is completed.
> +**/
> +STATIC
> +EFI_STATUS
> +NorFlashWriteFullBlock (
> +  IN NOR_FLASH_INSTANCE  *Instance,
> +  IN EFI_LBA             Lba,
> +  IN UINT32              *DataBuffer,
> +  IN UINT32              BlockSizeInWords
> +  )
> +{
> +  EFI_STATUS              Status;
> +  UINTN                   WordAddress;
> +  UINT32                  WordIndex;
> +  UINTN                   BlockAddress;
> +  NOR_FLASH_LOCK_CONTEXT  Lock;
> +
> +  Status = EFI_SUCCESS;
> +
> +  // Get the physical address of the block
> +  BlockAddress = GET_NOR_BLOCK_ADDRESS (
> +                   Instance->RegionBaseAddress,
> +                   Lba,
> +                   BlockSizeInWords * 4
> +                   );
> +
> +  // Start writing from the first address at the start of the block
> +  WordAddress = BlockAddress;
> +
> +  NorFlashLock (&Lock);
> +
> +  Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((
> +      DEBUG_ERROR,
> +      "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n",
> +      BlockAddress
> +      ));
> +    goto EXIT;
> +  }
> +
> +  for (WordIndex = 0;
> +       WordIndex < BlockSizeInWords;
> +       WordIndex++, DataBuffer++, WordAddress += 4)
> +  {
> +    Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
> +    if (EFI_ERROR (Status)) {
> +      goto EXIT;
> +    }
> +  }
> +
> +EXIT:
> +  NorFlashUnlock (&Lock);
> +
IIUC,  NorFlashUnlockAndEraseSingleBlock calls NorFlashLock and
NorFLashUnlock too.
After calling NorFlashUnlock, it seems TPL or Interrupt seems to be
enabled again.
Isn't it problem?

Thanks.

--------
Sincerely,
Levi.




IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.


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



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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 1/5] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 1/5] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region sahil
  2023-12-07 10:59   ` Thomas Abraham
@ 2023-12-18 15:12   ` Sami Mujawar
  1 sibling, 0 replies; 17+ messages in thread
From: Sami Mujawar @ 2023-12-18 15:12 UTC (permalink / raw)
  To: devel, sahil; +Cc: Ard Biesheuvel, Leif Lindholm, nd@arm.com

Hi Sahil,

Please see my response inline marked [SAMI].

Regards,

Sami Mujawar

On 16/11/2023 11:45 am, sahil via groups.io wrote:
> Enable SCP QSPI flash region access by adding it in the PlatformLibMem
>
> Signed-off-by: sahil <sahil@arm.com>
> ---
>   Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h              |  6 +++++-
>   Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c | 10 ++++++++--
>   2 files changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h b/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
> index 097160c7e2d1..92b8c9c45775 100644
> --- a/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
> +++ b/Silicon/ARM/NeoverseN1Soc/Include/NeoverseN1Soc.h
> @@ -1,6 +1,6 @@
>   /** @file
>
>   *
>
> -* Copyright (c) 2018 - 2020, ARM Limited. All rights reserved.
>
> +* Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.
>
>   *
>
>   * SPDX-License-Identifier: BSD-2-Clause-Patent
>
>   *
>
> @@ -41,6 +41,10 @@
>   #define NEOVERSEN1SOC_EXP_PERIPH_BASE0               0x1C000000
>
>   #define NEOVERSEN1SOC_EXP_PERIPH_BASE0_SZ            0x1300000
>
>   
>
> +// SCP QSPI flash device
>
> +#define NEOVERSEN1SOC_SCP_QSPI_AHB_BASE              0x18000000
>
> +#define NEOVERSEN1SOC_SCP_QSPI_AHB_SZ                0x2000000

[SAMI] Can you elaborate what is meant by 'SCP', please? Does this mean 
the flash is shared by SCP and AP? It would be good to clarify that in 
the commit message.

Also, if you can add a reference to the relevant document in the file 
header it would be of great help.

[/SAMI]

>
> +
>
>   // Base address to a structure of type NEOVERSEN1SOC_PLAT_INFO which is
>
>   // pre-populated by a earlier boot stage
>
>   #define NEOVERSEN1SOC_PLAT_INFO_STRUCT_BASE          (NEOVERSEN1SOC_NON_SECURE_SRAM_BASE + \
>
> diff --git a/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c b/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
> index 9e8a1efc557d..eb099953fe29 100644
> --- a/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
> +++ b/Silicon/ARM/NeoverseN1Soc/Library/PlatformLib/PlatformLibMem.c
> @@ -1,6 +1,6 @@
>   /** @file
>
>   
>
> -  Copyright (c) 2018 - 2021, ARM Limited. All rights reserved.<BR>
>
> +  Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.<BR>
>
>   
>
>     SPDX-License-Identifier: BSD-2-Clause-Patent
>
>   
>
> @@ -13,7 +13,7 @@
>   #include <NeoverseN1Soc.h>
>
>   
>
>   // The total number of descriptors, including the final "end-of-table" descriptor.
>
> -#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 19
>
> +#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 20
>
>   
>
>   /**
>
>     Returns the Virtual Memory Map of the platform.
>
> @@ -184,6 +184,12 @@ ArmPlatformGetVirtualMemoryMap (
>     VirtualMemoryTable[Index].Length          = NEOVERSEN1SOC_EXP_PERIPH_BASE0_SZ;
>
>     VirtualMemoryTable[Index].Attributes      = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
>
>   
>
> +  // SCP QSPI flash device
>
> +  VirtualMemoryTable[++Index].PhysicalBase  = NEOVERSEN1SOC_SCP_QSPI_AHB_BASE;
>
> +  VirtualMemoryTable[Index].VirtualBase     = NEOVERSEN1SOC_SCP_QSPI_AHB_BASE;
>
> +  VirtualMemoryTable[Index].Length          = NEOVERSEN1SOC_SCP_QSPI_AHB_SZ;
>
> +  VirtualMemoryTable[Index].Attributes      = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
>
> +
>
>     if (PlatInfo->MultichipMode == 1) {
>
>       //Remote DDR (2GB)
>
>       VirtualMemoryTable[++Index].PhysicalBase  = PcdGet64 (PcdExtMemorySpace) +
>


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



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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 2/5] Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 2/5] Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp sahil
  2023-12-07 12:01   ` Thomas Abraham
@ 2023-12-18 15:12   ` Sami Mujawar
  1 sibling, 0 replies; 17+ messages in thread
From: Sami Mujawar @ 2023-12-18 15:12 UTC (permalink / raw)
  To: sahil, devel; +Cc: Ard Biesheuvel, Leif Lindholm, nd@arm.com

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

Hi Sahil,

Please find my feedback marked inline as [SAMI].

With those fixed,

Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>

Regards,

Sami Mujawar

On 16/11/2023 11:45 am, sahil wrote:
> Add NOR flash library, this library provides APIs for getting the list
> of NOR flash devices on the platform.
>
> Signed-off-by: sahil<sahil@arm.com>
> ---
>   Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf | 36 ++++++++++++++
>   Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c   | 52 ++++++++++++++++++++
>   2 files changed, 88 insertions(+)
>
> diff --git a/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
> new file mode 100644
> index 000000000000..14f81125c4e1
> --- /dev/null
> +++ b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
> @@ -0,0 +1,36 @@
> +## @file
>
> +#  NOR flash lib for ARM Neoverse N1 platform.
>
> +#
>
> +#  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
>
> +#
>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +#
>
> +##
>
> +
>
> +[Defines]
>
> +  INF_VERSION                    = 0x0001001B
>
> +  BASE_NAME                      = NorFlashNeoverseN1SocLib
>
> +  FILE_GUID                      = 7006fcf1-a585-4272-92e3-b286b1dff5bb
>
> +  MODULE_TYPE                    = DXE_DRIVER
>
> +  VERSION_STRING                 = 1.0
>
> +  LIBRARY_CLASS                  = NorFlashPlatformLib

[SAMI] Since this library class is NorFlashPlatformLib, you need to 
implement NorFlashPlatformInitialization().

A platform may not need to do anything in 
NorFlashPlatformInitialization() and just return success.

[/SAMI]

>
> +
>
> +[Sources.common]
>
> +  NorFlashLib.c
>
> +
>
> +[Packages]
>
> +  MdeModulePkg/MdeModulePkg.dec
>
> +  MdePkg/MdePkg.dec
>
> +  Platform/ARM/ARM.dec
>
> +  Silicon/ARM/NeoverseN1Soc/NeoverseN1Soc.dec
>
> +
>
> +[LibraryClasses]
>
> +  BaseLib
>
> +  DebugLib
>
> +  IoLib
>
> +
>
> +[FixedPcd]
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>
> diff --git a/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c
> new file mode 100644
> index 000000000000..a508d7d77373
> --- /dev/null
> +++ b/Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.c
> @@ -0,0 +1,52 @@
> +/** @file
>
> +*  NOR flash lib for ARM Neoverse N1 platform
>
> +*
>
> +*  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
>
> +*
>
> +*  SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +*
>
> +**/
>
> +
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/NorFlashPlatformLib.h>
>
> +#include <NeoverseN1Soc.h>
>
> +#include <PiDxe.h>
>
> +
>
> +#define FW_ENV_REGION_BASE  FixedPcdGet32 (PcdFlashNvStorageVariableBase)
>
> +#define FW_ENV_REGION_SIZE  (FixedPcdGet32 (PcdFlashNvStorageVariableSize) +           \
>
> +                                      FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + \
>
> +                                      FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize))
[SAMI] Please limit line length to 80 characters. Also run uncrustify.
>
> +
>
> +STATIC NOR_FLASH_DESCRIPTION  mNorFlashDevices[] = {
>
> +  {
>
> +    /// Environment variable region
>
> +    NEOVERSEN1SOC_SCP_QSPI_AHB_BASE,                    ///< device base
>
> +    FW_ENV_REGION_BASE,                                 ///< region base
>
> +    FW_ENV_REGION_SIZE,                                 ///< region size
>
> +    SIZE_4KB,                                           ///< block size
>
> +  },
>
> +};
>
> +
>
> +/**
>
> +  Get NOR flash region info
>
> +
>
> +  @param[out]    NorFlashDevices    NOR flash regions info.
>
> +  @param[out]    Count              number of flash instance.
>
> +
>
> +  @retval        EFI_SUCCESS        Success.
[SAMI] EFI_INVALID_PARAMETER ?
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashPlatformGetDevices (
>
> +  OUT NOR_FLASH_DESCRIPTION  **NorFlashDevices,
>
> +  OUT UINT32                 *Count
>
> +  )
>
> +{
>
> +  if ((NorFlashDevices == NULL) || (Count == NULL)) {
>
> +    return EFI_INVALID_PARAMETER;
>
> +  }
>
> +
>
> +  *NorFlashDevices = mNorFlashDevices;
>
> +  *Count           = ARRAY_SIZE (mNorFlashDevices);
>
> +  return EFI_SUCCESS;
>
> +}
>


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



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

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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver for N1Sdp
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver " sahil
  2023-12-07 14:46   ` Thomas Abraham
  2023-12-12 12:08   ` levi.yun
@ 2023-12-18 15:12   ` Sami Mujawar
  2 siblings, 0 replies; 17+ messages in thread
From: Sami Mujawar @ 2023-12-18 15:12 UTC (permalink / raw)
  To: sahil, devel; +Cc: Ard Biesheuvel, Leif Lindholm, nd@arm.com

Hi Sahil,

Where can I find the documentation for Cadence QSPI? Can you add a link 
to the relevant file headers, please?

Also, this patch is duplicating a lot of the code in 
edk2-platforms\Platform\ARM\Drivers\NorFlashDxe and I have already 
spotted some new bugs in this patch.

Have you considered splitting the NorFlashDxe to introduce a 
NorFlashDeviceLib that implements the specifics for the respective flash?

i.e. NorFlashDxe links with NorFlashDeviceLib and the platforms can 
specify the respective NorFlashDeviceLib instances.

NorFlashDeviceLib|Platform/Arm/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.inf

NorFlashDeviceLib|Platform/Arm/Library/CadenceQspiNorFlashDeviceLib/CadenceQspiNorFlashDeviceLib.inf

Regards,

Sami Mujawar

On 16/11/2023 11:45 am, sahil wrote:
> Add NOR flash DXE driver, this brings up NV storage on
> QSPI's flash device using FVB protocol.
>
> Signed-off-by: sahil <sahil@arm.com>
> ---
>   Platform/ARM/N1Sdp/N1SdpPlatform.dec                         |    5 +-
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf |   72 ++
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h   |   33 +
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h         |  491 +++++++++
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c   |  409 ++++++++
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c         | 1100 ++++++++++++++++++++
>   Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c      |  647 ++++++++++++
>   7 files changed, 2756 insertions(+), 1 deletion(-)
>
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dec b/Platform/ARM/N1Sdp/N1SdpPlatform.dec
> index 16937197b8e8..67b5f4c871b6 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.dec
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dec
> @@ -1,7 +1,7 @@
>   ## @file
>
>   #  Describes the N1Sdp configuration.
>
>   #
>
> -#  Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
>
> +#  Copyright (c) 2021-2023, ARM Limited. All rights reserved.<BR>
>
>   #
>
>   #  SPDX-License-Identifier: BSD-2-Clause-Patent
>
>   ##
>
> @@ -89,3 +89,6 @@
>     # unmapped reserved region results in a DECERR response.
>
>     #
>
>     gArmN1SdpTokenSpaceGuid.PcdCsComponentSize|0x1000|UINT32|0x00000049
>
> +
>
> +  # Base address of Cadence QSPI controller configuration registers
>
> +  gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress|0x1C0C0000|UINT32|0x0000004A
>
> diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
> new file mode 100644
> index 000000000000..62a4944c95db
> --- /dev/null
> +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
> @@ -0,0 +1,72 @@
> +## @file
>
> +#  NOR flash DXE
>
> +#
>
> +#  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
>
> +#
>
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +#
>
> +##
>
> +
>
> +[Defines]
>
> +  INF_VERSION                    = 0x0001001B
>
> +  BASE_NAME                      = CadenceQspiDxe
>
> +  FILE_GUID                      = CC8A9713-4442-4A6C-B389-8B46490A0641
>
> +  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
>
> +  VERSION_STRING                 = 0.1
>
> +  ENTRY_POINT                    = NorFlashInitialise
>
> +
>
> +[Sources]
>
> +  CadenceQspiDxe.c
>
> +  CadenceQspiReg.h
>
> +  NorFlash.c
>
> +  NorFlash.h
>
> +  NorFlashFvb.c
>
> +
>
> +[Packages]
>
> +  EmbeddedPkg/EmbeddedPkg.dec
>
> +  MdeModulePkg/MdeModulePkg.dec
>
> +  MdePkg/MdePkg.dec
>
> +  Platform/ARM/ARM.dec
>
> +  Platform/ARM/N1Sdp/N1SdpPlatform.dec
>
> +
>
> +[LibraryClasses]
>
> +  BaseLib
>
> +  BaseMemoryLib
>
> +  DebugLib
>
> +  DevicePathLib
>
> +  DxeServicesTableLib
>
> +  HobLib
>
> +  IoLib
>
> +  MemoryAllocationLib
>
> +  NorFlashInfoLib
>
> +  NorFlashPlatformLib
>
> +  TimerLib
>
> +  UefiBootServicesTableLib
>
> +  UefiDriverEntryPoint
>
> +  UefiLib
>
> +  UefiRuntimeLib
>
> +  UefiRuntimeServicesTableLib
>
> +
>
> +[Guids]
>
> +  gEdkiiNvVarStoreFormattedGuid
>
> +  gEfiAuthenticatedVariableGuid
>
> +  gEfiEventVirtualAddressChangeGuid
>
> +  gEfiSystemNvDataFvGuid
>
> +  gEfiVariableGuid
>
> +  gEfiGlobalVariableGuid
>
> +
>
> +[Protocols]
>
> +  gEfiDevicePathProtocolGuid
>
> +  gEfiFirmwareVolumeBlockProtocolGuid
>
> +
>
> +[FixedPcd]
>
> +  gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>
> +
>
> +[Depex]
>
> +  gEfiCpuArchProtocolGuid
>
> diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
> new file mode 100644
> index 000000000000..535e6d738d31
> --- /dev/null
> +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
> @@ -0,0 +1,33 @@
> +/** @file
>
> +
>
> +  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
>
> +
>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +
>
> +**/
>
> +
>
> +#ifndef CADENCE_QSPI_REG_H_
>
> +#define CADENCE_QSPI_REG_H_
>
> +
>
> +// QSPI Controller defines
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET             0x90
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE            0x01
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE        0x01
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS       19
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS  16
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT         0x02
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS     24
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE        0x01
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_BYTE_3B       0x02
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS     23
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS   20
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C           0x8
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_BIT_POS      7
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES(x)  ((x - 1) << CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS)
>
> +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES(x)  ((x - 1) << CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS)
>
> +
>
> +#define CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET  0xA0
>
> +
>
> +#define CDNS_QSPI_FLASH_CMD_ADDR_REG_OFFSET  0x94
>
> +
>
> +#endif /* CADENCE_QSPI_REG_H_ */
>
> diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
> new file mode 100644
> index 000000000000..38ae1c2fae89
> --- /dev/null
> +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
> @@ -0,0 +1,491 @@
> +/** @file
>
> +
>
> +  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
>
> +
>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +
>
> +**/
>
> +
>
> +#ifndef NOR_FLASH_DXE_H_
>
> +#define NOR_FLASH_DXE_H_
>
> +
>
> +#include <Guid/EventGroup.h>
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/NorFlashPlatformLib.h>
>
> +#include <PiDxe.h>
>
> +#include <Protocol/BlockIo.h>
>
> +#include <Protocol/DiskIo.h>
>
> +#include <Protocol/FirmwareVolumeBlock.h>
>
> +
>
> +#include "CadenceQspiReg.h"
>
> +
>
> +#define NOR_FLASH_ERASE_RETRY  10
>
> +
>
> +#define GET_NOR_BLOCK_ADDRESS(BaseAddr, Lba, LbaSize) \
>
> +                                      ((BaseAddr) + (UINTN)((Lba) * (LbaSize)))
>
> +
>
> +#define NOR_FLASH_SIGNATURE  SIGNATURE_32('S', 'n', 'o', 'r')
>
> +#define INSTANCE_FROM_FVB_THIS(a)  CR(a, NOR_FLASH_INSTANCE, FvbProtocol,   \
>
> +                                        NOR_FLASH_SIGNATURE)
>
> +
>
> +#define NOR_FLASH_POLL_FSR  BIT0
>
> +
>
> +typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE;
>
> +
>
> +typedef EFI_STATUS (*NOR_FLASH_INITIALIZE)        (
>
> +  NOR_FLASH_INSTANCE  *Instance
>
> +  );
>
> +
>
> +#pragma pack(1)
>
> +typedef struct {
>
> +  VENDOR_DEVICE_PATH          Vendor;
>
> +  UINT8                       Index;
>
> +  EFI_DEVICE_PATH_PROTOCOL    End;
>
> +} NOR_FLASH_DEVICE_PATH;
>
> +#pragma pack()
>
> +
>
> +struct _NOR_FLASH_INSTANCE {
>
> +  UINT32                                 Signature;
>
> +  EFI_HANDLE                             Handle;
>
> +
>
> +  BOOLEAN                                Initialized;
>
> +  NOR_FLASH_INITIALIZE                   Initialize;
>
> +
>
> +  UINTN                                  HostRegisterBaseAddress;
>
> +  UINTN                                  DeviceBaseAddress;
>
> +  UINTN                                  RegionBaseAddress;
>
> +  UINTN                                  Size;
>
> +  UINTN                                  BlockSize;
>
> +  UINTN                                  LastBlock;
>
> +  EFI_LBA                                StartLba;
>
> +  EFI_LBA                                OffsetLba;
>
> +
>
> +  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL    FvbProtocol;
>
> +  VOID                                   *ShadowBuffer;
>
> +
>
> +  NOR_FLASH_DEVICE_PATH                  DevicePath;
>
> +
>
> +  UINT32                                 Flags;
>
> +};
>
> +
>
> +typedef struct {
>
> +  EFI_TPL    OriginalTPL;
>
> +  BOOLEAN    InterruptsEnabled;
>
> +} NOR_FLASH_LOCK_CONTEXT;
>
> +
>
> +/**
>
> +  Lock all pending read/write to Nor flash device
>
> +
>
> +  @param[in]     Context     Nor flash device context structure.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +NorFlashLock (
>
> +  IN NOR_FLASH_LOCK_CONTEXT  *Context
>
> +  );
>
> +
>
> +/**
>
> +  Unlock all pending read/write to Nor flash device
>
> +
>
> +  @param[in]     Context     Nor flash device context structure.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +NorFlashUnlock (
>
> +  IN NOR_FLASH_LOCK_CONTEXT  *Context
>
> +  );
>
> +
>
> +extern UINTN  mFlashNvStorageVariableBase;
>
> +
>
> +/**
>
> +  Create Nor flash Instance for given region.
>
> +
>
> +  @param[in]    HostRegisterBase      Base address of Nor flash controller.
>
> +  @param[in]    NorFlashDeviceBase    Base address of flash device.
>
> +  @param[in]    NorFlashRegionBase    Base address of flash region on device.
>
> +  @param[in]    NorFlashSize          Size of flash region.
>
> +  @param[in]    Index                 Index of given flash region.
>
> +  @param[in]    BlockSize             Block size of NOR flash device.
>
> +  @param[in]    HasVarStore           Boolean set for VarStore on given region.
>
> +  @param[out]   NorFlashInstance      Instance of given flash region.
>
> +
>
> +  @retval       EFI_SUCCESS           On successful creation of NOR flash instance.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashCreateInstance (
>
> +  IN UINTN                HostRegisterBase,
>
> +  IN UINTN                NorFlashDeviceBase,
>
> +  IN UINTN                NorFlashRegionBase,
>
> +  IN UINTN                NorFlashSize,
>
> +  IN UINT32               Index,
>
> +  IN UINT32               BlockSize,
>
> +  IN BOOLEAN              HasVarStore,
>
> +  OUT NOR_FLASH_INSTANCE  **NorFlashInstance
>
> +  );
>
> +
>
> +/**
>
> +  Install Fv block on to variable store region
>
> +
>
> +  @param[in]   Instance         Instance of Nor flash variable region.
>
> +
>
> +  @retval      EFI_SUCCESS      The entry point is executed successfully.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +NorFlashFvbInitialize (
>
> +  IN NOR_FLASH_INSTANCE  *Instance
>
> +  );
>
> +
>
> +/**
>
> +  Check the integrity of firmware volume header.
>
> +
>
> +  @param[in]  Instance        Instance of Nor flash variable region.
>
> +
>
> +  @retval     EFI_SUCCESS     The firmware volume is consistent.
>
> +  @retval     EFI_NOT_FOUND   The firmware volume has been corrupted.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +ValidateFvHeader (
>
> +  IN  NOR_FLASH_INSTANCE  *Instance
>
> +  );
>
> +
>
> +/**
>
> +  Initialize the FV Header and Variable Store Header
>
> +  to support variable operations.
>
> +
>
> +  @param[in]  Instance      Location to Initialize the headers
>
> +
>
> +  @retval     EFI_SUCCESS   Fv init is done
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +InitializeFvAndVariableStoreHeaders (
>
> +  IN NOR_FLASH_INSTANCE  *Instance
>
> +  );
>
> +
>
> +/**
>
> + Retrieves the attributes and current settings of the block.
>
> +
>
> + @param[in]   This         Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[out]  Attributes   Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
>
> +                           current settings are returned.
>
> +                           Type EFI_FVB_ATTRIBUTES_2 is defined in
>
> +                           EFI_FIRMWARE_VOLUME_HEADER.
>
> +
>
> + @retval      EFI_SUCCESS  The firmware volume attributes were returned.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbGetAttributes (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes
>
> +  );
>
> +
>
> +/**
>
> + Sets configurable firmware volume attributes and returns the
>
> + new settings of the firmware volume.
>
> +
>
> +
>
> + @param[in]         This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[in, out]    Attributes               On input, Attributes is a pointer to
>
> +                                             EFI_FVB_ATTRIBUTES_2 that contains the desired
>
> +                                             firmware volume settings.
>
> +                                             On successful return, it contains the new
>
> +                                             settings of the firmware volume.
>
> +
>
> + @retval            EFI_UNSUPPORTED          The firmware volume attributes are not supported.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbSetAttributes (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
>
> +  );
>
> +
>
> +/**
>
> + Retrieves the base address of a memory-mapped firmware volume.
>
> + This function should be called only for memory-mapped firmware volumes.
>
> +
>
> + @param[in]     This               EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[out]    Address            Pointer to a caller-allocated
>
> +                                   EFI_PHYSICAL_ADDRESS that, on successful
>
> +                                   return from GetPhysicalAddress(), contains the
>
> +                                   base address of the firmware volume.
>
> +
>
> + @retval        EFI_SUCCESS        The firmware volume base address was returned.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbGetPhysicalAddress (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  OUT       EFI_PHYSICAL_ADDRESS                 *Address
>
> +  );
>
> +
>
> +/**
>
> + Retrieves the size of the requested block.
>
> + It also returns the number of additional blocks with the identical size.
>
> + The GetBlockSize() function is used to retrieve the block map
>
> + (see EFI_FIRMWARE_VOLUME_HEADER).
>
> +
>
> +
>
> + @param[in]     This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[in]     Lba                      Indicates the block whose size to return
>
> +
>
> + @param[out]    BlockSize                Pointer to a caller-allocated UINTN in which
>
> +                                         the size of the block is returned.
>
> +
>
> + @param[out]    NumberOfBlocks           Pointer to a caller-allocated UINTN in
>
> +                                         which the number of consecutive blocks,
>
> +                                         starting with Lba, is returned. All
>
> +                                         blocks in this range have a size of
>
> +                                         BlockSize.
>
> +
>
> + @retval        EFI_SUCCESS              The firmware volume base address was returned.
>
> +
>
> + @retval        EFI_INVALID_PARAMETER    The requested LBA is out of range.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbGetBlockSize (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  IN        EFI_LBA                              Lba,
>
> +  OUT       UINTN                                *BlockSize,
>
> +  OUT       UINTN                                *NumberOfBlocks
>
> +  );
>
> +
>
> +/**
>
> + Reads the specified number of bytes into a buffer from the specified block.
>
> +
>
> + The Read() function reads the requested number of bytes from the
>
> + requested block and stores them in the provided buffer.
>
> +
>
> + @param[in]       This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[in]       Lba                  The starting logical block index from which to read
>
> +
>
> + @param[in]       Offset               Offset into the block at which to begin reading.
>
> +
>
> + @param[in, out]  NumBytes             Pointer to a UINTN.
>
> +                                       At entry, *NumBytes contains the total size of the
>
> +                                       buffer. *NumBytes should have a non zero value.
>
> +                                       At exit, *NumBytes contains the total number of
>
> +                                       bytes read.
>
> +
>
> + @param[in out]   Buffer               Pointer to a caller-allocated buffer that will be
>
> +                                       used to hold the data that is read.
>
> +
>
> + @retval          EFI_SUCCESS          The firmware volume was read successfully, and
>
> +                                       contents are in Buffer.
>
> +
>
> + @retval          EFI_BAD_BUFFER_SIZE  Read attempted across an LBA boundary.
>
> +
>
> + @retval          EFI_DEVICE_ERROR     The block device is not functioning correctly and
>
> +                                       could not be read.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbRead (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  IN        EFI_LBA                              Lba,
>
> +  IN        UINTN                                Offset,
>
> +  IN OUT    UINTN                                *NumBytes,
>
> +  IN OUT    UINT8                                *Buffer
>
> +  );
>
> +
>
> +/**
>
> + Writes the specified number of bytes from the input buffer to the block.
>
> +
>
> + @param[in]        This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[in]        Lba                  The starting logical block index to write to.
>
> +
>
> + @param[in]        Offset               Offset into the block at which to begin writing.
>
> +
>
> + @param[in, out]   NumBytes             The pointer to a UINTN.
>
> +                                        At entry, *NumBytes contains the total size of the
>
> +                                        buffer.
>
> +                                        At exit, *NumBytes contains the total number of
>
> +                                        bytes actually written.
>
> +
>
> + @param[in]        Buffer               The pointer to a caller-allocated buffer that
>
> +                                        contains the source for the write.
>
> +
>
> + @retval           EFI_SUCCESS          The firmware volume was written successfully.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbWrite (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  IN        EFI_LBA                              Lba,
>
> +  IN        UINTN                                Offset,
>
> +  IN OUT    UINTN                                *NumBytes,
>
> +  IN        UINT8                                *Buffer
>
> +  );
>
> +
>
> +/**
>
> + Erases and initialises a firmware volume block.
>
> +
>
> + @param[in]   This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
>
> +
>
> + @param[in]   ...                      The variable argument list is a list of tuples.
>
> +                                       Each tuple describes a range of LBAs to erase
>
> +                                       and consists of the following:
>
> +                                       - An EFI_LBA that indicates the starting LBA
>
> +                                       - A UINTN that indicates the number of blocks
>
> +                                       to erase.
>
> +
>
> +                                       The list is terminated with an
>
> +                                       EFI_LBA_LIST_TERMINATOR.
>
> +
>
> + @retval      EFI_SUCCESS              The erase request successfully completed.
>
> +
>
> + @retval      EFI_ACCESS_DENIED        The firmware volume is in the WriteDisabled
>
> +                                       state.
>
> +
>
> + @retval      EFI_DEVICE_ERROR         The block device is not functioning correctly
>
> +                                       and could not be written.
>
> +                                       The firmware device may have been partially
>
> +                                       erased.
>
> +
>
> + @retval      EFI_INVALID_PARAMETER    One or more of the LBAs listed in the variable
>
> +                                       argument list do not exist in the firmware
>
> +                                       volume.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbEraseBlocks (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  ...
>
> +  );
>
> +
>
> +/**
>
> +  This function unlock and erase an entire NOR Flash block.
>
> +
>
> +  @param[in]     Instance       NOR flash Instance of variable store region.
>
> +  @param[in]     BlockAddress   Block address within the variable store region.
>
> +
>
> +  @retval        EFI_SUCCESS    The erase and unlock successfully completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashUnlockAndEraseSingleBlock (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN UINTN               BlockAddress
>
> +  );
>
> +
>
> +/**
>
> +  Write a full or portion of a block.
>
> +
>
> +  @param[in]        Instance     NOR flash Instance of variable store region.
>
> +  @param[in]        Lba          The starting logical block index to write to.
>
> +  @param[in]        Offset       Offset into the block at which to begin writing.
>
> +  @param[in,out]    NumBytes     The total size of the buffer.
>
> +  @param[in]        Buffer       The pointer to a caller-allocated buffer that
>
> +                                 contains the source for the write.
>
> +
>
> +  @retval           EFI_SUCCESS  The write is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashWriteSingleBlock (
>
> +  IN        NOR_FLASH_INSTANCE  *Instance,
>
> +  IN        EFI_LBA             Lba,
>
> +  IN        UINTN               Offset,
>
> +  IN OUT    UINTN               *NumBytes,
>
> +  IN        UINT8               *Buffer
>
> +  );
>
> +
>
> +/**
>
> +  Write a full  block.
>
> +
>
> +  @param[in]    Instance             NOR flash Instance of variable store region.
>
> +  @param[in]    Lba                  The starting logical block index to write to.
>
> +  @param[in]    BufferSizeInBytes    The number of bytes to write.
>
> +  @param[in]    Buffer               The pointer to a caller-allocated buffer that
>
> +                                     contains the source for the write.
>
> +
>
> +  @retval       EFI_SUCCESS          The write is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashWriteBlocks (
>
> +  IN  NOR_FLASH_INSTANCE  *Instance,
>
> +  IN  EFI_LBA             Lba,
>
> +  IN  UINTN               BufferSizeInBytes,
>
> +  IN  VOID                *Buffer
>
> +  );
>
> +
>
> +/**
>
> +  Read a full  block.
>
> +
>
> +  @param[in]     Instance           NOR flash Instance of variable store region.
>
> +  @param[in]     Lba                The starting logical block index to read from.
>
> +  @param[in]     BufferSizeInBytes  The number of bytes to read.
>
> +  @param[out]    Buffer             The pointer to a caller-allocated buffer that
>
> +                                    should be copied with read data.
>
> +
>
> +  @retval        EFI_SUCCESS        The read is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashReadBlocks (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN EFI_LBA             Lba,
>
> +  IN UINTN               BufferSizeInBytes,
>
> +  OUT VOID               *Buffer
>
> +  );
>
> +
>
> +/**
>
> +  Read from nor flash.
>
> +
>
> +  @param[in]     Instance           NOR flash Instance of variable store region.
>
> +  @param[in]     Lba                The starting logical block index to read from.
>
> +  @param[in]     Offset             Offset into the block at which to begin reading.
>
> +  @param[in]     BufferSizeInBytes  The number of bytes to read.
>
> +  @param[out]    Buffer             The pointer to a caller-allocated buffer that
>
> +                                    should copied with read data.
>
> +
>
> +  @retval        EFI_SUCCESS        The read is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashRead (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN EFI_LBA             Lba,
>
> +  IN UINTN               Offset,
>
> +  IN UINTN               BufferSizeInBytes,
>
> +  OUT VOID               *Buffer
>
> +  );
>
> +
>
> +/**
>
> +  Read JEDEC ID of NOR flash device.
>
> +
>
> +  @param[in]     Instance     NOR flash Instance of variable store region.
>
> +  @param[out]    JedecId      JEDEC ID of NOR flash device.
>
> +
>
> +  @retval        EFI_SUCCESS  The write is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashReadID (
>
> +  IN  NOR_FLASH_INSTANCE  *Instance,
>
> +  OUT UINT8               JedecId[3]
>
> +  );
>
> +
>
> +#define SPINOR_SR_WIP  BIT0                 // Write in progress
>
> +
>
> +#define SPINOR_OP_WREN   0x06               // Write enable
>
> +#define SPINOR_OP_BE_4K  0x20               // Erase 4KiB block
>
> +#define SPINOR_OP_RDID   0x9f               // Read JEDEC ID
>
> +#define SPINOR_OP_RDSR   0x05               // Read status register
>
> +
>
> +#define SPINOR_SR_WIP_POLL_TIMEOUT_MS  1000u // Status Register read timeout
>
> +
>
> +#endif /* NOR_FLASH_DXE_H_ */
>
> diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c
> new file mode 100644
> index 000000000000..fffe689161a6
> --- /dev/null
> +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c
> @@ -0,0 +1,409 @@
> +/** @file
>
> +  NOR flash DXE
>
> +
>
> +  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
>
> +
>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +
>
> +**/
>
> +
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Library/DxeServicesTableLib.h>
>
> +#include <Library/HobLib.h>
>
> +#include <Library/MemoryAllocationLib.h>
>
> +#include <Library/NorFlashInfoLib.h>
>
> +#include <Library/PcdLib.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/UefiLib.h>
>
> +#include <Library/UefiRuntimeLib.h>
>
> +#include <Library/UefiRuntimeServicesTableLib.h>
>
> +
>
> +#include "NorFlash.h"
>
> +
>
> +STATIC NOR_FLASH_INSTANCE  **mNorFlashInstances;
>
> +STATIC UINT32              mNorFlashDeviceCount;
>
> +
>
> +STATIC EFI_EVENT  mNorFlashVirtualAddrChangeEvent;
>
> +
>
> +/**
>
> +  Install Fv block onto variable store region
>
> +
>
> +  @param[in]   Instance         Instance of Nor flash variable region.
>
> +
>
> +  @retval      EFI_SUCCESS      The entry point is executed successfully.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +NorFlashFvbInitialize (
>
> +  IN NOR_FLASH_INSTANCE  *Instance
>
> +  )
>
> +{
>
> +  EFI_STATUS     Status;
>
> +  UINT32         FvbNumLba;
>
> +  EFI_BOOT_MODE  BootMode;
>
> +  UINTN          RuntimeMmioRegionSize;
>
> +  UINTN          RuntimeMmioDeviceSize;
>
> +  UINTN          BlockSize;
>
> +
>
> +  DEBUG ((DEBUG_INFO, "NorFlashFvbInitialize\n"));
>
> +
>
> +  BlockSize = Instance->BlockSize;
>
> +
>
> +  // FirmwareVolumeHeader->FvLength is declared to have the Variable area
>
> +  // AND the FTW working area AND the FTW Spare contiguous.
>
> +  ASSERT (
>
> +    PcdGet32 (PcdFlashNvStorageVariableBase) +
>
> +    PcdGet32 (PcdFlashNvStorageVariableSize) ==
>
> +    PcdGet32 (PcdFlashNvStorageFtwWorkingBase)
>
> +    );
>
> +  ASSERT (
>
> +    PcdGet32 (PcdFlashNvStorageFtwWorkingBase) +
>
> +    PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ==
>
> +    PcdGet32 (PcdFlashNvStorageFtwSpareBase)
>
> +    );
>
> +
>
> +  // Check if the size of the area is at least one block size.
>
> +  ASSERT (
>
> +    (PcdGet32 (PcdFlashNvStorageVariableSize) > 0) &&
>
> +    (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0)
>
> +    );
>
> +  ASSERT (
>
> +    (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) &&
>
> +    (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0)
>
> +    );
>
> +  ASSERT (
>
> +    (PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) &&
>
> +    (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0)
>
> +    );
>
> +
>
> +  // Ensure the Variable areas are aligned on block size boundaries.
>
> +  ASSERT ((PcdGet32 (PcdFlashNvStorageVariableBase) % BlockSize) == 0);
>
> +  ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) % BlockSize) == 0);
>
> +  ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareBase) % BlockSize) == 0);
>
> +
>
> +  Instance->Initialized       = TRUE;
>
> +  mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
>
> +
>
> +  // Set the index of the first LBA for the FVB.
>
> +  Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) -
>
> +                        Instance->RegionBaseAddress) / BlockSize;
>
> +
>
> +  BootMode = GetBootModeHob ();
>
> +  if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
>
> +    Status = EFI_INVALID_PARAMETER;
>
> +  } else {
>
> +    // Determine if there is a valid header at the beginning of the NorFlash.
>
> +    Status = ValidateFvHeader (Instance);
>
> +  }
>
> +
>
> +  // Install the Default FVB header if required.
>
> +  if (EFI_ERROR (Status)) {
>
> +    // There is no valid header, so time to install one.
>
> +    DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __func__));
>
> +    DEBUG ((
>
> +      DEBUG_INFO,
>
> +      "%a: Installing a correct one for this volume.\n",
>
> +      __func__
>
> +      ));
>
> +
>
> +    // Erase all the NorFlash that is reserved for variable storage.
>
> +    FvbNumLba = (PcdGet32 (PcdFlashNvStorageVariableSize) +
>
> +                 PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
>
> +                 PcdGet32 (PcdFlashNvStorageFtwSpareSize)) /
>
> +                Instance->BlockSize;
>
> +
>
> +    Status = FvbEraseBlocks (
>
> +               &Instance->FvbProtocol,
>
> +               (EFI_LBA)0,
>
> +               FvbNumLba,
>
> +               EFI_LBA_LIST_TERMINATOR
>
> +               );
>
> +    if (EFI_ERROR (Status)) {
>
> +      return Status;
>
> +    }
>
> +
>
> +    // Install all appropriate headers.
>
> +    Status = InitializeFvAndVariableStoreHeaders (Instance);
>
> +    if (EFI_ERROR (Status)) {
>
> +      return Status;
>
> +    }
>
> +
>
> +    // validate FV header again if FV was created successfully.
>
> +    Status = ValidateFvHeader (Instance);
>
> +    if (EFI_ERROR (Status)) {
>
> +      DEBUG ((DEBUG_ERROR, "ValidateFvHeader is failed \n"));
>
> +      return Status;
>
> +    }
>
> +  }
>
> +
>
> +  // The driver implementing the variable read service can now be dispatched;
>
> +  // the varstore headers are in place.
>
> +  Status = gBS->InstallProtocolInterface (
>
> +                  &gImageHandle,
>
> +                  &gEdkiiNvVarStoreFormattedGuid,
>
> +                  EFI_NATIVE_INTERFACE,
>
> +                  NULL
>
> +                  );
>
> +  if (EFI_ERROR (Status)) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "%a: Failed to install gEdkiiNvVarStoreFormattedGuid\n",
>
> +      __func__
>
> +      ));
>
> +    return Status;
>
> +  }
>
> +
>
> +  // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME.
>
> +  RuntimeMmioRegionSize = Instance->Size;
>
> +  RuntimeMmioDeviceSize = Instance->RegionBaseAddress - Instance->DeviceBaseAddress;
>
> +
>
> +  Status = gDS->AddMemorySpace (
>
> +                  EfiGcdMemoryTypeMemoryMappedIo,
>
> +                  Instance->RegionBaseAddress,
>
> +                  RuntimeMmioRegionSize,
>
> +                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
>
> +                  );
>
> +  ASSERT_EFI_ERROR (Status);
>
> +
>
> +  Status = gDS->AddMemorySpace (
>
> +                  EfiGcdMemoryTypeMemoryMappedIo,
>
> +                  Instance->DeviceBaseAddress,
>
> +                  RuntimeMmioDeviceSize,
>
> +                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
>
> +                  );
>
> +  ASSERT_EFI_ERROR (Status);
>
> +
>
> +  Status = gDS->SetMemorySpaceAttributes (
>
> +                  Instance->RegionBaseAddress,
>
> +                  RuntimeMmioRegionSize,
>
> +                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
>
> +                  );
>
> +  ASSERT_EFI_ERROR (Status);
>
> +
>
> +  Status = gDS->SetMemorySpaceAttributes (
>
> +                  Instance->DeviceBaseAddress,
>
> +                  RuntimeMmioDeviceSize,
>
> +                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
>
> +                  );
>
> +  ASSERT_EFI_ERROR (Status);
>
> +
>
> +  return Status;
>
> +}
>
> +
>
> +/**
>
> +  Fixup internal data so that EFI can be called in virtual mode.
>
> +  convert any pointers in lib to virtual mode.
>
> +
>
> +  @param[in]    Event   The Event that is being processed
>
> +  @param[in]    Context Event Context
>
> +**/
>
> +STATIC
>
> +VOID
>
> +EFIAPI
>
> +NorFlashVirtualNotifyEvent (
>
> +  IN EFI_EVENT  Event,
>
> +  IN VOID       *Context
>
> +  )
>
> +{
>
> +  UINTN  Index;
>
> +
>
> +  EfiConvertPointer (0x0, (VOID **)&mFlashNvStorageVariableBase);
>
> +
>
> +  for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->HostRegisterBaseAddress
>
> +      );
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress
>
> +      );
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress
>
> +      );
>
> +
>
> +    // Convert Fvb.
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks
>
> +      );
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes
>
> +      );
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize
>
> +      );
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress
>
> +      );
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read
>
> +      );
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes
>
> +      );
>
> +    EfiConvertPointer (
>
> +      0x0,
>
> +      (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write
>
> +      );
>
> +
>
> +    if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
>
> +      EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowBuffer);
>
> +    }
>
> +  }
>
> +}
>
> +
>
> +/**
>
> +  Entrypoint of Platform Nor flash DXE driver
>
> +
>
> +  @param[in]  ImageHandle       The firmware allocated handle for the EFI image.
>
> +  @param[in]  SystemTable       A pointer to the EFI System Table.
>
> +
>
> +  @retval     EFI_SUCCESS       The entry point is executed successfully.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +NorFlashInitialise (
>
> +  IN EFI_HANDLE        ImageHandle,
>
> +  IN EFI_SYSTEM_TABLE  *SystemTable
>
> +  )
>
> +{
>
> +  EFI_STATUS             Status;
>
> +  EFI_PHYSICAL_ADDRESS   HostRegisterBaseAddress;
>
> +  UINT32                 Index;
>
> +  NOR_FLASH_DESCRIPTION  *NorFlashDevices;
>
> +  BOOLEAN                ContainVariableStorage;
>
> +
>
> +  HostRegisterBaseAddress = PcdGet32 (PcdCadenceQspiDxeRegBaseAddress);
>
> +
>
> +  Status = gDS->AddMemorySpace (
>
> +                  EfiGcdMemoryTypeMemoryMappedIo,
>
> +                  HostRegisterBaseAddress,
>
> +                  SIZE_64KB,
>
> +                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
>
> +                  );
>
> +  ASSERT_EFI_ERROR (Status);
>
> +
>
> +  Status = gDS->SetMemorySpaceAttributes (
>
> +                  HostRegisterBaseAddress,
>
> +                  SIZE_64KB,
>
> +                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
>
> +                  );
>
> +  ASSERT_EFI_ERROR (Status);
>
> +
>
> +  // Initialize NOR flash instances.
>
> +  Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);
>
> +  if (EFI_ERROR (Status)) {
>
> +    DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to get Nor Flash devices\n"));
>
> +    return Status;
>
> +  }
>
> +
>
> +  mNorFlashInstances = AllocateRuntimePool (
>
> +                         sizeof (NOR_FLASH_INSTANCE *) *
>
> +                         mNorFlashDeviceCount
>
> +                         );
>
> +
>
> +  if (mNorFlashInstances == NULL) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "NorFlashInitialise: Failed to allocate mem for NorFlashInstance\n"
>
> +      ));
>
> +    return EFI_OUT_OF_RESOURCES;
>
> +  }
>
> +
>
> +  for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
>
> +    // Check if this NOR Flash device contain the variable storage region.
>
> +    ContainVariableStorage =
>
> +      (NorFlashDevices[Index].RegionBaseAddress <=
>
> +       PcdGet32 (PcdFlashNvStorageVariableBase)) &&
>
> +      (PcdGet32 (PcdFlashNvStorageVariableBase) +
>
> +       PcdGet32 (PcdFlashNvStorageVariableSize) <=
>
> +       NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
>
> +
>
> +    Status = NorFlashCreateInstance (
>
> +               HostRegisterBaseAddress,
>
> +               NorFlashDevices[Index].DeviceBaseAddress,
>
> +               NorFlashDevices[Index].RegionBaseAddress,
>
> +               NorFlashDevices[Index].Size,
>
> +               Index,
>
> +               NorFlashDevices[Index].BlockSize,
>
> +               ContainVariableStorage,
>
> +               &mNorFlashInstances[Index]
>
> +               );
>
> +    if (EFI_ERROR (Status)) {
>
> +      DEBUG ((
>
> +        DEBUG_ERROR,
>
> +        "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",
>
> +        Index
>
> +        ));
>
> +      continue;
>
> +    }
>
> +
>
> +    Status = gBS->InstallMultipleProtocolInterfaces (
>
> +                    &mNorFlashInstances[Index]->Handle,
>
> +                    &gEfiDevicePathProtocolGuid,
>
> +                    &mNorFlashInstances[Index]->DevicePath,
>
> +                    &gEfiFirmwareVolumeBlockProtocolGuid,
>
> +                    &mNorFlashInstances[Index]->FvbProtocol,
>
> +                    NULL
>
> +                    );
>
> +    ASSERT_EFI_ERROR (Status);
>
> +  }
>
> +
>
> +  // Register for the virtual address change event.
>
> +  Status = gBS->CreateEventEx (
>
> +                  EVT_NOTIFY_SIGNAL,
>
> +                  TPL_NOTIFY,
>
> +                  NorFlashVirtualNotifyEvent,
>
> +                  NULL,
>
> +                  &gEfiEventVirtualAddressChangeGuid,
>
> +                  &mNorFlashVirtualAddrChangeEvent
>
> +                  );
>
> +  ASSERT_EFI_ERROR (Status);
>
> +
>
> +  return Status;
>
> +}
>
> +
>
> +/**
>
> +  Lock all pending read/write to Nor flash device
>
> +
>
> +  @param[in]     Context     Nor flash device context structure.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +NorFlashLock (
>
> +  IN NOR_FLASH_LOCK_CONTEXT  *Context
>
> +  )
>
> +{
>
> +  if (!EfiAtRuntime ()) {
>
> +    // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
>
> +    Context->OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
>
> +  } else {
>
> +    Context->InterruptsEnabled = SaveAndDisableInterrupts ();
>
> +  }
>
> +}
>
> +
>
> +/**
>
> +  Unlock all pending read/write to Nor flash device
>
> +
>
> +  @param[in]     Context     Nor flash device context structure.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +NorFlashUnlock (
>
> +  IN NOR_FLASH_LOCK_CONTEXT  *Context
>
> +  )
>
> +{
>
> +  if (!EfiAtRuntime ()) {
>
> +    // Interruptions can resume.
>
> +    gBS->RestoreTPL (Context->OriginalTPL);
>
> +  } else if (Context->InterruptsEnabled) {
>
> +    SetInterruptState (TRUE);
>
> +  }
>
> +}
>
> diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
> new file mode 100644
> index 000000000000..be7b626c5697
> --- /dev/null
> +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
> @@ -0,0 +1,1100 @@
> +/** @file
>
> +
>
> +  Copyright (c) 2023 ARM Limited. All rights reserved.<BR>
>
> +
>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +
>
> +**/
>
> +
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Library/MemoryAllocationLib.h>
>
> +#include <Library/NorFlashInfoLib.h>
>
> +#include <Library/PcdLib.h>
>
> +#include <Library/TimerLib.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/UefiLib.h>
>
> +
>
> +#include "NorFlash.h"
>
> +
>
> +STATIC CONST NOR_FLASH_INSTANCE  mNorFlashInstanceTemplate = {
>
> +  NOR_FLASH_SIGNATURE, // Signature
>
> +  NULL,                // Handle
>
> +
>
> +  FALSE, // Initialized
>
> +  NULL,  // Initialize
>
> +
>
> +  0, // HostRegisterBaseAddress
>
> +  0, // DeviceBaseAddress
>
> +  0, // RegionBaseAddress
>
> +  0, // Size
>
> +  0, // BlockSize
>
> +  0, // LastBlock
>
> +  0, // StartLba
>
> +  0, // OffsetLba
>
> +
>
> +  {
>
> +    FvbGetAttributes,      // GetAttributes
>
> +    FvbSetAttributes,      // SetAttributes
>
> +    FvbGetPhysicalAddress, // GetPhysicalAddress
>
> +    FvbGetBlockSize,       // GetBlockSize
>
> +    FvbRead,               // Read
>
> +    FvbWrite,              // Write
>
> +    FvbEraseBlocks,        // EraseBlocks
>
> +    NULL,                  // ParentHandle
>
> +  },    //  FvbProtoccol;
>
> +  NULL, // ShadowBuffer
>
> +
>
> +  {
>
> +    {
>
> +      {
>
> +        HARDWARE_DEVICE_PATH,
>
> +        HW_VENDOR_DP,
>
> +        {
>
> +          (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),
>
> +          (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)
>
> +        }
>
> +      },
>
> +      { 0x0,                               0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
>
> +      },
>
> +    },
>
> +    0, // Index
>
> +
>
> +    {
>
> +      END_DEVICE_PATH_TYPE,
>
> +      END_ENTIRE_DEVICE_PATH_SUBTYPE,
>
> +      { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
>
> +    }
>
> +  }, // DevicePath
>
> +  0  // Flags
>
> +};
>
> +
>
> +/**
>
> +  Execute Flash cmd ctrl and Read Status.
>
> +
>
> +  @param[in]      Instance         NOR flash Instance.
>
> +  @param[in]      Val              Value to be written to Flash cmd ctrl Register.
>
> +
>
> +  @retval         EFI_SUCCESS      Request is executed successfully.
>
> +
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +CdnsQspiExecuteCommand (
>
> +  IN  NOR_FLASH_INSTANCE  *Instance,
>
> +  IN  UINT32              Val
>
> +  )
>
> +{
>
> +  // Set the command
>
> +  MmioWrite32 (
>
> +    Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET,
>
> +    Val
>
> +    );
>
> +  // Execute the command
>
> +  MmioWrite32 (
>
> +    Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET,
>
> +    Val | CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE
>
> +    );
>
> +
>
> +  // Wait until command has been executed
>
> +  while ((MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET)
>
> +          & CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT) == CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT)
>
> +  {
>
> +    continue;
>
> +  }
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> +  Create Nor flash Instance for given region.
>
> +
>
> +  @param[in]    HostRegisterBase      Base address of Nor flash controller.
>
> +  @param[in]    NorFlashDeviceBase    Base address of flash device.
>
> +  @param[in]    NorFlashRegionBase    Base address of flash region on device.
>
> +  @param[in]    NorFlashSize          Size of flash region.
>
> +  @param[in]    Index                 Index of given flash region.
>
> +  @param[in]    BlockSize             Block size of NOR flash device.
>
> +  @param[in]    HasVarStore           Boolean set for VarStore on given region.
>
> +  @param[out]   NorFlashInstance      Instance of given flash region.
>
> +
>
> +  @retval       EFI_SUCCESS           On successful creation of NOR flash instance.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashCreateInstance (
>
> +  IN UINTN                HostRegisterBase,
>
> +  IN UINTN                NorFlashDeviceBase,
>
> +  IN UINTN                NorFlashRegionBase,
>
> +  IN UINTN                NorFlashSize,
>
> +  IN UINT32               Index,
>
> +  IN UINT32               BlockSize,
>
> +  IN BOOLEAN              HasVarStore,
>
> +  OUT NOR_FLASH_INSTANCE  **NorFlashInstance
>
> +  )
>
> +{
>
> +  EFI_STATUS          Status;
>
> +  NOR_FLASH_INSTANCE  *Instance;
>
> +  NOR_FLASH_INFO      *FlashInfo;
>
> +  UINT8               JedecId[3];
>
> +
>
> +  ASSERT (NorFlashInstance != NULL);
>
> +  Instance = AllocateRuntimeCopyPool (
>
> +               sizeof (mNorFlashInstanceTemplate),
>
> +               &mNorFlashInstanceTemplate
>
> +               );
>
> +  if (Instance == NULL) {
>
> +    return EFI_OUT_OF_RESOURCES;
>
> +  }
>
> +
>
> +  Instance->HostRegisterBaseAddress = HostRegisterBase;
>
> +  Instance->DeviceBaseAddress       = NorFlashDeviceBase;
>
> +  Instance->RegionBaseAddress       = NorFlashRegionBase;
>
> +  Instance->Size                    = NorFlashSize;
>
> +  Instance->BlockSize               = BlockSize;
>
> +  Instance->LastBlock               = (NorFlashSize / BlockSize) - 1;
>
> +
>
> +  Instance->OffsetLba = (NorFlashRegionBase - NorFlashDeviceBase) / BlockSize;
>
> +
>
> +  CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);
>
> +  Instance->DevicePath.Index = (UINT8)Index;
>
> +
>
> +  Status = NorFlashReadID (Instance, JedecId);
>
> +  if (EFI_ERROR (Status)) {
>
> +    goto FreeInstance;
>
> +  }
>
> +
>
> +  Status = NorFlashGetInfo (JedecId, &FlashInfo, TRUE);
>
> +  if (EFI_ERROR (Status)) {
>
> +    goto FreeInstance;
>
> +  }
>
> +
>
> +  NorFlashPrintInfo (FlashInfo);
>
> +
>
> +  Instance->Flags = 0;
>
> +  if (FlashInfo->Flags & NOR_FLASH_WRITE_FSR) {
>
> +    Instance->Flags = NOR_FLASH_POLL_FSR;
>
> +  }
>
> +
>
> +  Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);
>
> +  if (Instance->ShadowBuffer == NULL) {
>
> +    Status = EFI_OUT_OF_RESOURCES;
>
> +    goto FreeInstance;
>
> +  }
>
> +
>
> +  if (HasVarStore) {
>
> +    Instance->Initialize = NorFlashFvbInitialize;
>
> +  }
>
> +
>
> +  *NorFlashInstance = Instance;
>
> +  FreePool (FlashInfo);
>
> +  return EFI_SUCCESS;
>
> +
>
> +FreeInstance:
>
> +  FreePool (Instance);
>
> +  return Status;
>
> +}
>
> +
>
> +/**
>
> +  Converts milliseconds into number of ticks of the performance counter.
>
> +
>
> +  @param[in] Milliseconds  Milliseconds to convert into ticks.
>
> +
>
> +  @retval Milliseconds expressed as number of ticks.
>
> +
>
> +**/
>
> +STATIC
>
> +UINT64
>
> +MilliSecondsToTicks (
>
> +  IN UINTN  Milliseconds
>
> +  )
>
> +{
>
> +  CONST UINT64  NanoSecondsPerTick = GetTimeInNanoSecond (1);
>
> +
>
> +  return (Milliseconds * 1000000) / NanoSecondsPerTick;
>
> +}
>
> +
>
> +/**
>
> +  Poll Status register for NOR flash erase/write completion.
>
> +
>
> +  @param[in]      Instance           NOR flash Instance.
>
> +
>
> +  @retval         EFI_SUCCESS        Request is executed successfully.
>
> +  @retval         EFI_TIMEOUT        Operation timed out.
>
> +  @retval         EFI_DEVICE_ERROR   Controller operartion failed.
>
> +
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +NorFlashPollStatusRegister (
>
> +  IN NOR_FLASH_INSTANCE  *Instance
>
> +  )
>
> +{
>
> +  BOOLEAN  SRegDone;
>
> +  UINT32   val;
>
> +
>
> +  val = SPINOR_OP_RDSR << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
>
> +        CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS |
>
> +        CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES (1) |
>
> +        CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C << CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_BIT_POS;
>
> +
>
> +  CONST UINT64  TickOut =
>
> +    GetPerformanceCounter () + MilliSecondsToTicks (SPINOR_SR_WIP_POLL_TIMEOUT_MS);
>
> +
>
> +  do {
>
> +    if (GetPerformanceCounter () > TickOut) {
>
> +      DEBUG ((
>
> +        DEBUG_ERROR,
>
> +        "NorFlashPollStatusRegister: Timeout waiting for erase/write.\n"
>
> +        ));
>
> +      return EFI_TIMEOUT;
>
> +    }
>
> +
>
> +    if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
>
> +      return EFI_DEVICE_ERROR;
>
> +    }
>
> +
>
> +    SRegDone =
>
> +      (MmioRead8 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET)
>
> +       & SPINOR_SR_WIP) == 0;
>
> +  } while (!SRegDone);
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> +  Check whether NOR flash opertions are Locked.
>
> +
>
> +  @param[in]     Instance         NOR flash Instance.
>
> +  @param[in]     BlockAddress     BlockAddress in NOR flash device.
>
> +
>
> +  @retval        FALSE            If NOR flash is not locked.
>
> +**/
>
> +STATIC
>
> +BOOLEAN
>
> +NorFlashBlockIsLocked (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN UINTN               BlockAddress
>
> +  )
>
> +{
>
> +  return FALSE;
>
> +}
>
> +
>
> +/**
>
> +  Unlock NOR flash operations on given block.
>
> +
>
> +  @param[in]      Instance         NOR flash instance.
>
> +  @param[in]      BlockAddress     BlockAddress in NOR flash device.
>
> +
>
> +  @retval         EFI_SUCCESS      NOR flash operations is unlocked.
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +NorFlashUnlockSingleBlock (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN UINTN               BlockAddress
>
> +  )
>
> +{
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> +  Unlock NOR flash operations if it is necessary.
>
> +
>
> +  @param[in]      Instance         NOR flash instance.
>
> +  @param[in]      BlockAddress     BlockAddress in NOR flash device.
>
> +
>
> +  @retval         EFI_SUCCESS      Request is executed successfully.
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +NorFlashUnlockSingleBlockIfNecessary (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN UINTN               BlockAddress
>
> +  )
>
> +{
>
> +  EFI_STATUS  Status;
>
> +
>
> +  Status = EFI_SUCCESS;
>
> +
>
> +  if (!NorFlashBlockIsLocked (Instance, BlockAddress)) {
>
> +    Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
>
> +  }
>
> +
>
> +  return Status;
>
> +}
>
> +
>
> +/**
>
> +  Enable write to NOR flash device.
>
> +
>
> +  @param[in]      Instance         NOR flash instance.
>
> +
>
> +  @retval         EFI_SUCCESS      Request is executed successfully.
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +NorFlashEnableWrite (
>
> +  IN  NOR_FLASH_INSTANCE  *Instance
>
> +  )
>
> +{
>
> +  UINT32  val;
>
> +
>
> +  DEBUG ((DEBUG_INFO, "NorFlashEnableWrite()\n"));
>
> +  val = (SPINOR_OP_WREN << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS);
>
> +  if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> +  The following function presumes that the block has already been unlocked.
>
> +
>
> +  @param[in]      Instance         NOR flash instance.
>
> +  @param[in]      BlockAddress     Block address within the variable region.
>
> +
>
> +  @retval         EFI_SUCCESS      Request is executed successfully.
>
> + **/
>
> +EFI_STATUS
>
> +NorFlashEraseSingleBlock (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN UINTN               BlockAddress
>
> +  )
>
> +{
>
> +  UINT32  DevConfigVal;
>
> +  UINT32  EraseOffset;
>
> +
>
> +  EraseOffset = 0x0;
>
> +
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "NorFlashEraseSingleBlock(BlockAddress=0x%08x)\n",
>
> +    BlockAddress
>
> +    ));
>
> +
>
> +  if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  EraseOffset = BlockAddress - Instance->DeviceBaseAddress;
>
> +
>
> +  MmioWrite32 (
>
> +    Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_ADDR_REG_OFFSET,
>
> +    EraseOffset
>
> +    );
>
> +
>
> +  DevConfigVal = SPINOR_OP_BE_4K << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
>
> +                 CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS |
>
> +                 CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES (3);
>
> +
>
> +  if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, DevConfigVal))) {
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) {
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> +  This function unlock and erase an entire NOR Flash block.
>
> +
>
> +  @param[in]     Instance       NOR flash Instance of variable store region.
>
> +  @param[in]     BlockAddress   Block address within the variable store region.
>
> +
>
> +  @retval        EFI_SUCCESS    The erase and unlock successfully completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashUnlockAndEraseSingleBlock (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN UINTN               BlockAddress
>
> +  )
>
> +{
>
> +  EFI_STATUS              Status;
>
> +  UINTN                   Index;
>
> +  NOR_FLASH_LOCK_CONTEXT  Lock;
>
> +
>
> +  NorFlashLock (&Lock);
>
> +
>
> +  Index = 0;
>
> +  do {
>
> +    // Unlock the block if we have to
>
> +    Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
>
> +    if (EFI_ERROR (Status)) {
>
> +      break;
>
> +    }
>
> +
>
> +    Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
>
> +    if (EFI_ERROR (Status)) {
>
> +      break;
>
> +    }
>
> +
>
> +    Index++;
>
> +  } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
>
> +
>
> +  if (Index == NOR_FLASH_ERASE_RETRY) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n",
>
> +      BlockAddress,
>
> +      Index
>
> +      ));
>
> +  }
>
> +
>
> +  NorFlashUnlock (&Lock);
>
> +
>
> +  return Status;
>
> +}
>
> +
>
> +/**
>
> +  Write a single word to given location.
>
> +
>
> +  @param[in]    Instance     NOR flash Instance of variable store region.
>
> +  @param[in]    WordAddress  The address in NOR flash to write given word.
>
> +  @param[in]    WriteData    The data to write into NOR flash location.
>
> +
>
> +  @retval       EFI_SUCCESS  The write is completed.
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +NorFlashWriteSingleWord (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN UINTN               WordAddress,
>
> +  IN UINT32              WriteData
>
> +  )
>
> +{
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "NorFlashWriteSingleWord(WordAddress=0x%08x, WriteData=0x%08x)\n",
>
> +    WordAddress,
>
> +    WriteData
>
> +    ));
>
> +
>
> +  if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  MmioWrite32 (WordAddress, WriteData);
>
> +  if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) {
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> +  Write a full block to given location.
>
> +
>
> +  @param[in]    Instance           NOR flash Instance of variable store region.
>
> +  @param[in]    Lba                The logical block address in NOR flash.
>
> +  @param[in]    DataBuffer         The data to write into NOR flash location.
>
> +  @param[in]    BlockSizeInWords   The number of bytes to write.
>
> +
>
> +  @retval       EFI_SUCCESS        The write is completed.
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +NorFlashWriteFullBlock (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN EFI_LBA             Lba,
>
> +  IN UINT32              *DataBuffer,
>
> +  IN UINT32              BlockSizeInWords
>
> +  )
>
> +{
>
> +  EFI_STATUS              Status;
>
> +  UINTN                   WordAddress;
>
> +  UINT32                  WordIndex;
>
> +  UINTN                   BlockAddress;
>
> +  NOR_FLASH_LOCK_CONTEXT  Lock;
>
> +
>
> +  Status = EFI_SUCCESS;
>
> +
>
> +  // Get the physical address of the block
>
> +  BlockAddress = GET_NOR_BLOCK_ADDRESS (
>
> +                   Instance->RegionBaseAddress,
>
> +                   Lba,
>
> +                   BlockSizeInWords * 4
>
> +                   );
>
> +
>
> +  // Start writing from the first address at the start of the block
>
> +  WordAddress = BlockAddress;
>
> +
>
> +  NorFlashLock (&Lock);
>
> +
>
> +  Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
>
> +  if (EFI_ERROR (Status)) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n",
>
> +      BlockAddress
>
> +      ));
>
> +    goto EXIT;
>
> +  }
>
> +
>
> +  for (WordIndex = 0;
>
> +       WordIndex < BlockSizeInWords;
>
> +       WordIndex++, DataBuffer++, WordAddress += 4)
>
> +  {
>
> +    Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
>
> +    if (EFI_ERROR (Status)) {
>
> +      goto EXIT;
>
> +    }
>
> +  }
>
> +
>
> +EXIT:
>
> +  NorFlashUnlock (&Lock);
>
> +
>
> +  if (EFI_ERROR (Status)) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = %r.\n",
>
> +      WordAddress,
>
> +      Status
>
> +      ));
>
> +  }
>
> +
>
> +  return Status;
>
> +}
>
> +
>
> +/**
>
> +  Write a full  block.
>
> +
>
> +  @param[in]    Instance           NOR flash Instance of variable store region.
>
> +  @param[in]    Lba                The starting logical block index.
>
> +  @param[in]    BufferSizeInBytes  The number of bytes to read.
>
> +  @param[in]    Buffer             The pointer to a caller-allocated buffer that
>
> +                                   contains the source for the write.
>
> +
>
> +  @retval       EFI_SUCCESS        The write is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashWriteBlocks (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN EFI_LBA             Lba,
>
> +  IN UINTN               BufferSizeInBytes,
>
> +  IN VOID                *Buffer
>
> +  )
>
> +{
>
> +  UINT32      *pWriteBuffer;
>
> +  EFI_STATUS  Status;
>
> +  EFI_LBA     CurrentBlock;
>
> +  UINT32      BlockSizeInWords;
>
> +  UINT32      NumBlocks;
>
> +  UINT32      BlockCount;
>
> +
>
> +  Status = EFI_SUCCESS;
>
> +  // The buffer must be valid
>
> +  if (Buffer == NULL) {
>
> +    return EFI_INVALID_PARAMETER;
>
> +  }
>
> +
>
> +  // We must have some bytes to read
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n",
>
> +    BufferSizeInBytes
>
> +    ));
>
> +  if (BufferSizeInBytes == 0) {
>
> +    return EFI_BAD_BUFFER_SIZE;
>
> +  }
>
> +
>
> +  // The size of the buffer must be a multiple of the block size
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n",
>
> +    Instance->BlockSize
>
> +    ));
>
> +  if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
>
> +    return EFI_BAD_BUFFER_SIZE;
>
> +  }
>
> +
>
> +  // All blocks must be within the device
>
> +  NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
>
> +
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n",
>
> +    NumBlocks,
>
> +    Instance->LastBlock,
>
> +    Lba
>
> +    ));
>
> +
>
> +  if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"
>
> +      ));
>
> +    return EFI_INVALID_PARAMETER;
>
> +  }
>
> +
>
> +  ASSERT (((UINTN)Buffer % sizeof (UINT32)) == 0);
>
> +
>
> +  BlockSizeInWords = Instance->BlockSize / 4;
>
> +
>
> +  // Because the target *Buffer is a pointer to VOID, we must put
>
> +  // all the data into a pointer to a proper data type, so use *ReadBuffer
>
> +  pWriteBuffer = (UINT32 *)Buffer;
>
> +
>
> +  CurrentBlock = Lba;
>
> +  for (BlockCount = 0;
>
> +       BlockCount < NumBlocks;
>
> +       BlockCount++, CurrentBlock++, pWriteBuffer += BlockSizeInWords)
>
> +  {
>
> +    DEBUG ((
>
> +      DEBUG_INFO,
>
> +      "NorFlashWriteBlocks: Writing block #%d\n",
>
> +      (UINTN)CurrentBlock
>
> +      ));
>
> +
>
> +    Status = NorFlashWriteFullBlock (
>
> +               Instance,
>
> +               CurrentBlock,
>
> +               pWriteBuffer,
>
> +               BlockSizeInWords
>
> +               );
>
> +
>
> +    if (EFI_ERROR (Status)) {
>
> +      break;
>
> +    }
>
> +  }
>
> +
>
> +  DEBUG ((DEBUG_INFO, "NorFlashWriteBlocks: Exit Status = %r.\n", Status));
>
> +  return Status;
>
> +}
>
> +
>
> +/**
>
> +  Read a full  block.
>
> +
>
> +  @param[in]     Instance           NOR flash Instance of variable store region.
>
> +  @param[in]     Lba                The starting logical block index to read from.
>
> +  @param[in]     BufferSizeInBytes  The number of bytes to read.
>
> +  @param[out]    Buffer             The pointer to a caller-allocated buffer that
>
> +                                    should be copied with read data.
>
> +
>
> +  @retval        EFI_SUCCESS        The read is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashReadBlocks (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN EFI_LBA             Lba,
>
> +  IN UINTN               BufferSizeInBytes,
>
> +  OUT VOID               *Buffer
>
> +  )
>
> +{
>
> +  UINT32  NumBlocks;
>
> +  UINTN   StartAddress;
>
> +
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
>
> +    BufferSizeInBytes,
>
> +    Instance->BlockSize,
>
> +    Instance->LastBlock,
>
> +    Lba
>
> +    ));
>
> +
>
> +  // The buffer must be valid
>
> +  if (Buffer == NULL) {
>
> +    return EFI_INVALID_PARAMETER;
>
> +  }
>
> +
>
> +  // Return if we do not have any byte to read
>
> +  if (BufferSizeInBytes == 0) {
>
> +    return EFI_SUCCESS;
>
> +  }
>
> +
>
> +  // The size of the buffer must be a multiple of the block size
>
> +  if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
>
> +    return EFI_BAD_BUFFER_SIZE;
>
> +  }
>
> +
>
> +  NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
>
> +
>
> +  if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "NorFlashReadBlocks: ERROR - Read will exceed last block\n"
>
> +      ));
>
> +    return EFI_INVALID_PARAMETER;
>
> +  }
>
> +
>
> +  // Get the address to start reading from
>
> +  StartAddress = GET_NOR_BLOCK_ADDRESS (
>
> +                   Instance->RegionBaseAddress,
>
> +                   Lba,
>
> +                   Instance->BlockSize
>
> +                   );
>
> +
>
> +  // Readout the data
>
> +  CopyMem (Buffer, (UINTN *)StartAddress, BufferSizeInBytes);
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> +  Read from nor flash.
>
> +
>
> +  @param[in]     Instance           NOR flash Instance of variable store region.
>
> +  @param[in]     Lba                The starting logical block index to read from.
>
> +  @param[in]     Offset             Offset into the block at which to begin reading.
>
> +  @param[in]     BufferSizeInBytes  The number of bytes to read.
>
> +  @param[out]    Buffer             The pointer to a caller-allocated buffer that
>
> +                                    should copied with read data.
>
> +
>
> +  @retval        EFI_SUCCESS        The read is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashRead (
>
> +  IN NOR_FLASH_INSTANCE  *Instance,
>
> +  IN EFI_LBA             Lba,
>
> +  IN UINTN               Offset,
>
> +  IN UINTN               BufferSizeInBytes,
>
> +  OUT VOID               *Buffer
>
> +  )
>
> +{
>
> +  UINTN  StartAddress;
>
> +
>
> +  // The buffer must be valid
>
> +  if (Buffer == NULL) {
>
> +    return EFI_INVALID_PARAMETER;
>
> +  }
>
> +
>
> +  // Return if we do not have any byte to read
>
> +  if (BufferSizeInBytes == 0) {
>
> +    return EFI_SUCCESS;
>
> +  }
>
> +
>
> +  if (((Lba * Instance->BlockSize) + Offset + BufferSizeInBytes) >
>
> +      Instance->Size)
>
> +  {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "NorFlashRead: ERROR - Read will exceed device size.\n"
>
> +      ));
>
> +    return EFI_INVALID_PARAMETER;
>
> +  }
>
> +
>
> +  // Get the address to start reading from
>
> +  StartAddress = GET_NOR_BLOCK_ADDRESS (
>
> +                   Instance->RegionBaseAddress,
>
> +                   Lba,
>
> +                   Instance->BlockSize
>
> +                   );
>
> +
>
> +  // Readout the data
>
> +  CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes);
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> +  Write a full or portion of a block.
>
> +
>
> +  @param[in]         Instance     NOR flash Instance of variable store region.
>
> +  @param[in]         Lba          The starting logical block index to write to.
>
> +  @param[in]         Offset       Offset into the block at which to begin writing.
>
> +  @param[in, out]    NumBytes     The total size of the buffer.
>
> +  @param[in]         Buffer       The pointer to a caller-allocated buffer that
>
> +                                  contains the source for the write.
>
> +
>
> +  @retval            EFI_SUCCESS  The write is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashWriteSingleBlock (
>
> +  IN        NOR_FLASH_INSTANCE  *Instance,
>
> +  IN        EFI_LBA             Lba,
>
> +  IN        UINTN               Offset,
>
> +  IN OUT    UINTN               *NumBytes,
>
> +  IN        UINT8               *Buffer
>
> +  )
>
> +{
>
> +  EFI_STATUS  Status;
>
> +  UINT32      Tmp;
>
> +  UINT32      TmpBuf;
>
> +  UINT32      WordToWrite;
>
> +  UINT32      Mask;
>
> +  BOOLEAN     DoErase;
>
> +  UINTN       BytesToWrite;
>
> +  UINTN       CurOffset;
>
> +  UINTN       WordAddr;
>
> +  UINTN       BlockSize;
>
> +  UINTN       BlockAddress;
>
> +  UINTN       PrevBlockAddress;
>
> +
>
> +  if (Buffer == NULL) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "NorFlashWriteSingleBlock: ERROR - Buffer is invalid\n"
>
> +      ));
>
> +    return EFI_OUT_OF_RESOURCES;
>
> +  }
>
> +
>
> +  PrevBlockAddress = 0;
>
> +  if (!Instance->Initialized && Instance->Initialize) {
>
> +    Instance->Initialize (Instance);
>
> +  }
>
> +
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n",
>
> +    Lba,
>
> +    Offset,
>
> +    *NumBytes,
>
> +    Buffer
>
> +    ));
>
> +
>
> +  // Localise the block size to avoid de-referencing pointers all the time
>
> +  BlockSize = Instance->BlockSize;
>
> +
>
> +  // The write must not span block boundaries.
>
> +  // We need to check each variable individually because adding two large
>
> +  // values together overflows.
>
> +  if ((Offset               >= BlockSize) ||
>
> +      (*NumBytes            >  BlockSize) ||
>
> +      ((Offset + *NumBytes) >  BlockSize))
>
> +  {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
>
> +      Offset,
>
> +      *NumBytes,
>
> +      BlockSize
>
> +      ));
>
> +    return EFI_BAD_BUFFER_SIZE;
>
> +  }
>
> +
>
> +  // We must have some bytes to write
>
> +  if (*NumBytes == 0) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
>
> +      Offset,
>
> +      *NumBytes,
>
> +      BlockSize
>
> +      ));
>
> +    return EFI_BAD_BUFFER_SIZE;
>
> +  }
>
> +
>
> +  // Pick 128bytes as a good start for word operations as opposed to erasing the
>
> +  // block and writing the data regardless if an erase is really needed.
>
> +  // It looks like most individual NV variable writes are smaller than 128bytes.
>
> +  if (*NumBytes <= 128) {
>
> +    // Check to see if we need to erase before programming the data into NOR.
>
> +    // If the destination bits are only changing from 1s to 0s we can just write.
>
> +    // After a block is erased all bits in the block is set to 1.
>
> +    // If any byte requires us to erase we just give up and rewrite all of it.
>
> +    DoErase      = FALSE;
>
> +    BytesToWrite = *NumBytes;
>
> +    CurOffset    = Offset;
>
> +
>
> +    while (BytesToWrite > 0) {
>
> +      // Read full word from NOR, splice as required. A word is the smallest
>
> +      // unit we can write.
>
> +      Status = NorFlashRead (
>
> +                 Instance,
>
> +                 Lba,
>
> +                 CurOffset & ~(0x3),
>
> +                 sizeof (Tmp),
>
> +                 &Tmp
>
> +                 );
>
> +      if (EFI_ERROR (Status)) {
>
> +        return EFI_DEVICE_ERROR;
>
> +      }
>
> +
>
> +      // Physical address of word in NOR to write.
>
> +      WordAddr = (CurOffset & ~(0x3)) +
>
> +                 GET_NOR_BLOCK_ADDRESS (
>
> +                   Instance->RegionBaseAddress,
>
> +                   Lba,
>
> +                   BlockSize
>
> +                   );
>
> +
>
> +      // The word of data that is to be written.
>
> +      TmpBuf = ReadUnaligned32 ((UINT32 *)(Buffer + (*NumBytes - BytesToWrite)));
>
> +
>
> +      // First do word aligned chunks.
>
> +      if ((CurOffset & 0x3) == 0) {
>
> +        if (BytesToWrite >= 4) {
>
> +          // Is the destination still in 'erased' state?
>
> +          if (~Tmp != 0) {
>
> +            // Check to see if we are only changing bits to zero.
>
> +            if ((Tmp ^ TmpBuf) & TmpBuf) {
>
> +              DoErase = TRUE;
>
> +              break;
>
> +            }
>
> +          }
>
> +
>
> +          // Write this word to NOR
>
> +          WordToWrite   = TmpBuf;
>
> +          CurOffset    += sizeof (TmpBuf);
>
> +          BytesToWrite -= sizeof (TmpBuf);
>
> +        } else {
>
> +          // BytesToWrite < 4. Do small writes and left-overs
>
> +          Mask = ~((~0) << (BytesToWrite * 8));
>
> +          // Mask out the bytes we want.
>
> +          TmpBuf &= Mask;
>
> +          // Is the destination still in 'erased' state?
>
> +          if ((Tmp & Mask) != Mask) {
>
> +            // Check to see if we are only changing bits to zero.
>
> +            if ((Tmp ^ TmpBuf) & TmpBuf) {
>
> +              DoErase = TRUE;
>
> +              break;
>
> +            }
>
> +          }
>
> +
>
> +          // Merge old and new data. Write merged word to NOR
>
> +          WordToWrite  = (Tmp & ~Mask) | TmpBuf;
>
> +          CurOffset   += BytesToWrite;
>
> +          BytesToWrite = 0;
>
> +        }
>
> +      } else {
>
> +        // Do multiple words, but starting unaligned.
>
> +        if (BytesToWrite > (4 - (CurOffset & 0x3))) {
>
> +          Mask = ((~0) << ((CurOffset & 0x3) * 8));
>
> +          // Mask out the bytes we want.
>
> +          TmpBuf &= Mask;
>
> +          // Is the destination still in 'erased' state?
>
> +          if ((Tmp & Mask) != Mask) {
>
> +            // Check to see if we are only changing bits to zero.
>
> +            if ((Tmp ^ TmpBuf) & TmpBuf) {
>
> +              DoErase = TRUE;
>
> +              break;
>
> +            }
>
> +          }
>
> +
>
> +          // Merge old and new data. Write merged word to NOR
>
> +          WordToWrite   = (Tmp & ~Mask) | TmpBuf;
>
> +          BytesToWrite -= (4 - (CurOffset & 0x3));
>
> +          CurOffset    += (4 - (CurOffset & 0x3));
>
> +        } else {
>
> +          // Unaligned and fits in one word.
>
> +          Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8);
>
> +          // Mask out the bytes we want.
>
> +          TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;
>
> +          // Is the destination still in 'erased' state?
>
> +          if ((Tmp & Mask) != Mask) {
>
> +            // Check to see if we are only changing bits to zero.
>
> +            if ((Tmp ^ TmpBuf) & TmpBuf) {
>
> +              DoErase = TRUE;
>
> +              break;
>
> +            }
>
> +          }
>
> +
>
> +          // Merge old and new data. Write merged word to NOR
>
> +          WordToWrite  = (Tmp & ~Mask) | TmpBuf;
>
> +          CurOffset   += BytesToWrite;
>
> +          BytesToWrite = 0;
>
> +        }
>
> +      }
>
> +
>
> +      BlockAddress = GET_NOR_BLOCK_ADDRESS (
>
> +                       Instance->RegionBaseAddress,
>
> +                       Lba,
>
> +                       BlockSize
>
> +                       );
>
> +      if (BlockAddress != PrevBlockAddress) {
>
> +        Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
>
> +        if (EFI_ERROR (Status)) {
>
> +          return EFI_DEVICE_ERROR;
>
> +        }
>
> +
>
> +        PrevBlockAddress = BlockAddress;
>
> +      }
>
> +
>
> +      Status = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite);
>
> +      if (EFI_ERROR (Status)) {
>
> +        return EFI_DEVICE_ERROR;
>
> +      }
>
> +    }
>
> +
>
> +    // Exit if we got here and could write all the data. Otherwise do the
>
> +    // Erase-Write cycle.
>
> +    if (!DoErase) {
>
> +      return EFI_SUCCESS;
>
> +    }
>
> +  }
>
> +
>
> +  // Check we did get some memory. Buffer is BlockSize.
>
> +  if (Instance->ShadowBuffer == NULL) {
>
> +    DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  // Read NOR Flash data into shadow buffer
>
> +  Status = NorFlashReadBlocks (
>
> +             Instance,
>
> +             Lba,
>
> +             BlockSize,
>
> +             Instance->ShadowBuffer
>
> +             );
>
> +  if (EFI_ERROR (Status)) {
>
> +    // Return one of the pre-approved error statuses
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  // Put the data at the appropriate location inside the buffer area
>
> +  CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
>
> +
>
> +  // Write the modified buffer back to the NorFlash
>
> +  Status = NorFlashWriteBlocks (
>
> +             Instance,
>
> +             Lba,
>
> +             BlockSize,
>
> +             Instance->ShadowBuffer
>
> +             );
>
> +  if (EFI_ERROR (Status)) {
>
> +    // Return one of the pre-approved error statuses
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> +  Read JEDEC ID of NOR flash device.
>
> +
>
> +  @param[in]     Instance     NOR flash Instance of variable store region.
>
> +  @param[out]    JedecId      JEDEC ID of NOR flash device.
>
> +
>
> +  @retval        EFI_SUCCESS  The write is completed.
>
> +**/
>
> +EFI_STATUS
>
> +NorFlashReadID (
>
> +  IN  NOR_FLASH_INSTANCE  *Instance,
>
> +  OUT UINT8               JedecId[3]
>
> +  )
>
> +{
>
> +  UINT32  val;
>
> +
>
> +  if ((Instance == NULL) || (JedecId == NULL)) {
>
> +    return EFI_INVALID_PARAMETER;
>
> +  }
>
> +
>
> +  val = SPINOR_OP_RDID << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
>
> +        CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS |
>
> +        CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES (3);
>
> +
>
> +  if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  val = MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET);
>
> +
>
> +  // Manu.ID field
>
> +  JedecId[0] = (UINT8)val;
>
> +  // Type field
>
> +  JedecId[1] = (UINT8)(val >> 8);
>
> +  // Capacity field
>
> +  JedecId[2] = (UINT8)(val >> 16);
>
> +
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "Nor flash detected, Jedec ID, Manu.Id=%x Type=%x Capacity=%x \n",
>
> +    JedecId[0],
>
> +    JedecId[1],
>
> +    JedecId[2]
>
> +    ));
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c
> new file mode 100644
> index 000000000000..8281d4825dc9
> --- /dev/null
> +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c
> @@ -0,0 +1,647 @@
> +/** @file
>
> +
>
> +  Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
>
> +
>
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +
>
> +**/
>
> +
>
> +#include <Guid/VariableFormat.h>
>
> +#include <Guid/SystemNvDataGuid.h>
>
> +
>
> +#include <Library/BaseLib.h>
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Library/MemoryAllocationLib.h>
>
> +#include <Library/PcdLib.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/UefiLib.h>
>
> +
>
> +#include <PiDxe.h>
>
> +
>
> +#include "NorFlash.h"
>
> +
>
> +UINTN  mFlashNvStorageVariableBase;
>
> +
>
> +/**
>
> +  Initialize the FV Header and Variable Store Header
>
> +  to support variable operations.
>
> +
>
> +  @param[in]  Instance      Location to initialise the headers.
>
> +
>
> +  @retval     EFI_SUCCESS   Fv init is done.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +InitializeFvAndVariableStoreHeaders (
>
> +  IN NOR_FLASH_INSTANCE  *Instance
>
> +  )
>
> +{
>
> +  EFI_STATUS                  Status;
>
> +  VOID                        *Headers;
>
> +  UINTN                       HeadersLength;
>
> +  EFI_FIRMWARE_VOLUME_HEADER  *FirmwareVolumeHeader;
>
> +  VARIABLE_STORE_HEADER       *VariableStoreHeader;
>
> +
>
> +  if (!Instance->Initialized && Instance->Initialize) {
>
> +    Instance->Initialize (Instance);
>
> +  }
>
> +
>
> +  HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
>
> +                  sizeof (EFI_FV_BLOCK_MAP_ENTRY) +
>
> +                  sizeof (VARIABLE_STORE_HEADER);
>
> +  Headers = AllocateZeroPool (HeadersLength);
>
> +
>
> +  FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Headers;
>
> +  CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
>
> +  FirmwareVolumeHeader->FvLength =
>
> +    PcdGet32 (PcdFlashNvStorageVariableSize) +
>
> +    PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
>
> +    PcdGet32 (PcdFlashNvStorageFtwSpareSize);
>
> +  FirmwareVolumeHeader->Signature  = EFI_FVH_SIGNATURE;
>
> +  FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP |
>
> +                                     EFI_FVB2_READ_STATUS |
>
> +                                     EFI_FVB2_STICKY_WRITE |
>
> +                                     EFI_FVB2_MEMORY_MAPPED |
>
> +                                     EFI_FVB2_ERASE_POLARITY |
>
> +                                     EFI_FVB2_WRITE_STATUS |
>
> +                                     EFI_FVB2_WRITE_ENABLED_CAP;
>
> +
>
> +  FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
>
> +                                       sizeof (EFI_FV_BLOCK_MAP_ENTRY);
>
> +  FirmwareVolumeHeader->Revision              = EFI_FVH_REVISION;
>
> +  FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->LastBlock + 1;
>
> +  FirmwareVolumeHeader->BlockMap[0].Length    = Instance->BlockSize;
>
> +  FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
>
> +  FirmwareVolumeHeader->BlockMap[1].Length    = 0;
>
> +  FirmwareVolumeHeader->Checksum              = CalculateCheckSum16 (
>
> +                                                  (UINT16 *)FirmwareVolumeHeader,
>
> +                                                  FirmwareVolumeHeader->HeaderLength
>
> +                                                  );
>
> +
>
> +  VariableStoreHeader = (VOID *)((UINTN)Headers +
>
> +                                 FirmwareVolumeHeader->HeaderLength);
>
> +  CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
>
> +  VariableStoreHeader->Size = PcdGet32 (PcdFlashNvStorageVariableSize) -
>
> +                              FirmwareVolumeHeader->HeaderLength;
>
> +  VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
>
> +  VariableStoreHeader->State  = VARIABLE_STORE_HEALTHY;
>
> +
>
> +  // Install the combined super-header in the NorFlash
>
> +  Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
>
> +
>
> +  FreePool (Headers);
>
> +  return Status;
>
> +}
>
> +
>
> +/**
>
> +  Check the integrity of firmware volume header.
>
> +
>
> +  @param[in]  Instance        Instance of Nor flash variable region.
>
> +
>
> +  @retval     EFI_SUCCESS     The firmware volume is consistent.
>
> +  @retval     EFI_NOT_FOUND   The firmware volume has been corrupted.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +ValidateFvHeader (
>
> +  IN  NOR_FLASH_INSTANCE  *Instance
>
> +  )
>
> +{
>
> +  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;
>
> +  VARIABLE_STORE_HEADER       *VariableStoreHeader;
>
> +  UINTN                       VariableStoreLength;
>
> +  UINTN                       FvLength;
>
> +
>
> +  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Instance->RegionBaseAddress;
>
> +
>
> +  FvLength = PcdGet32 (PcdFlashNvStorageVariableSize) +
>
> +             PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
>
> +             PcdGet32 (PcdFlashNvStorageFtwSpareSize);
>
> +
>
> +  if (  (FwVolHeader->Revision  != EFI_FVH_REVISION)
>
> +     || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)
>
> +     || (FwVolHeader->FvLength  != FvLength)
>
> +        )
>
> +  {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "%a: No Firmware Volume header present\n",
>
> +      __func__
>
> +      ));
>
> +    return EFI_NOT_FOUND;
>
> +  }
>
> +
>
> +  // Check the Firmware Volume Guid
>
> +  if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "%a: Firmware Volume Guid non-compatible\n",
>
> +      __func__
>
> +      ));
>
> +    return EFI_NOT_FOUND;
>
> +  }
>
> +
>
> +  VariableStoreHeader = (VOID *)((UINTN)FwVolHeader +
>
> +                                 FwVolHeader->HeaderLength);
>
> +
>
> +  // Check the Variable Store Guid
>
> +  if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
>
> +      !CompareGuid (
>
> +         &VariableStoreHeader->Signature,
>
> +         &gEfiAuthenticatedVariableGuid
>
> +         ))
>
> +  {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "%a: Variable Store Guid non-compatible\n",
>
> +      __func__
>
> +      ));
>
> +    return EFI_NOT_FOUND;
>
> +  }
>
> +
>
> +  VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) -
>
> +                        FwVolHeader->HeaderLength;
>
> +  if (VariableStoreHeader->Size != VariableStoreLength) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "%a: Variable Store Length does not match\n",
>
> +      __func__
>
> +      ));
>
> +    return EFI_NOT_FOUND;
>
> +  }
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Retrieves the attributes and current settings of the block.
>
> +
>
> + @param[in]   This         Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[out]  Attributes   Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
>
> +                           current settings are returned.
>
> +                           Type EFI_FVB_ATTRIBUTES_2 is defined in
>
> +                           EFI_FIRMWARE_VOLUME_HEADER.
>
> +
>
> + @retval      EFI_SUCCESS  The firmware volume attributes were returned.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbGetAttributes (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes
>
> +  )
>
> +{
>
> +  EFI_FVB_ATTRIBUTES_2  FlashFvbAttributes;
>
> +
>
> +  FlashFvbAttributes = EFI_FVB2_READ_ENABLED_CAP | EFI_FVB2_READ_STATUS |
>
> +                       EFI_FVB2_WRITE_ENABLED_CAP | EFI_FVB2_WRITE_STATUS |
>
> +                       EFI_FVB2_STICKY_WRITE | EFI_FVB2_MEMORY_MAPPED |
>
> +                       EFI_FVB2_ERASE_POLARITY;
>
> +
>
> +  *Attributes = FlashFvbAttributes;
>
> +
>
> +  DEBUG ((DEBUG_INFO, "FvbGetAttributes(0x%X)\n", *Attributes));
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Sets configurable firmware volume attributes and returns the
>
> + new settings of the firmware volume.
>
> +
>
> +
>
> + @param[in]         This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[in, out]    Attributes               On input, Attributes is a pointer to
>
> +                                             EFI_FVB_ATTRIBUTES_2 that contains the desired
>
> +                                             firmware volume settings.
>
> +                                             On successful return, it contains the new
>
> +                                             settings of the firmware volume.
>
> +
>
> + @retval            EFI_UNSUPPORTED          The firmware volume attributes are not supported.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbSetAttributes (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
>
> +  )
>
> +{
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "FvbSetAttributes(0x%X) is not supported\n",
>
> +    *Attributes
>
> +    ));
>
> +  return EFI_UNSUPPORTED;
>
> +}
>
> +
>
> +/**
>
> + Retrieves the base address of a memory-mapped firmware volume.
>
> + This function should be called only for memory-mapped firmware volumes.
>
> +
>
> + @param[in]     This               EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[out]    Address            Pointer to a caller-allocated
>
> +                                   EFI_PHYSICAL_ADDRESS that, on successful
>
> +                                   return from GetPhysicalAddress(), contains the
>
> +                                   base address of the firmware volume.
>
> +
>
> + @retval        EFI_SUCCESS        The firmware volume base address was returned.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbGetPhysicalAddress (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  OUT       EFI_PHYSICAL_ADDRESS                 *Address
>
> +  )
>
> +{
>
> +  NOR_FLASH_INSTANCE  *Instance;
>
> +
>
> +  Instance = INSTANCE_FROM_FVB_THIS (This);
>
> +
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "FvbGetPhysicalAddress(BaseAddress=0x%08x)\n",
>
> +    Instance->RegionBaseAddress
>
> +    ));
>
> +
>
> +  ASSERT (Address != NULL);
>
> +
>
> +  *Address = Instance->RegionBaseAddress;
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Retrieves the size of the requested block.
>
> + It also returns the number of additional blocks with the identical size.
>
> + The GetBlockSize() function is used to retrieve the block map
>
> + (see EFI_FIRMWARE_VOLUME_HEADER).
>
> +
>
> +
>
> + @param[in]     This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[in]     Lba                      Indicates the block whose size to return
>
> +
>
> + @param[out]    BlockSize                Pointer to a caller-allocated UINTN in which
>
> +                                         the size of the block is returned.
>
> +
>
> + @param[out]    NumberOfBlocks           Pointer to a caller-allocated UINTN in
>
> +                                         which the number of consecutive blocks,
>
> +                                         starting with Lba, is returned. All
>
> +                                         blocks in this range have a size of
>
> +                                         BlockSize.
>
> +
>
> + @retval        EFI_SUCCESS              The firmware volume base address was returned.
>
> +
>
> + @retval        EFI_INVALID_PARAMETER    The requested LBA is out of range.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbGetBlockSize (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  IN        EFI_LBA                              Lba,
>
> +  OUT       UINTN                                *BlockSize,
>
> +  OUT       UINTN                                *NumberOfBlocks
>
> +  )
>
> +{
>
> +  EFI_STATUS          Status;
>
> +  NOR_FLASH_INSTANCE  *Instance;
>
> +
>
> +  Instance = INSTANCE_FROM_FVB_THIS (This);
>
> +
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n",
>
> +    Lba,
>
> +    Instance->BlockSize,
>
> +    Instance->LastBlock
>
> +    ));
>
> +
>
> +  if (Lba > Instance->LastBlock) {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (%ld).\n",
>
> +      Lba,
>
> +      Instance->LastBlock
>
> +      ));
>
> +    Status = EFI_INVALID_PARAMETER;
>
> +  } else {
>
> +    // This is easy because in this platform each NorFlash device has equal sized blocks.
>
> +    *BlockSize      = (UINTN)Instance->BlockSize;
>
> +    *NumberOfBlocks = (UINTN)(Instance->LastBlock - Lba + 1);
>
> +
>
> +    DEBUG ((
>
> +      DEBUG_INFO,
>
> +      "FvbGetBlockSize: *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n",
>
> +      *BlockSize,
>
> +      *NumberOfBlocks
>
> +      ));
>
> +
>
> +    Status = EFI_SUCCESS;
>
> +  }
>
> +
>
> +  return Status;
>
> +}
>
> +
>
> +/**
>
> + Reads the specified number of bytes into a buffer from the specified block.
>
> +
>
> + The Read() function reads the requested number of bytes from the
>
> + requested block and stores them in the provided buffer.
>
> +
>
> + @param[in]       This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[in]       Lba                  The starting logical block index from which to read
>
> +
>
> + @param[in]       Offset               Offset into the block at which to begin reading.
>
> +
>
> + @param[in, out]  NumBytes             Pointer to a UINTN.
>
> +                                       At entry, *NumBytes contains the total size of the
>
> +                                       buffer. *NumBytes should have a non zero value.
>
> +                                       At exit, *NumBytes contains the total number of
>
> +                                       bytes read.
>
> +
>
> + @param[in, out]  Buffer               Pointer to a caller-allocated buffer that will be
>
> +                                       used to hold the data that is read.
>
> +
>
> + @retval          EFI_SUCCESS          The firmware volume was read successfully, and
>
> +                                       contents are in Buffer.
>
> +
>
> + @retval          EFI_BAD_BUFFER_SIZE  Read attempted across an LBA boundary.
>
> +
>
> + @retval          EFI_DEVICE_ERROR     The block device is not functioning correctly and
>
> +                                       could not be read.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbRead (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  IN        EFI_LBA                              Lba,
>
> +  IN        UINTN                                Offset,
>
> +  IN OUT    UINTN                                *NumBytes,
>
> +  IN OUT    UINT8                                *Buffer
>
> +  )
>
> +{
>
> +  EFI_STATUS          Status;
>
> +  UINTN               BlockSize;
>
> +  NOR_FLASH_INSTANCE  *Instance;
>
> +
>
> +  Instance = INSTANCE_FROM_FVB_THIS (This);
>
> +
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n",
>
> +    Instance->StartLba + Lba,
>
> +    Offset,
>
> +    *NumBytes,
>
> +    Buffer
>
> +    ));
>
> +
>
> +  if (!Instance->Initialized && Instance->Initialize) {
>
> +    Instance->Initialize (Instance);
>
> +  }
>
> +
>
> +  BlockSize = Instance->BlockSize;
>
> +
>
> +  DEBUG ((
>
> +    DEBUG_INFO,
>
> +    "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n",
>
> +    Offset,
>
> +    *NumBytes,
>
> +    BlockSize
>
> +    ));
>
> +
>
> +  // The read must not span block boundaries.
>
> +  // We need to check each variable individually because adding two large
>
> +  // values together overflows.
>
> +  if ((Offset               >= BlockSize) ||
>
> +      (*NumBytes            >  BlockSize) ||
>
> +      ((Offset + *NumBytes) >  BlockSize))
>
> +  {
>
> +    DEBUG ((
>
> +      DEBUG_ERROR,
>
> +      "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
>
> +      Offset,
>
> +      *NumBytes,
>
> +      BlockSize
>
> +      ));
>
> +    return EFI_BAD_BUFFER_SIZE;
>
> +  }
>
> +
>
> +  // We must have some bytes to read
>
> +  if (*NumBytes == 0) {
>
> +    return EFI_BAD_BUFFER_SIZE;
>
> +  }
>
> +
>
> +  // Decide if we are doing full block reads or not.
>
> +  if (*NumBytes % BlockSize != 0) {
>
> +    Status = NorFlashRead (
>
> +               Instance,
>
> +               Instance->StartLba + Lba,
>
> +               Offset,
>
> +               *NumBytes,
>
> +               Buffer
>
> +               );
>
> +  } else {
>
> +    // Read NOR Flash data into shadow buffer
>
> +    Status = NorFlashReadBlocks (
>
> +               Instance,
>
> +               Instance->StartLba + Lba,
>
> +               BlockSize,
>
> +               Buffer
>
> +               );
>
> +  }
>
> +
>
> +  if (EFI_ERROR (Status)) {
>
> +    // Return one of the pre-approved error statuses
>
> +    return EFI_DEVICE_ERROR;
>
> +  }
>
> +
>
> +  return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Writes the specified number of bytes from the input buffer to the block.
>
> +
>
> + @param[in]        This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>
> +
>
> + @param[in]        Lba                  The starting logical block index to write to.
>
> +
>
> + @param[in]        Offset               Offset into the block at which to begin writing.
>
> +
>
> + @param[in, out]   NumBytes             The pointer to a UINTN.
>
> +                                        At entry, *NumBytes contains the total size of the
>
> +                                        buffer.
>
> +                                        At exit, *NumBytes contains the total number of
>
> +                                        bytes actually written.
>
> +
>
> + @param[in]        Buffer               The pointer to a caller-allocated buffer that
>
> +                                        contains the source for the write.
>
> +
>
> + @retval           EFI_SUCCESS          The firmware volume was written successfully.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbWrite (
>
> +  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  IN        EFI_LBA                              Lba,
>
> +  IN        UINTN                                Offset,
>
> +  IN OUT    UINTN                                *NumBytes,
>
> +  IN        UINT8                                *Buffer
>
> +  )
>
> +{
>
> +  NOR_FLASH_INSTANCE  *Instance;
>
> +
>
> +  Instance = INSTANCE_FROM_FVB_THIS (This);
>
> +
>
> +  return NorFlashWriteSingleBlock (
>
> +           Instance,
>
> +           Instance->StartLba + Lba,
>
> +           Offset,
>
> +           NumBytes,
>
> +           Buffer
>
> +           );
>
> +}
>
> +
>
> +/**
>
> + Erases and initialises a firmware volume block.
>
> +
>
> + @param[in]   This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
>
> +
>
> + @param[in]   ...                      The variable argument list is a list of tuples.
>
> +                                       Each tuple describes a range of LBAs to erase
>
> +                                       and consists of the following:
>
> +                                       - An EFI_LBA that indicates the starting LBA
>
> +                                       - A UINTN that indicates the number of blocks
>
> +                                       to erase.
>
> +
>
> +                                       The list is terminated with an
>
> +                                       EFI_LBA_LIST_TERMINATOR.
>
> +
>
> + @retval      EFI_SUCCESS              The erase request successfully completed.
>
> +
>
> + @retval      EFI_ACCESS_DENIED        The firmware volume is in the WriteDisabled
>
> +                                       state.
>
> +
>
> + @retval      EFI_DEVICE_ERROR         The block device is not functioning correctly
>
> +                                       and could not be written.
>
> +                                       The firmware device may have been partially
>
> +                                       erased.
>
> +
>
> + @retval      EFI_INVALID_PARAMETER   One or more of the LBAs listed in the variable
>
> +                                      argument list do not exist in the firmware
>
> +                                      volume.
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FvbEraseBlocks (
>
> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
>
> +  ...
>
> +  )
>
> +{
>
> +  EFI_STATUS          Status;
>
> +  VA_LIST             Args;
>
> +  UINTN               BlockAddress; // Physical address of Lba to erase
>
> +  EFI_LBA             StartingLba;  // Lba from which we start erasing
>
> +  UINTN               NumOfLba;     // Number of Lba blocks to erase
>
> +  NOR_FLASH_INSTANCE  *Instance;
>
> +
>
> +  Instance = INSTANCE_FROM_FVB_THIS (This);
>
> +
>
> +  DEBUG ((DEBUG_INFO, "FvbEraseBlocks()\n"));
>
> +
>
> +  Status = EFI_SUCCESS;
>
> +
>
> +  // Before erasing, check the entire list of parameters to ensure
>
> +  // all specified blocks are valid
>
> +
>
> +  VA_START (Args, This);
>
> +  do {
>
> +    // Get the Lba from which we start erasing
>
> +    StartingLba = VA_ARG (Args, EFI_LBA);
>
> +
>
> +    // Have we reached the end of the list?
>
> +    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
>
> +      break;
>
> +    }
>
> +
>
> +    // How many Lba blocks are we requested to erase?
>
> +    NumOfLba = VA_ARG (Args, UINT32);
>
> +
>
> +    // All blocks must be within range
>
> +    DEBUG ((
>
> +      DEBUG_INFO,
>
> +      "FvbEraseBlocks: Check if: ( StartingLba=%ld + NumOfLba=%d - 1 ) > LastBlock=%ld.\n",
>
> +      Instance->StartLba + StartingLba,
>
> +      NumOfLba,
>
> +      Instance->LastBlock
>
> +      ));
>
> +    if ((NumOfLba == 0) ||
>
> +        ((Instance->StartLba + StartingLba + NumOfLba - 1) >
>
> +         Instance->LastBlock))
>
> +    {
>
> +      VA_END (Args);
>
> +      DEBUG ((
>
> +        DEBUG_ERROR,
>
> +        "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"
>
> +        ));
>
> +      return EFI_INVALID_PARAMETER;
>
> +    }
>
> +  } while (TRUE);
>
> +
>
> +  VA_END (Args);
>
> +
>
> +  VA_START (Args, This);
>
> +  do {
>
> +    // Get the Lba from which we start erasing
>
> +    StartingLba = VA_ARG (Args, EFI_LBA);
>
> +
>
> +    // Have we reached the end of the list?
>
> +    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
>
> +      // Exit the while loop
>
> +      break;
>
> +    }
>
> +
>
> +    // How many Lba blocks are we requested to erase?
>
> +    NumOfLba = VA_ARG (Args, UINT32);
>
> +
>
> +    // Go through each one and erase it
>
> +    while (NumOfLba > 0) {
>
> +      // Get the physical address of Lba to erase
>
> +      BlockAddress = GET_NOR_BLOCK_ADDRESS (
>
> +                       Instance->RegionBaseAddress,
>
> +                       Instance->StartLba + StartingLba,
>
> +                       Instance->BlockSize
>
> +                       );
>
> +
>
> +      // Erase it
>
> +      DEBUG ((
>
> +        DEBUG_INFO,
>
> +        "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n",
>
> +        Instance->StartLba + StartingLba,
>
> +        BlockAddress
>
> +        ));
>
> +      Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
>
> +      if (EFI_ERROR (Status)) {
>
> +        VA_END (Args);
>
> +        return EFI_DEVICE_ERROR;
>
> +      }
>
> +
>
> +      // Move to the next Lba
>
> +      StartingLba++;
>
> +      NumOfLba--;
>
> +    }
>
> +  } while (TRUE);
>
> +
>
> +  VA_END (Args);
>
> +
>
> +  return Status;
>
> +}
>


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



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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 4/5] Platform/ARM/N1Sdp: Persistent storage for N1Sdp
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 4/5] Platform/ARM/N1Sdp: Persistent storage " sahil
  2023-12-07 14:48   ` Thomas Abraham
@ 2023-12-18 15:13   ` Sami Mujawar
  1 sibling, 0 replies; 17+ messages in thread
From: Sami Mujawar @ 2023-12-18 15:13 UTC (permalink / raw)
  To: sahil, devel; +Cc: Ard Biesheuvel, Leif Lindholm, nd@arm.com

Hi Sahil,

Please see my response for Patch 3/5.

Regards,

Sami Mujawar

On 16/11/2023 11:45 am, sahil wrote:
> Enable persistent storage on QSPI flash device.
>
> Signed-off-by: sahil <sahil@arm.com>
> ---
>   Platform/ARM/N1Sdp/N1SdpPlatform.dsc | 20 ++++++++++++++------
>   Platform/ARM/N1Sdp/N1SdpPlatform.fdf |  4 +++-
>   2 files changed, 17 insertions(+), 7 deletions(-)
>
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> index d04b22d3ef51..10fe2db9e1b1 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> @@ -4,7 +4,7 @@
>   # This provides platform specific component descriptions and libraries that
>
>   # conform to EFI/Framework standards.
>
>   #
>
> -# Copyright (c) 2018 - 2021, ARM Limited. All rights reserved.<BR>
>
> +# Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.<BR>
>
>   #
>
>   # SPDX-License-Identifier: BSD-2-Clause-Patent
>
>   #
>
> @@ -44,6 +44,9 @@
>     # file explorer library support
>
>     FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
>
>   
>
> +  # NOR flash support
>
> +  NorFlashInfoLib|EmbeddedPkg/Library/NorFlashInfoLib/NorFlashInfoLib.inf
>
> +
>
>   [LibraryClasses.common.SEC]
>
>     HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
>
>     MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
>
> @@ -161,11 +164,9 @@
>     # ACPI Table Version
>
>     gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions|0x20
>
>   
>
> -  # Runtime Variable storage
>
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved|0
>
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
>
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000
>
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800
>
> +  # NOR flash support
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x18F00000
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x00020000
>
>   
>
>   ################################################################################
>
>   #
>
> @@ -197,6 +198,12 @@
>         gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8000000F
>
>     }
>
>   
>
> +  # NOR flash support
>
> +  Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf {
>
> +      <LibraryClasses>
>
> +      NorFlashPlatformLib|Silicon/ARM/NeoverseN1Soc/Library/NorFlashLib/NorFlashLib.inf
>
> +  }
>
> +
>
>     # Architectural Protocols
>
>     ArmPkg/Drivers/CpuDxe/CpuDxe.inf
>
>     ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
>
> @@ -217,6 +224,7 @@
>     MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
>
>       <LibraryClasses>
>
>         NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf
>
> +      NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf
>
>         BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
>
>     }
>
>   
>
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> index e5e24ea50294..4329f892f7c5 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> @@ -1,7 +1,7 @@
>   ## @file
>
>   #  FDF file of N1Sdp
>
>   #
>
> -#  Copyright (c) 2018 - 2021, ARM Limited. All rights reserved.<BR>
>
> +#  Copyright (c) 2018 - 2023, ARM Limited. All rights reserved.<BR>
>
>   #
>
>   #  SPDX-License-Identifier: BSD-2-Clause-Patent
>
>   ##
>
> @@ -140,6 +140,8 @@ READ_LOCK_STATUS   = TRUE
>     INF ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf
>
>     INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
>
>   
>
> +  INF Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
>
> +
>
>     INF Platform/ARM/Drivers/BootMonFs/BootMonFs.inf
>
>     INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
>
>   
>


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



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

* Re: [edk2-devel] [edk2-platforms][PATCH V1 5/5] Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver for N1Sdp
  2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 5/5] Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver " sahil
  2023-12-07 14:51   ` Thomas Abraham
@ 2023-12-18 15:16   ` Sami Mujawar
  1 sibling, 0 replies; 17+ messages in thread
From: Sami Mujawar @ 2023-12-18 15:16 UTC (permalink / raw)
  To: sahil, devel; +Cc: Ard Biesheuvel, Leif Lindholm, nd@arm.com

Hi Sahil,

As such these changes look good to me. But, we would need to revisit 
this based on my response for Patch 3/5.

Regards,

Sami Mujawar

On 16/11/2023 11:45 am, sahil wrote:
> Signed-off-by: sahil <sahil@arm.com>
> ---
>   Platform/ARM/N1Sdp/N1SdpPlatform.dsc | 5 +++++
>   Platform/ARM/N1Sdp/N1SdpPlatform.fdf | 1 +
>   2 files changed, 6 insertions(+)
>
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> index 10fe2db9e1b1..703829bbac99 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dsc
> @@ -165,6 +165,10 @@
>     gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiExposedTableVersions|0x20
>
>   
>
>     # NOR flash support
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0x18F40000
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize|0x00020000
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0x18F20000
>
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0x00020000
>
>     gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x18F00000
>
>     gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize|0x00020000
>
>   
>
> @@ -227,6 +231,7 @@
>         NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf
>
>         BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
>
>     }
>
> +  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>
>   
>
>     # ACPI Support
>
>     MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf
>
> diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> index 4329f892f7c5..17d370a371cf 100644
> --- a/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.fdf
> @@ -90,6 +90,7 @@ READ_LOCK_STATUS   = TRUE
>     INF MdeModulePkg/Universal/Metronome/Metronome.inf
>
>     INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf
>
>     INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf
>
> +  INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>
>     INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf
>
>     INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf
>
>     INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
>


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



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

end of thread, other threads:[~2023-12-18 15:16 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-11-16 11:45 [edk2-devel] [edk2-platforms][PATCH V1 0/5] Enable non volatile storage on N1SDP sahil
2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 1/5] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region sahil
2023-12-07 10:59   ` Thomas Abraham
2023-12-18 15:12   ` Sami Mujawar
2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 2/5] Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp sahil
2023-12-07 12:01   ` Thomas Abraham
2023-12-18 15:12   ` Sami Mujawar
2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver " sahil
2023-12-07 14:46   ` Thomas Abraham
2023-12-12 12:08   ` levi.yun
2023-12-18 15:12   ` Sami Mujawar
2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 4/5] Platform/ARM/N1Sdp: Persistent storage " sahil
2023-12-07 14:48   ` Thomas Abraham
2023-12-18 15:13   ` Sami Mujawar
2023-11-16 11:45 ` [edk2-devel] [edk2-platforms][PATCH V1 5/5] Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver " sahil
2023-12-07 14:51   ` Thomas Abraham
2023-12-18 15:16   ` Sami Mujawar

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