blob: 1db94e4948a85e6313fcad0d05d61105683adb63 [file] [log] [blame]
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001From 726f4505970c82db1822b127059519044dc496c8 Mon Sep 17 00:00:00 2001
2From: sahil <sahil@arm.com>
3Date: Mon, 2 May 2022 19:00:40 +0530
4Subject: [PATCH] Platform/ARM/N1Sdp: NOR flash Dxe Driver for N1Sdp
5
6Add NOR flash DXE driver, this brings up NV storage on
7QSPI's flash device using FVB protocol.
8
9Upstream-Status: Pending
10Signed-off-by: Xueliang Zhong <xueliang.zhong@arm.com>
11Signed-off-by: sahil <sahil@arm.com>
12Change-Id: Ica383c2be6d1805daa19afd98d28b943816218dd
13---
14 .../Drivers/CadenceQspiDxe/CadenceQspiDxe.c | 366 +++++++
15 .../Drivers/CadenceQspiDxe/CadenceQspiDxe.inf | 70 ++
16 .../Drivers/CadenceQspiDxe/CadenceQspiReg.h | 31 +
17 .../N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c | 930 ++++++++++++++++++
18 .../N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h | 484 +++++++++
19 .../Drivers/CadenceQspiDxe/NorFlashFvb.c | 573 +++++++++++
20 Platform/ARM/N1Sdp/N1SdpPlatform.dec | 5 +-
21 7 files changed, 2458 insertions(+), 1 deletion(-)
22 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c
23 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
24 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
25 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
26 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
27 create mode 100644 Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c
28
29diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c
30new file mode 100644
31index 00000000..fb1dff3e
32--- /dev/null
33+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c
34@@ -0,0 +1,366 @@
35+/** @file
36+ NOR flash DXE
37+
38+ Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
39+
40+ SPDX-License-Identifier: BSD-2-Clause-Patent
41+
42+**/
43+
44+#include <Library/BaseMemoryLib.h>
45+#include <Library/DxeServicesTableLib.h>
46+#include <Library/HobLib.h>
47+#include <Library/MemoryAllocationLib.h>
48+#include <Library/NorFlashInfoLib.h>
49+#include <Library/PcdLib.h>
50+#include <Library/UefiBootServicesTableLib.h>
51+#include <Library/UefiLib.h>
52+#include <Library/UefiRuntimeLib.h>
53+#include <Library/UefiRuntimeServicesTableLib.h>
54+
55+#include "NorFlash.h"
56+
57+STATIC NOR_FLASH_INSTANCE **mNorFlashInstances;
58+STATIC UINT32 mNorFlashDeviceCount;
59+
60+STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent;
61+
62+/**
63+ Install Fv block onto variable store region
64+
65+ @param[in] Instance Instance of Nor flash variable region.
66+
67+ @retval EFI_SUCCESS The entry point is executed successfully.
68+**/
69+EFI_STATUS
70+EFIAPI
71+NorFlashFvbInitialize (
72+ IN NOR_FLASH_INSTANCE* Instance
73+ )
74+{
75+ EFI_STATUS Status;
76+ UINT32 FvbNumLba;
77+ EFI_BOOT_MODE BootMode;
78+ UINTN RuntimeMmioRegionSize;
79+ UINTN RuntimeMmioDeviceSize;
80+ UINTN BlockSize;
81+
82+ DEBUG ((DEBUG_INFO,"NorFlashFvbInitialize\n"));
83+
84+ BlockSize = Instance->BlockSize;
85+
86+ // FirmwareVolumeHeader->FvLength is declared to have the Variable area
87+ // AND the FTW working area AND the FTW Spare contiguous.
88+ ASSERT (PcdGet32 (PcdFlashNvStorageVariableBase) +
89+ PcdGet32 (PcdFlashNvStorageVariableSize) ==
90+ PcdGet32 (PcdFlashNvStorageFtwWorkingBase));
91+ ASSERT (PcdGet32 (PcdFlashNvStorageFtwWorkingBase) +
92+ PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ==
93+ PcdGet32 (PcdFlashNvStorageFtwSpareBase));
94+
95+ // Check if the size of the area is at least one block size.
96+ ASSERT ((PcdGet32 (PcdFlashNvStorageVariableSize) > 0) &&
97+ (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0));
98+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) &&
99+ (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0));
100+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) &&
101+ (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0));
102+
103+ // Ensure the Variable areas are aligned on block size boundaries.
104+ ASSERT ((PcdGet32 (PcdFlashNvStorageVariableBase) % BlockSize) == 0);
105+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) % BlockSize) == 0);
106+ ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareBase) % BlockSize) == 0);
107+
108+ Instance->Initialized = TRUE;
109+ mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
110+
111+ // Set the index of the first LBA for the FVB.
112+ Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) -
113+ Instance->RegionBaseAddress) / BlockSize;
114+
115+ BootMode = GetBootModeHob ();
116+ if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
117+ Status = EFI_INVALID_PARAMETER;
118+ } else {
119+ // Determine if there is a valid header at the beginning of the NorFlash.
120+ Status = ValidateFvHeader (Instance);
121+ }
122+
123+ // Install the Default FVB header if required.
124+ if (EFI_ERROR(Status)) {
125+ // There is no valid header, so time to install one.
126+ DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __FUNCTION__));
127+ DEBUG ((DEBUG_INFO, "%a: Installing a correct one for this volume.\n",
128+ __FUNCTION__));
129+
130+ // Erase all the NorFlash that is reserved for variable storage.
131+ FvbNumLba = (PcdGet32 (PcdFlashNvStorageVariableSize) +
132+ PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
133+ PcdGet32 (PcdFlashNvStorageFtwSpareSize)) /
134+ Instance->BlockSize;
135+
136+ Status = FvbEraseBlocks (
137+ &Instance->FvbProtocol,
138+ (EFI_LBA)0,
139+ FvbNumLba,
140+ EFI_LBA_LIST_TERMINATOR
141+ );
142+ if (EFI_ERROR(Status)) {
143+ return Status;
144+ }
145+
146+ // Install all appropriate headers.
147+ Status = InitializeFvAndVariableStoreHeaders (Instance);
148+ if (EFI_ERROR(Status)) {
149+ return Status;
150+ }
151+
152+ // validate FV header again if FV was created successfully.
153+ Status = ValidateFvHeader (Instance);
154+ if (EFI_ERROR(Status)) {
155+ DEBUG ((DEBUG_ERROR, "ValidateFvHeader is failed \n"));
156+ return Status;
157+ }
158+ }
159+
160+ // The driver implementing the variable read service can now be dispatched;
161+ // the varstore headers are in place.
162+ Status = gBS->InstallProtocolInterface (
163+ &gImageHandle,
164+ &gEdkiiNvVarStoreFormattedGuid,
165+ EFI_NATIVE_INTERFACE,
166+ NULL
167+ );
168+ if (EFI_ERROR (Status)) {
169+ DEBUG ((DEBUG_ERROR,
170+ "%a: Failed to install gEdkiiNvVarStoreFormattedGuid\n",
171+ __FUNCTION__));
172+ return Status;
173+ }
174+
175+ // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME.
176+ RuntimeMmioRegionSize = Instance->Size;
177+ RuntimeMmioDeviceSize = Instance->RegionBaseAddress - Instance->DeviceBaseAddress;
178+
179+ Status = gDS->AddMemorySpace (
180+ EfiGcdMemoryTypeMemoryMappedIo,
181+ Instance->RegionBaseAddress,
182+ RuntimeMmioRegionSize,
183+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
184+ );
185+ ASSERT_EFI_ERROR (Status);
186+
187+ Status = gDS->AddMemorySpace (
188+ EfiGcdMemoryTypeMemoryMappedIo,
189+ Instance->DeviceBaseAddress,
190+ RuntimeMmioDeviceSize,
191+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
192+ );
193+ ASSERT_EFI_ERROR (Status);
194+
195+ Status = gDS->SetMemorySpaceAttributes (
196+ Instance->RegionBaseAddress,
197+ RuntimeMmioRegionSize,
198+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
199+ );
200+ ASSERT_EFI_ERROR (Status);
201+
202+ Status = gDS->SetMemorySpaceAttributes (
203+ Instance->DeviceBaseAddress,
204+ RuntimeMmioDeviceSize,
205+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
206+ );
207+ ASSERT_EFI_ERROR (Status);
208+
209+ return Status;
210+}
211+
212+/**
213+ Fixup internal data so that EFI can be called in virtual mode.
214+ convert any pointers in lib to virtual mode.
215+
216+ @param[in] Event The Event that is being processed
217+ @param[in] Context Event Context
218+**/
219+STATIC
220+VOID
221+EFIAPI
222+NorFlashVirtualNotifyEvent (
223+ IN EFI_EVENT Event,
224+ IN VOID *Context
225+ )
226+{
227+ UINTN Index;
228+
229+ EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase);
230+
231+ for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
232+ EfiConvertPointer (0x0,
233+ (VOID**)&mNorFlashInstances[Index]->HostRegisterBaseAddress);
234+ EfiConvertPointer (0x0,
235+ (VOID**)&mNorFlashInstances[Index]->DeviceBaseAddress);
236+ EfiConvertPointer (0x0,
237+ (VOID**)&mNorFlashInstances[Index]->RegionBaseAddress);
238+
239+ // Convert Fvb.
240+ EfiConvertPointer (0x0,
241+ (VOID**)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
242+ EfiConvertPointer (0x0,
243+ (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
244+ EfiConvertPointer (0x0,
245+ (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
246+ EfiConvertPointer (0x0,
247+ (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
248+ EfiConvertPointer (0x0,
249+ (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Read);
250+ EfiConvertPointer (0x0,
251+ (VOID**)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
252+ EfiConvertPointer (0x0,
253+ (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Write);
254+
255+ if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
256+ EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->ShadowBuffer);
257+ }
258+ }
259+}
260+
261+/**
262+ Entrypoint of Platform Nor flash DXE driver
263+
264+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
265+ @param[in] SystemTable A pointer to the EFI System Table.
266+
267+ @retval EFI_SUCCESS The entry point is executed successfully.
268+**/
269+EFI_STATUS
270+EFIAPI
271+NorFlashInitialise (
272+ IN EFI_HANDLE ImageHandle,
273+ IN EFI_SYSTEM_TABLE *SystemTable
274+ )
275+{
276+ EFI_STATUS Status;
277+ EFI_PHYSICAL_ADDRESS HostRegisterBaseAddress;
278+ UINT32 Index;
279+ NOR_FLASH_DESCRIPTION* NorFlashDevices;
280+ BOOLEAN ContainVariableStorage;
281+
282+ HostRegisterBaseAddress = PcdGet32 (PcdCadenceQspiDxeRegBaseAddress);
283+
284+ Status = gDS->AddMemorySpace (
285+ EfiGcdMemoryTypeMemoryMappedIo,
286+ HostRegisterBaseAddress,
287+ SIZE_64KB,
288+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
289+ );
290+ ASSERT_EFI_ERROR (Status);
291+
292+ Status = gDS->SetMemorySpaceAttributes (
293+ HostRegisterBaseAddress,
294+ SIZE_64KB,
295+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
296+ );
297+ ASSERT_EFI_ERROR (Status);
298+
299+ // Initialize NOR flash instances.
300+ Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);
301+ if (EFI_ERROR (Status)) {
302+ DEBUG ((DEBUG_ERROR,"NorFlashInitialise: Fail to get Nor Flash devices\n"));
303+ return Status;
304+ }
305+
306+ mNorFlashInstances = AllocateRuntimePool (sizeof (NOR_FLASH_INSTANCE*) *
307+ mNorFlashDeviceCount);
308+
309+ if(mNorFlashInstances == NULL) {
310+ DEBUG ((DEBUG_ERROR,
311+ "NorFlashInitialise: Failed to allocate mem for NorFlashInstance\n"));
312+ return EFI_OUT_OF_RESOURCES;
313+ }
314+
315+ for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
316+ // Check if this NOR Flash device contain the variable storage region.
317+ ContainVariableStorage =
318+ (NorFlashDevices[Index].RegionBaseAddress <=
319+ PcdGet32 (PcdFlashNvStorageVariableBase)) &&
320+ (PcdGet32 (PcdFlashNvStorageVariableBase) +
321+ PcdGet32 (PcdFlashNvStorageVariableSize) <=
322+ NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
323+
324+ Status = NorFlashCreateInstance (
325+ HostRegisterBaseAddress,
326+ NorFlashDevices[Index].DeviceBaseAddress,
327+ NorFlashDevices[Index].RegionBaseAddress,
328+ NorFlashDevices[Index].Size,
329+ Index,
330+ NorFlashDevices[Index].BlockSize,
331+ ContainVariableStorage,
332+ &mNorFlashInstances[Index]
333+ );
334+ if (EFI_ERROR (Status)) {
335+ DEBUG ((DEBUG_ERROR,
336+ "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",
337+ Index));
338+ continue;
339+ }
340+ Status = gBS->InstallMultipleProtocolInterfaces (
341+ &mNorFlashInstances[Index]->Handle,
342+ &gEfiDevicePathProtocolGuid,
343+ &mNorFlashInstances[Index]->DevicePath,
344+ &gEfiFirmwareVolumeBlockProtocolGuid,
345+ &mNorFlashInstances[Index]->FvbProtocol,
346+ NULL
347+ );
348+ ASSERT_EFI_ERROR (Status);
349+ }
350+ // Register for the virtual address change event.
351+ Status = gBS->CreateEventEx (
352+ EVT_NOTIFY_SIGNAL,
353+ TPL_NOTIFY,
354+ NorFlashVirtualNotifyEvent,
355+ NULL,
356+ &gEfiEventVirtualAddressChangeGuid,
357+ &mNorFlashVirtualAddrChangeEvent
358+ );
359+ ASSERT_EFI_ERROR (Status);
360+
361+ return Status;
362+}
363+
364+/**
365+ Lock all pending read/write to Nor flash device
366+
367+ @param[in] Context Nor flash device context structure.
368+**/
369+VOID
370+EFIAPI
371+NorFlashLock (
372+ IN NOR_FLASH_LOCK_CONTEXT *Context
373+ )
374+{
375+ if (!EfiAtRuntime ()) {
376+ // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
377+ Context->OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
378+ } else {
379+ Context->InterruptsEnabled = SaveAndDisableInterrupts ();
380+ }
381+}
382+
383+/**
384+ Unlock all pending read/write to Nor flash device
385+
386+ @param[in] Context Nor flash device context structure.
387+**/
388+VOID
389+EFIAPI
390+NorFlashUnlock (
391+ IN NOR_FLASH_LOCK_CONTEXT *Context
392+ )
393+{
394+ if (!EfiAtRuntime ()) {
395+ // Interruptions can resume.
396+ gBS->RestoreTPL (Context->OriginalTPL);
397+ } else if (Context->InterruptsEnabled) {
398+ SetInterruptState (TRUE);
399+ }
400+}
401diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
402new file mode 100644
403index 00000000..4f20c3ba
404--- /dev/null
405+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf
406@@ -0,0 +1,70 @@
407+## @file
408+# NOR flash DXE
409+#
410+# Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
411+#
412+# SPDX-License-Identifier: BSD-2-Clause-Patent
413+#
414+##
415+
416+[Defines]
417+ INF_VERSION = 0x0001001B
418+ BASE_NAME = CadenceQspiDxe
419+ FILE_GUID = CC8A9713-4442-4A6C-B389-8B46490A0641
420+ MODULE_TYPE = DXE_RUNTIME_DRIVER
421+ VERSION_STRING = 0.1
422+ ENTRY_POINT = NorFlashInitialise
423+
424+[Sources]
425+ CadenceQspiDxe.c
426+ NorFlash.c
427+ NorFlash.h
428+ NorFlashFvb.c
429+
430+[Packages]
431+ EmbeddedPkg/EmbeddedPkg.dec
432+ MdeModulePkg/MdeModulePkg.dec
433+ MdePkg/MdePkg.dec
434+ Platform/ARM/ARM.dec
435+ Platform/ARM/N1Sdp/N1SdpPlatform.dec
436+
437+[LibraryClasses]
438+ BaseLib
439+ BaseMemoryLib
440+ DebugLib
441+ DevicePathLib
442+ DxeServicesTableLib
443+ HobLib
444+ IoLib
445+ MemoryAllocationLib
446+ NorFlashInfoLib
447+ NorFlashPlatformLib
448+ UefiBootServicesTableLib
449+ UefiDriverEntryPoint
450+ UefiLib
451+ UefiRuntimeLib
452+ UefiRuntimeServicesTableLib
453+
454+[Guids]
455+ gEdkiiNvVarStoreFormattedGuid
456+ gEfiAuthenticatedVariableGuid
457+ gEfiEventVirtualAddressChangeGuid
458+ gEfiSystemNvDataFvGuid
459+ gEfiVariableGuid
460+ gEfiGlobalVariableGuid
461+
462+[Protocols]
463+ gEfiDevicePathProtocolGuid
464+ gEfiFirmwareVolumeBlockProtocolGuid
465+
466+[FixedPcd]
467+ gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress
468+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
469+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
470+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
471+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
472+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
473+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
474+
475+[Depex]
476+ gEfiCpuArchProtocolGuid
477diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
478new file mode 100644
479index 00000000..fe3b327c
480--- /dev/null
481+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h
482@@ -0,0 +1,31 @@
483+/** @file
484+
485+ Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
486+
487+ SPDX-License-Identifier: BSD-2-Clause-Patent
488+
489+**/
490+
491+#ifndef CADENCE_QSPI_REG_H_
492+#define CADENCE_QSPI_REG_H_
493+
494+// QSPI Controller defines
495+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET 0x90
496+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE 0x01
497+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE 0x01
498+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS 19
499+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS 16
500+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT 0x02
501+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_4B 0x03
502+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_3B 0x02
503+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS 24
504+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE 0x01
505+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_BYTE_3B 0x02
506+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS 23
507+#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS 20
508+
509+#define CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET 0xA0
510+
511+#define CDNS_QSPI_FLASH_CMD_ADDR_REG_OFFSET 0x94
512+
513+#endif /* CADENCE_QSPI_REG_H_ */
514diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
515new file mode 100644
516index 00000000..188c75e2
517--- /dev/null
518+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c
519@@ -0,0 +1,930 @@
520+/** @file
521+
522+ Copyright (c) 2023 ARM Limited. All rights reserved.<BR>
523+
524+ SPDX-License-Identifier: BSD-2-Clause-Patent
525+
526+**/
527+
528+#include <Library/BaseMemoryLib.h>
529+#include <Library/MemoryAllocationLib.h>
530+#include <Library/NorFlashInfoLib.h>
531+#include <Library/PcdLib.h>
532+#include <Library/UefiBootServicesTableLib.h>
533+#include <Library/UefiLib.h>
534+
535+#include "NorFlash.h"
536+
537+STATIC CONST NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {
538+ NOR_FLASH_SIGNATURE, // Signature
539+ NULL, // Handle
540+
541+ FALSE, // Initialized
542+ NULL, // Initialize
543+
544+ 0, // HostRegisterBaseAddress
545+ 0, // DeviceBaseAddress
546+ 0, // RegionBaseAddress
547+ 0, // Size
548+ 0, // BlockSize
549+ 0, // LastBlock
550+ 0, // StartLba
551+ 0, // OffsetLba
552+
553+ {
554+ FvbGetAttributes, // GetAttributes
555+ FvbSetAttributes, // SetAttributes
556+ FvbGetPhysicalAddress, // GetPhysicalAddress
557+ FvbGetBlockSize, // GetBlockSize
558+ FvbRead, // Read
559+ FvbWrite, // Write
560+ FvbEraseBlocks, // EraseBlocks
561+ NULL, //ParentHandle
562+ }, // FvbProtoccol;
563+ NULL, // ShadowBuffer
564+
565+ {
566+ {
567+ {
568+ HARDWARE_DEVICE_PATH,
569+ HW_VENDOR_DP,
570+ {
571+ (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),
572+ (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)
573+ }
574+ },
575+ { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } },
576+ },
577+ 0, // Index
578+
579+ {
580+ END_DEVICE_PATH_TYPE,
581+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
582+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
583+ }
584+
585+ }, // DevicePath
586+ 0 // Flags
587+};
588+
589+/**
590+ Execute Flash cmd ctrl and Read Status.
591+
592+ @param[in] Instance NOR flash Instance.
593+ @param[in] Val Value to be written to Flash cmd ctrl Register.
594+
595+ @retval EFI_SUCCESS Request is executed successfully.
596+
597+**/
598+STATIC
599+EFI_STATUS
600+CdnsQspiExecuteCommand (
601+ IN NOR_FLASH_INSTANCE *Instance,
602+ IN UINT32 Val
603+ )
604+{
605+ // Set the command
606+ MmioWrite32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET,
607+ Val);
608+ // Execute the command
609+ MmioWrite32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET,
610+ Val | CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE);
611+
612+ // Wait until command has been executed
613+ while ((MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET)
614+ & CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT) == CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT)
615+ continue;
616+
617+ return EFI_SUCCESS;
618+}
619+
620+/**
621+ Create Nor flash Instance for given region.
622+
623+ @param[in] HostRegisterBase Base address of Nor flash controller.
624+ @param[in] NorFlashDeviceBase Base address of flash device.
625+ @param[in] NorFlashRegionBase Base address of flash region on device.
626+ @param[in] NorFlashSize Size of flash region.
627+ @param[in] Index Index of given flash region.
628+ @param[in] BlockSize Block size of NOR flash device.
629+ @param[in] HasVarStore Boolean set for VarStore on given region.
630+ @param[out] NorFlashInstance Instance of given flash region.
631+
632+ @retval EFI_SUCCESS On successful creation of NOR flash instance.
633+**/
634+EFI_STATUS
635+NorFlashCreateInstance (
636+ IN UINTN HostRegisterBase,
637+ IN UINTN NorFlashDeviceBase,
638+ IN UINTN NorFlashRegionBase,
639+ IN UINTN NorFlashSize,
640+ IN UINT32 Index,
641+ IN UINT32 BlockSize,
642+ IN BOOLEAN HasVarStore,
643+ OUT NOR_FLASH_INSTANCE** NorFlashInstance
644+ )
645+{
646+ EFI_STATUS Status;
647+ NOR_FLASH_INSTANCE* Instance;
648+ NOR_FLASH_INFO *FlashInfo;
649+ UINT8 JedecId[3];
650+
651+ ASSERT(NorFlashInstance != NULL);
652+ Instance = AllocateRuntimeCopyPool (sizeof (mNorFlashInstanceTemplate),
653+ &mNorFlashInstanceTemplate);
654+ if (Instance == NULL) {
655+ return EFI_OUT_OF_RESOURCES;
656+ }
657+
658+ Instance->HostRegisterBaseAddress = HostRegisterBase;
659+ Instance->DeviceBaseAddress = NorFlashDeviceBase;
660+ Instance->RegionBaseAddress = NorFlashRegionBase;
661+ Instance->Size = NorFlashSize;
662+ Instance->BlockSize = BlockSize;
663+ Instance->LastBlock = (NorFlashSize / BlockSize) - 1;
664+
665+ Instance->OffsetLba = (NorFlashRegionBase - NorFlashDeviceBase) / BlockSize;
666+
667+ CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);
668+ Instance->DevicePath.Index = (UINT8)Index;
669+
670+ Status = NorFlashReadID (Instance, JedecId);
671+ if (EFI_ERROR (Status)) {
672+ goto FreeInstance;
673+ }
674+
675+ Status = NorFlashGetInfo (JedecId, &FlashInfo, TRUE);
676+ if (EFI_ERROR (Status)) {
677+ goto FreeInstance;
678+ }
679+
680+ NorFlashPrintInfo (FlashInfo);
681+
682+ Instance->Flags = 0;
683+ if (FlashInfo->Flags & NOR_FLASH_WRITE_FSR) {
684+ Instance->Flags = NOR_FLASH_POLL_FSR;
685+ }
686+
687+ Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);
688+ if (Instance->ShadowBuffer == NULL) {
689+ Status = EFI_OUT_OF_RESOURCES;
690+ goto FreeInstance;
691+ }
692+
693+ if (HasVarStore) {
694+ Instance->Initialize = NorFlashFvbInitialize;
695+ }
696+
697+ *NorFlashInstance = Instance;
698+ FreePool (FlashInfo);
699+ return EFI_SUCCESS;
700+
701+FreeInstance:
702+ FreePool (Instance);
703+ return Status;
704+}
705+
706+/**
707+ Check whether NOR flash opertions are Locked.
708+
709+ @param[in] Instance NOR flash Instance.
710+ @param[in] BlockAddress BlockAddress in NOR flash device.
711+
712+ @retval FALSE If NOR flash is not locked.
713+**/
714+STATIC
715+BOOLEAN
716+NorFlashBlockIsLocked (
717+ IN NOR_FLASH_INSTANCE *Instance,
718+ IN UINTN BlockAddress
719+ )
720+{
721+ return FALSE;
722+}
723+
724+/**
725+ Unlock NOR flash operations on given block.
726+
727+ @param[in] Instance NOR flash instance.
728+ @param[in] BlockAddress BlockAddress in NOR flash device.
729+
730+ @retval EFI_SUCCESS NOR flash operations is unlocked.
731+**/
732+STATIC
733+EFI_STATUS
734+NorFlashUnlockSingleBlock (
735+ IN NOR_FLASH_INSTANCE *Instance,
736+ IN UINTN BlockAddress
737+ )
738+{
739+ return EFI_SUCCESS;
740+}
741+
742+/**
743+ Unlock NOR flash operations if it is necessary.
744+
745+ @param[in] Instance NOR flash instance.
746+ @param[in] BlockAddress BlockAddress in NOR flash device.
747+
748+ @retval EFI_SUCCESS Request is executed successfully.
749+**/
750+STATIC
751+EFI_STATUS
752+NorFlashUnlockSingleBlockIfNecessary (
753+ IN NOR_FLASH_INSTANCE *Instance,
754+ IN UINTN BlockAddress
755+ )
756+{
757+ EFI_STATUS Status;
758+
759+ Status = EFI_SUCCESS;
760+
761+ if (!NorFlashBlockIsLocked (Instance, BlockAddress)) {
762+ Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
763+ }
764+
765+ return Status;
766+}
767+
768+/**
769+ Enable write to NOR flash device.
770+
771+ @param[in] Instance NOR flash instance.
772+
773+ @retval EFI_SUCCESS Request is executed successfully.
774+**/
775+STATIC
776+EFI_STATUS
777+NorFlashEnableWrite (
778+ IN NOR_FLASH_INSTANCE *Instance
779+ )
780+{
781+
782+ UINT32 val;
783+
784+ DEBUG ((DEBUG_INFO, "NorFlashEnableWrite()\n"));
785+ val = (SPINOR_OP_WREN << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS);
786+ if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
787+ return EFI_DEVICE_ERROR;
788+ }
789+
790+ return EFI_SUCCESS;
791+}
792+
793+/**
794+ The following function presumes that the block has already been unlocked.
795+
796+ @param[in] Instance NOR flash instance.
797+ @param[in] BlockAddress Block address within the variable region.
798+
799+ @retval EFI_SUCCESS Request is executed successfully.
800+ **/
801+EFI_STATUS
802+NorFlashEraseSingleBlock (
803+ IN NOR_FLASH_INSTANCE *Instance,
804+ IN UINTN BlockAddress
805+ )
806+{
807+
808+ UINT32 DevConfigVal;
809+ UINT32 EraseOffset;
810+
811+ EraseOffset = 0x0;
812+
813+ DEBUG ((DEBUG_INFO, "NorFlashEraseSingleBlock(BlockAddress=0x%08x)\n",
814+ BlockAddress));
815+
816+ if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
817+ return EFI_DEVICE_ERROR;
818+ }
819+
820+ EraseOffset = BlockAddress - Instance->DeviceBaseAddress;
821+
822+ MmioWrite32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_ADDR_REG_OFFSET,
823+ EraseOffset);
824+
825+ DevConfigVal = SPINOR_OP_BE_4K << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
826+ CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS |
827+ CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_3B << CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS;
828+
829+ if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, DevConfigVal))) {
830+ return EFI_DEVICE_ERROR;
831+ }
832+
833+ return EFI_SUCCESS;
834+}
835+
836+/**
837+ This function unlock and erase an entire NOR Flash block.
838+
839+ @param[in] Instance NOR flash Instance of variable store region.
840+ @param[in] BlockAddress Block address within the variable store region.
841+
842+ @retval EFI_SUCCESS The erase and unlock successfully completed.
843+**/
844+EFI_STATUS
845+NorFlashUnlockAndEraseSingleBlock (
846+ IN NOR_FLASH_INSTANCE *Instance,
847+ IN UINTN BlockAddress
848+ )
849+{
850+ EFI_STATUS Status;
851+ UINTN Index;
852+ NOR_FLASH_LOCK_CONTEXT Lock;
853+ NorFlashLock (&Lock);
854+
855+ Index = 0;
856+ do {
857+ // Unlock the block if we have to
858+ Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
859+ if (EFI_ERROR (Status)) {
860+ break;
861+ }
862+ Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
863+ if (EFI_ERROR (Status)) {
864+ break;
865+ }
866+ Index++;
867+ } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
868+
869+ if (Index == NOR_FLASH_ERASE_RETRY) {
870+ DEBUG ((DEBUG_ERROR,
871+ "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n",
872+ BlockAddress,Index));
873+ }
874+
875+ NorFlashUnlock (&Lock);
876+
877+ return Status;
878+}
879+
880+/**
881+ Write a single word to given location.
882+
883+ @param[in] Instance NOR flash Instance of variable store region.
884+ @param[in] WordAddress The address in NOR flash to write given word.
885+ @param[in] WriteData The data to write into NOR flash location.
886+
887+ @retval EFI_SUCCESS The write is completed.
888+**/
889+STATIC
890+EFI_STATUS
891+NorFlashWriteSingleWord (
892+ IN NOR_FLASH_INSTANCE *Instance,
893+ IN UINTN WordAddress,
894+ IN UINT32 WriteData
895+ )
896+{
897+ DEBUG ((DEBUG_INFO,
898+ "NorFlashWriteSingleWord(WordAddress=0x%08x, WriteData=0x%08x)\n",
899+ WordAddress, WriteData));
900+
901+ if (EFI_ERROR (NorFlashEnableWrite (Instance))) {
902+ return EFI_DEVICE_ERROR;
903+ }
904+ MmioWrite32 (WordAddress, WriteData);
905+ return EFI_SUCCESS;
906+}
907+
908+/**
909+ Write a full block to given location.
910+
911+ @param[in] Instance NOR flash Instance of variable store region.
912+ @param[in] Lba The logical block address in NOR flash.
913+ @param[in] DataBuffer The data to write into NOR flash location.
914+ @param[in] BlockSizeInWords The number of bytes to write.
915+
916+ @retval EFI_SUCCESS The write is completed.
917+**/
918+STATIC
919+EFI_STATUS
920+NorFlashWriteFullBlock (
921+ IN NOR_FLASH_INSTANCE *Instance,
922+ IN EFI_LBA Lba,
923+ IN UINT32 *DataBuffer,
924+ IN UINT32 BlockSizeInWords
925+ )
926+{
927+ EFI_STATUS Status;
928+ UINTN WordAddress;
929+ UINT32 WordIndex;
930+ UINTN BlockAddress;
931+ NOR_FLASH_LOCK_CONTEXT Lock;
932+
933+ Status = EFI_SUCCESS;
934+
935+ // Get the physical address of the block
936+ BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
937+ BlockSizeInWords * 4);
938+
939+ // Start writing from the first address at the start of the block
940+ WordAddress = BlockAddress;
941+
942+ NorFlashLock (&Lock);
943+
944+ Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
945+ if (EFI_ERROR (Status)) {
946+ DEBUG ((DEBUG_ERROR,
947+ "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n",
948+ BlockAddress));
949+ goto EXIT;
950+ }
951+
952+ for (WordIndex=0;
953+ WordIndex < BlockSizeInWords;
954+ WordIndex++, DataBuffer++, WordAddress += 4) {
955+ Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
956+ if (EFI_ERROR (Status)) {
957+ goto EXIT;
958+ }
959+ }
960+
961+EXIT:
962+ NorFlashUnlock (&Lock);
963+
964+ if (EFI_ERROR (Status)) {
965+ DEBUG ((DEBUG_ERROR,
966+ "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = %r.\n",
967+ WordAddress, Status));
968+ }
969+ return Status;
970+}
971+
972+/**
973+ Write a full block.
974+
975+ @param[in] Instance NOR flash Instance of variable store region.
976+ @param[in] Lba The starting logical block index.
977+ @param[in] BufferSizeInBytes The number of bytes to read.
978+ @param[in] Buffer The pointer to a caller-allocated buffer that
979+ contains the source for the write.
980+
981+ @retval EFI_SUCCESS The write is completed.
982+**/
983+EFI_STATUS
984+NorFlashWriteBlocks (
985+ IN NOR_FLASH_INSTANCE *Instance,
986+ IN EFI_LBA Lba,
987+ IN UINTN BufferSizeInBytes,
988+ IN VOID *Buffer
989+ )
990+{
991+ UINT32 *pWriteBuffer;
992+ EFI_STATUS Status;
993+ EFI_LBA CurrentBlock;
994+ UINT32 BlockSizeInWords;
995+ UINT32 NumBlocks;
996+ UINT32 BlockCount;
997+
998+ Status = EFI_SUCCESS;
999+ // The buffer must be valid
1000+ if (Buffer == NULL) {
1001+ return EFI_INVALID_PARAMETER;
1002+ }
1003+
1004+ // We must have some bytes to read
1005+ DEBUG ((DEBUG_INFO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n",
1006+ BufferSizeInBytes));
1007+ if (BufferSizeInBytes == 0) {
1008+ return EFI_BAD_BUFFER_SIZE;
1009+ }
1010+
1011+ // The size of the buffer must be a multiple of the block size
1012+ DEBUG ((DEBUG_INFO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n",
1013+ Instance->BlockSize));
1014+ if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
1015+ return EFI_BAD_BUFFER_SIZE;
1016+ }
1017+
1018+ // All blocks must be within the device
1019+ NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
1020+
1021+ DEBUG ((DEBUG_INFO,
1022+ "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks,
1023+ Instance->LastBlock, Lba));
1024+
1025+ if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
1026+ DEBUG ((DEBUG_ERROR,
1027+ "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
1028+ return EFI_INVALID_PARAMETER;
1029+ }
1030+
1031+ ASSERT (((UINTN)Buffer % sizeof (UINT32)) == 0);
1032+
1033+ BlockSizeInWords = Instance->BlockSize / 4;
1034+
1035+ // Because the target *Buffer is a pointer to VOID, we must put
1036+ // all the data into a pointer to a proper data type, so use *ReadBuffer
1037+ pWriteBuffer = (UINT32 *)Buffer;
1038+
1039+ CurrentBlock = Lba;
1040+ for (BlockCount = 0;
1041+ BlockCount < NumBlocks;
1042+ BlockCount++, CurrentBlock++, pWriteBuffer += BlockSizeInWords) {
1043+
1044+ DEBUG ((DEBUG_INFO, "NorFlashWriteBlocks: Writing block #%d\n",
1045+ (UINTN)CurrentBlock));
1046+
1047+ Status = NorFlashWriteFullBlock (
1048+ Instance,
1049+ CurrentBlock,
1050+ pWriteBuffer,
1051+ BlockSizeInWords
1052+ );
1053+
1054+ if (EFI_ERROR (Status)) {
1055+ break;
1056+ }
1057+ }
1058+
1059+ DEBUG ((DEBUG_INFO, "NorFlashWriteBlocks: Exit Status = %r.\n", Status));
1060+ return Status;
1061+}
1062+
1063+/**
1064+ Read a full block.
1065+
1066+ @param[in] Instance NOR flash Instance of variable store region.
1067+ @param[in] Lba The starting logical block index to read from.
1068+ @param[in] BufferSizeInBytes The number of bytes to read.
1069+ @param[out] Buffer The pointer to a caller-allocated buffer that
1070+ should be copied with read data.
1071+
1072+ @retval EFI_SUCCESS The read is completed.
1073+**/
1074+EFI_STATUS
1075+NorFlashReadBlocks (
1076+ IN NOR_FLASH_INSTANCE *Instance,
1077+ IN EFI_LBA Lba,
1078+ IN UINTN BufferSizeInBytes,
1079+ OUT VOID *Buffer
1080+ )
1081+{
1082+ UINT32 NumBlocks;
1083+ UINTN StartAddress;
1084+ DEBUG ((DEBUG_INFO,
1085+ "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
1086+ BufferSizeInBytes, Instance->BlockSize, Instance->LastBlock,
1087+ Lba));
1088+
1089+ // The buffer must be valid
1090+ if (Buffer == NULL) {
1091+ return EFI_INVALID_PARAMETER;
1092+ }
1093+
1094+ // Return if we do not have any byte to read
1095+ if (BufferSizeInBytes == 0) {
1096+ return EFI_SUCCESS;
1097+ }
1098+
1099+ // The size of the buffer must be a multiple of the block size
1100+ if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
1101+ return EFI_BAD_BUFFER_SIZE;
1102+ }
1103+
1104+ NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
1105+
1106+ if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
1107+ DEBUG ((DEBUG_ERROR,
1108+ "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
1109+ return EFI_INVALID_PARAMETER;
1110+ }
1111+
1112+ // Get the address to start reading from
1113+ StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
1114+ Instance->BlockSize);
1115+
1116+ // Readout the data
1117+ CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes);
1118+
1119+ return EFI_SUCCESS;
1120+}
1121+
1122+/**
1123+ Read from nor flash.
1124+
1125+ @param[in] Instance NOR flash Instance of variable store region.
1126+ @param[in] Lba The starting logical block index to read from.
1127+ @param[in] Offset Offset into the block at which to begin reading.
1128+ @param[in] BufferSizeInBytes The number of bytes to read.
1129+ @param[out] Buffer The pointer to a caller-allocated buffer that
1130+ should copied with read data.
1131+
1132+ @retval EFI_SUCCESS The read is completed.
1133+**/
1134+EFI_STATUS
1135+NorFlashRead (
1136+ IN NOR_FLASH_INSTANCE *Instance,
1137+ IN EFI_LBA Lba,
1138+ IN UINTN Offset,
1139+ IN UINTN BufferSizeInBytes,
1140+ OUT VOID *Buffer
1141+ )
1142+{
1143+ UINTN StartAddress;
1144+ // The buffer must be valid
1145+ if (Buffer == NULL) {
1146+ return EFI_INVALID_PARAMETER;
1147+ }
1148+
1149+ // Return if we do not have any byte to read
1150+ if (BufferSizeInBytes == 0) {
1151+ return EFI_SUCCESS;
1152+ }
1153+
1154+ if (((Lba * Instance->BlockSize) + Offset + BufferSizeInBytes) >
1155+ Instance->Size) {
1156+ DEBUG ((DEBUG_ERROR,
1157+ "NorFlashRead: ERROR - Read will exceed device size.\n"));
1158+ return EFI_INVALID_PARAMETER;
1159+ }
1160+
1161+ // Get the address to start reading from
1162+ StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
1163+ Instance->BlockSize);
1164+
1165+ // Readout the data
1166+ CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes);
1167+
1168+ return EFI_SUCCESS;
1169+}
1170+
1171+/**
1172+ Write a full or portion of a block.
1173+
1174+ @param[in] Instance NOR flash Instance of variable store region.
1175+ @param[in] Lba The starting logical block index to write to.
1176+ @param[in] Offset Offset into the block at which to begin writing.
1177+ @param[in, out] NumBytes The total size of the buffer.
1178+ @param[in] Buffer The pointer to a caller-allocated buffer that
1179+ contains the source for the write.
1180+
1181+ @retval EFI_SUCCESS The write is completed.
1182+**/
1183+EFI_STATUS
1184+NorFlashWriteSingleBlock (
1185+ IN NOR_FLASH_INSTANCE *Instance,
1186+ IN EFI_LBA Lba,
1187+ IN UINTN Offset,
1188+ IN OUT UINTN *NumBytes,
1189+ IN UINT8 *Buffer
1190+ )
1191+{
1192+ EFI_STATUS Status;
1193+ UINT32 Tmp;
1194+ UINT32 TmpBuf;
1195+ UINT32 WordToWrite;
1196+ UINT32 Mask;
1197+ BOOLEAN DoErase;
1198+ UINTN BytesToWrite;
1199+ UINTN CurOffset;
1200+ UINTN WordAddr;
1201+ UINTN BlockSize;
1202+ UINTN BlockAddress;
1203+ UINTN PrevBlockAddress;
1204+
1205+ if (Buffer == NULL) {
1206+ DEBUG ((DEBUG_ERROR,
1207+ "NorFlashWriteSingleBlock: ERROR - Buffer is invalid\n" ));
1208+ return EFI_OUT_OF_RESOURCES;
1209+ }
1210+
1211+ PrevBlockAddress = 0;
1212+ if (!Instance->Initialized && Instance->Initialize) {
1213+ Instance->Initialize(Instance);
1214+ }
1215+
1216+ DEBUG ((DEBUG_INFO,
1217+ "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n",
1218+ Lba, Offset, *NumBytes, Buffer));
1219+
1220+ // Localise the block size to avoid de-referencing pointers all the time
1221+ BlockSize = Instance->BlockSize;
1222+
1223+ // The write must not span block boundaries.
1224+ // We need to check each variable individually because adding two large
1225+ // values together overflows.
1226+ if (Offset >= BlockSize ||
1227+ *NumBytes > BlockSize ||
1228+ (Offset + *NumBytes) > BlockSize) {
1229+ DEBUG ((DEBUG_ERROR,
1230+ "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
1231+ Offset, *NumBytes, BlockSize ));
1232+ return EFI_BAD_BUFFER_SIZE;
1233+ }
1234+
1235+ // We must have some bytes to write
1236+ if (*NumBytes == 0) {
1237+ DEBUG ((DEBUG_ERROR,
1238+ "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
1239+ Offset, *NumBytes, BlockSize ));
1240+ return EFI_BAD_BUFFER_SIZE;
1241+ }
1242+
1243+ // Pick 128bytes as a good start for word operations as opposed to erasing the
1244+ // block and writing the data regardless if an erase is really needed.
1245+ // It looks like most individual NV variable writes are smaller than 128bytes.
1246+ if (*NumBytes <= 128) {
1247+ // Check to see if we need to erase before programming the data into NOR.
1248+ // If the destination bits are only changing from 1s to 0s we can just write.
1249+ // After a block is erased all bits in the block is set to 1.
1250+ // If any byte requires us to erase we just give up and rewrite all of it.
1251+ DoErase = FALSE;
1252+ BytesToWrite = *NumBytes;
1253+ CurOffset = Offset;
1254+
1255+ while (BytesToWrite > 0) {
1256+ // Read full word from NOR, splice as required. A word is the smallest
1257+ // unit we can write.
1258+ Status = NorFlashRead (
1259+ Instance,
1260+ Lba,
1261+ CurOffset & ~(0x3),
1262+ sizeof(Tmp),
1263+ &Tmp
1264+ );
1265+ if (EFI_ERROR (Status)) {
1266+ return EFI_DEVICE_ERROR;
1267+ }
1268+
1269+ // Physical address of word in NOR to write.
1270+ WordAddr = (CurOffset & ~(0x3)) +
1271+ GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba,
1272+ BlockSize);
1273+
1274+ // The word of data that is to be written.
1275+ TmpBuf = ReadUnaligned32 ((UINT32 *)(Buffer + (*NumBytes - BytesToWrite)));
1276+
1277+ // First do word aligned chunks.
1278+ if ((CurOffset & 0x3) == 0) {
1279+ if (BytesToWrite >= 4) {
1280+ // Is the destination still in 'erased' state?
1281+ if (~Tmp != 0) {
1282+ // Check to see if we are only changing bits to zero.
1283+ if ((Tmp ^ TmpBuf) & TmpBuf) {
1284+ DoErase = TRUE;
1285+ break;
1286+ }
1287+ }
1288+ // Write this word to NOR
1289+ WordToWrite = TmpBuf;
1290+ CurOffset += sizeof(TmpBuf);
1291+ BytesToWrite -= sizeof(TmpBuf);
1292+ } else {
1293+ // BytesToWrite < 4. Do small writes and left-overs
1294+ Mask = ~((~0) << (BytesToWrite * 8));
1295+ // Mask out the bytes we want.
1296+ TmpBuf &= Mask;
1297+ // Is the destination still in 'erased' state?
1298+ if ((Tmp & Mask) != Mask) {
1299+ // Check to see if we are only changing bits to zero.
1300+ if ((Tmp ^ TmpBuf) & TmpBuf) {
1301+ DoErase = TRUE;
1302+ break;
1303+ }
1304+ }
1305+ // Merge old and new data. Write merged word to NOR
1306+ WordToWrite = (Tmp & ~Mask) | TmpBuf;
1307+ CurOffset += BytesToWrite;
1308+ BytesToWrite = 0;
1309+ }
1310+ } else {
1311+ // Do multiple words, but starting unaligned.
1312+ if (BytesToWrite > (4 - (CurOffset & 0x3))) {
1313+ Mask = ((~0) << ((CurOffset & 0x3) * 8));
1314+ // Mask out the bytes we want.
1315+ TmpBuf &= Mask;
1316+ // Is the destination still in 'erased' state?
1317+ if ((Tmp & Mask) != Mask) {
1318+ // Check to see if we are only changing bits to zero.
1319+ if ((Tmp ^ TmpBuf) & TmpBuf) {
1320+ DoErase = TRUE;
1321+ break;
1322+ }
1323+ }
1324+ // Merge old and new data. Write merged word to NOR
1325+ WordToWrite = (Tmp & ~Mask) | TmpBuf;
1326+ BytesToWrite -= (4 - (CurOffset & 0x3));
1327+ CurOffset += (4 - (CurOffset & 0x3));
1328+ } else {
1329+ // Unaligned and fits in one word.
1330+ Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8);
1331+ // Mask out the bytes we want.
1332+ TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;
1333+ // Is the destination still in 'erased' state?
1334+ if ((Tmp & Mask) != Mask) {
1335+ // Check to see if we are only changing bits to zero.
1336+ if ((Tmp ^ TmpBuf) & TmpBuf) {
1337+ DoErase = TRUE;
1338+ break;
1339+ }
1340+ }
1341+ // Merge old and new data. Write merged word to NOR
1342+ WordToWrite = (Tmp & ~Mask) | TmpBuf;
1343+ CurOffset += BytesToWrite;
1344+ BytesToWrite = 0;
1345+ }
1346+ }
1347+
1348+ BlockAddress = GET_NOR_BLOCK_ADDRESS (
1349+ Instance->RegionBaseAddress,
1350+ Lba,
1351+ BlockSize
1352+ );
1353+ if (BlockAddress != PrevBlockAddress) {
1354+ Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
1355+ if (EFI_ERROR (Status)) {
1356+ return EFI_DEVICE_ERROR;
1357+ }
1358+ PrevBlockAddress = BlockAddress;
1359+ }
1360+ Status = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite);
1361+ if (EFI_ERROR (Status)) {
1362+ return EFI_DEVICE_ERROR;
1363+ }
1364+ }
1365+ // Exit if we got here and could write all the data. Otherwise do the
1366+ // Erase-Write cycle.
1367+ if (!DoErase) {
1368+ return EFI_SUCCESS;
1369+ }
1370+ }
1371+
1372+ // Check we did get some memory. Buffer is BlockSize.
1373+ if (Instance->ShadowBuffer == NULL) {
1374+ DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
1375+ return EFI_DEVICE_ERROR;
1376+ }
1377+
1378+ // Read NOR Flash data into shadow buffer
1379+ Status = NorFlashReadBlocks (
1380+ Instance,
1381+ Lba,
1382+ BlockSize,
1383+ Instance->ShadowBuffer
1384+ );
1385+ if (EFI_ERROR (Status)) {
1386+ // Return one of the pre-approved error statuses
1387+ return EFI_DEVICE_ERROR;
1388+ }
1389+
1390+ // Put the data at the appropriate location inside the buffer area
1391+ CopyMem ((VOID*)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
1392+
1393+ // Write the modified buffer back to the NorFlash
1394+ Status = NorFlashWriteBlocks (
1395+ Instance,
1396+ Lba,
1397+ BlockSize,
1398+ Instance->ShadowBuffer
1399+ );
1400+ if (EFI_ERROR (Status)) {
1401+ // Return one of the pre-approved error statuses
1402+ return EFI_DEVICE_ERROR;
1403+ }
1404+
1405+ return EFI_SUCCESS;
1406+}
1407+
1408+/**
1409+ Read JEDEC ID of NOR flash device.
1410+
1411+ @param[in] Instance NOR flash Instance of variable store region.
1412+ @param[out] JedecId JEDEC ID of NOR flash device.
1413+
1414+ @retval EFI_SUCCESS The write is completed.
1415+**/
1416+EFI_STATUS
1417+NorFlashReadID (
1418+ IN NOR_FLASH_INSTANCE *Instance,
1419+ OUT UINT8 JedecId[3]
1420+ )
1421+{
1422+ UINT32 val;
1423+ if (Instance == NULL || JedecId == NULL) {
1424+ return EFI_INVALID_PARAMETER;
1425+ }
1426+
1427+ val = SPINOR_OP_RDID << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |
1428+ CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS |
1429+ CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_3B << CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS;
1430+
1431+ if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {
1432+ return EFI_DEVICE_ERROR;
1433+ }
1434+
1435+ val = MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET);
1436+
1437+ // Manu.ID field
1438+ JedecId[0] = (UINT8) val;
1439+ // Type field
1440+ JedecId[1] = (UINT8) (val >> 8);
1441+ // Capacity field
1442+ JedecId[2] = (UINT8) (val >> 16);
1443+
1444+ DEBUG ((DEBUG_INFO,
1445+ "Nor flash detected, Jedec ID, Manu.Id=%x Type=%x Capacity=%x \n",
1446+ JedecId[0],JedecId[1],JedecId[2]));
1447+
1448+ return EFI_SUCCESS;
1449+}
1450diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
1451new file mode 100644
1452index 00000000..e720937e
1453--- /dev/null
1454+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h
1455@@ -0,0 +1,484 @@
1456+/** @file
1457+
1458+ Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
1459+
1460+ SPDX-License-Identifier: BSD-2-Clause-Patent
1461+
1462+**/
1463+
1464+#ifndef NOR_FLASH_DXE_H_
1465+#define NOR_FLASH_DXE_H_
1466+
1467+#include <Guid/EventGroup.h>
1468+#include <Library/DebugLib.h>
1469+#include <Library/IoLib.h>
1470+#include <Library/NorFlashPlatformLib.h>
1471+#include <PiDxe.h>
1472+#include <Protocol/BlockIo.h>
1473+#include <Protocol/DiskIo.h>
1474+#include <Protocol/FirmwareVolumeBlock.h>
1475+
1476+#include "CadenceQspiReg.h"
1477+
1478+#define NOR_FLASH_ERASE_RETRY 10
1479+
1480+#define GET_NOR_BLOCK_ADDRESS(BaseAddr, Lba, LbaSize) \
1481+ ((BaseAddr) + (UINTN)((Lba) * (LbaSize)))
1482+
1483+#define NOR_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r')
1484+#define INSTANCE_FROM_FVB_THIS(a) CR(a, NOR_FLASH_INSTANCE, FvbProtocol, \
1485+ NOR_FLASH_SIGNATURE)
1486+
1487+#define NOR_FLASH_POLL_FSR BIT0
1488+
1489+typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE;
1490+
1491+typedef EFI_STATUS (*NOR_FLASH_INITIALIZE) (NOR_FLASH_INSTANCE* Instance);
1492+
1493+#pragma pack(1)
1494+typedef struct {
1495+ VENDOR_DEVICE_PATH Vendor;
1496+ UINT8 Index;
1497+ EFI_DEVICE_PATH_PROTOCOL End;
1498+} NOR_FLASH_DEVICE_PATH;
1499+#pragma pack()
1500+
1501+struct _NOR_FLASH_INSTANCE {
1502+ UINT32 Signature;
1503+ EFI_HANDLE Handle;
1504+
1505+ BOOLEAN Initialized;
1506+ NOR_FLASH_INITIALIZE Initialize;
1507+
1508+ UINTN HostRegisterBaseAddress;
1509+ UINTN DeviceBaseAddress;
1510+ UINTN RegionBaseAddress;
1511+ UINTN Size;
1512+ UINTN BlockSize;
1513+ UINTN LastBlock;
1514+ EFI_LBA StartLba;
1515+ EFI_LBA OffsetLba;
1516+
1517+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol;
1518+ VOID* ShadowBuffer;
1519+
1520+ NOR_FLASH_DEVICE_PATH DevicePath;
1521+
1522+ UINT32 Flags;
1523+};
1524+
1525+typedef struct {
1526+ EFI_TPL OriginalTPL;
1527+ BOOLEAN InterruptsEnabled;
1528+} NOR_FLASH_LOCK_CONTEXT;
1529+
1530+/**
1531+ Lock all pending read/write to Nor flash device
1532+
1533+ @param[in] Context Nor flash device context structure.
1534+**/
1535+VOID
1536+EFIAPI
1537+NorFlashLock (
1538+ IN NOR_FLASH_LOCK_CONTEXT *Context
1539+ );
1540+
1541+/**
1542+ Unlock all pending read/write to Nor flash device
1543+
1544+ @param[in] Context Nor flash device context structure.
1545+**/
1546+VOID
1547+EFIAPI
1548+NorFlashUnlock (
1549+ IN NOR_FLASH_LOCK_CONTEXT *Context
1550+ );
1551+
1552+extern UINTN mFlashNvStorageVariableBase;
1553+
1554+/**
1555+ Create Nor flash Instance for given region.
1556+
1557+ @param[in] HostRegisterBase Base address of Nor flash controller.
1558+ @param[in] NorFlashDeviceBase Base address of flash device.
1559+ @param[in] NorFlashRegionBase Base address of flash region on device.
1560+ @param[in] NorFlashSize Size of flash region.
1561+ @param[in] Index Index of given flash region.
1562+ @param[in] BlockSize Block size of NOR flash device.
1563+ @param[in] HasVarStore Boolean set for VarStore on given region.
1564+ @param[out] NorFlashInstance Instance of given flash region.
1565+
1566+ @retval EFI_SUCCESS On successful creation of NOR flash instance.
1567+**/
1568+EFI_STATUS
1569+NorFlashCreateInstance (
1570+ IN UINTN HostRegisterBase,
1571+ IN UINTN NorFlashDeviceBase,
1572+ IN UINTN NorFlashRegionBase,
1573+ IN UINTN NorFlashSize,
1574+ IN UINT32 Index,
1575+ IN UINT32 BlockSize,
1576+ IN BOOLEAN HasVarStore,
1577+ OUT NOR_FLASH_INSTANCE** NorFlashInstance
1578+ );
1579+
1580+/**
1581+ Install Fv block on to variable store region
1582+
1583+ @param[in] Instance Instance of Nor flash variable region.
1584+
1585+ @retval EFI_SUCCESS The entry point is executed successfully.
1586+**/
1587+EFI_STATUS
1588+EFIAPI
1589+NorFlashFvbInitialize (
1590+ IN NOR_FLASH_INSTANCE* Instance
1591+ );
1592+
1593+/**
1594+ Check the integrity of firmware volume header.
1595+
1596+ @param[in] Instance Instance of Nor flash variable region.
1597+
1598+ @retval EFI_SUCCESS The firmware volume is consistent.
1599+ @retval EFI_NOT_FOUND The firmware volume has been corrupted.
1600+
1601+**/
1602+EFI_STATUS
1603+ValidateFvHeader (
1604+ IN NOR_FLASH_INSTANCE *Instance
1605+ );
1606+
1607+/**
1608+ Initialize the FV Header and Variable Store Header
1609+ to support variable operations.
1610+
1611+ @param[in] Instance Location to Initialize the headers
1612+
1613+ @retval EFI_SUCCESS Fv init is done
1614+
1615+**/
1616+EFI_STATUS
1617+InitializeFvAndVariableStoreHeaders (
1618+ IN NOR_FLASH_INSTANCE *Instance
1619+ );
1620+
1621+/**
1622+ Retrieves the attributes and current settings of the block.
1623+
1624+ @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
1625+
1626+ @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
1627+ current settings are returned.
1628+ Type EFI_FVB_ATTRIBUTES_2 is defined in
1629+ EFI_FIRMWARE_VOLUME_HEADER.
1630+
1631+ @retval EFI_SUCCESS The firmware volume attributes were returned.
1632+
1633+**/
1634+EFI_STATUS
1635+EFIAPI
1636+FvbGetAttributes(
1637+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
1638+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
1639+ );
1640+
1641+/**
1642+ Sets configurable firmware volume attributes and returns the
1643+ new settings of the firmware volume.
1644+
1645+
1646+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
1647+
1648+ @param[in, out] Attributes On input, Attributes is a pointer to
1649+ EFI_FVB_ATTRIBUTES_2 that contains the desired
1650+ firmware volume settings.
1651+ On successful return, it contains the new
1652+ settings of the firmware volume.
1653+
1654+ @retval EFI_UNSUPPORTED The firmware volume attributes are not supported.
1655+
1656+**/
1657+EFI_STATUS
1658+EFIAPI
1659+FvbSetAttributes(
1660+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
1661+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
1662+ );
1663+
1664+/**
1665+ Retrieves the base address of a memory-mapped firmware volume.
1666+ This function should be called only for memory-mapped firmware volumes.
1667+
1668+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
1669+
1670+ @param[out] Address Pointer to a caller-allocated
1671+ EFI_PHYSICAL_ADDRESS that, on successful
1672+ return from GetPhysicalAddress(), contains the
1673+ base address of the firmware volume.
1674+
1675+ @retval EFI_SUCCESS The firmware volume base address was returned.
1676+
1677+**/
1678+EFI_STATUS
1679+EFIAPI
1680+FvbGetPhysicalAddress(
1681+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
1682+ OUT EFI_PHYSICAL_ADDRESS *Address
1683+ );
1684+
1685+/**
1686+ Retrieves the size of the requested block.
1687+ It also returns the number of additional blocks with the identical size.
1688+ The GetBlockSize() function is used to retrieve the block map
1689+ (see EFI_FIRMWARE_VOLUME_HEADER).
1690+
1691+
1692+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
1693+
1694+ @param[in] Lba Indicates the block whose size to return
1695+
1696+ @param[out] BlockSize Pointer to a caller-allocated UINTN in which
1697+ the size of the block is returned.
1698+
1699+ @param[out] NumberOfBlocks Pointer to a caller-allocated UINTN in
1700+ which the number of consecutive blocks,
1701+ starting with Lba, is returned. All
1702+ blocks in this range have a size of
1703+ BlockSize.
1704+
1705+ @retval EFI_SUCCESS The firmware volume base address was returned.
1706+
1707+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
1708+
1709+**/
1710+EFI_STATUS
1711+EFIAPI
1712+FvbGetBlockSize(
1713+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
1714+ IN EFI_LBA Lba,
1715+ OUT UINTN *BlockSize,
1716+ OUT UINTN *NumberOfBlocks
1717+ );
1718+
1719+/**
1720+ Reads the specified number of bytes into a buffer from the specified block.
1721+
1722+ The Read() function reads the requested number of bytes from the
1723+ requested block and stores them in the provided buffer.
1724+
1725+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
1726+
1727+ @param[in] Lba The starting logical block index from which to read
1728+
1729+ @param[in] Offset Offset into the block at which to begin reading.
1730+
1731+ @param[in, out] NumBytes Pointer to a UINTN.
1732+ At entry, *NumBytes contains the total size of the
1733+ buffer. *NumBytes should have a non zero value.
1734+ At exit, *NumBytes contains the total number of
1735+ bytes read.
1736+
1737+ @param[in out] Buffer Pointer to a caller-allocated buffer that will be
1738+ used to hold the data that is read.
1739+
1740+ @retval EFI_SUCCESS The firmware volume was read successfully, and
1741+ contents are in Buffer.
1742+
1743+ @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary.
1744+
1745+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
1746+ could not be read.
1747+
1748+**/
1749+EFI_STATUS
1750+EFIAPI
1751+FvbRead(
1752+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
1753+ IN EFI_LBA Lba,
1754+ IN UINTN Offset,
1755+ IN OUT UINTN *NumBytes,
1756+ IN OUT UINT8 *Buffer
1757+ );
1758+
1759+/**
1760+ Writes the specified number of bytes from the input buffer to the block.
1761+
1762+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
1763+
1764+ @param[in] Lba The starting logical block index to write to.
1765+
1766+ @param[in] Offset Offset into the block at which to begin writing.
1767+
1768+ @param[in, out] NumBytes The pointer to a UINTN.
1769+ At entry, *NumBytes contains the total size of the
1770+ buffer.
1771+ At exit, *NumBytes contains the total number of
1772+ bytes actually written.
1773+
1774+ @param[in] Buffer The pointer to a caller-allocated buffer that
1775+ contains the source for the write.
1776+
1777+ @retval EFI_SUCCESS The firmware volume was written successfully.
1778+
1779+**/
1780+EFI_STATUS
1781+EFIAPI
1782+FvbWrite(
1783+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
1784+ IN EFI_LBA Lba,
1785+ IN UINTN Offset,
1786+ IN OUT UINTN *NumBytes,
1787+ IN UINT8 *Buffer
1788+ );
1789+
1790+/**
1791+ Erases and initialises a firmware volume block.
1792+
1793+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
1794+
1795+ @param[in] ... The variable argument list is a list of tuples.
1796+ Each tuple describes a range of LBAs to erase
1797+ and consists of the following:
1798+ - An EFI_LBA that indicates the starting LBA
1799+ - A UINTN that indicates the number of blocks
1800+ to erase.
1801+
1802+ The list is terminated with an
1803+ EFI_LBA_LIST_TERMINATOR.
1804+
1805+ @retval EFI_SUCCESS The erase request successfully completed.
1806+
1807+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
1808+ state.
1809+
1810+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
1811+ and could not be written.
1812+ The firmware device may have been partially
1813+ erased.
1814+
1815+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
1816+ argument list do not exist in the firmware
1817+ volume.
1818+
1819+**/
1820+EFI_STATUS
1821+EFIAPI
1822+FvbEraseBlocks(
1823+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
1824+ ...
1825+ );
1826+
1827+/**
1828+ This function unlock and erase an entire NOR Flash block.
1829+
1830+ @param[in] Instance NOR flash Instance of variable store region.
1831+ @param[in] BlockAddress Block address within the variable store region.
1832+
1833+ @retval EFI_SUCCESS The erase and unlock successfully completed.
1834+**/
1835+EFI_STATUS
1836+NorFlashUnlockAndEraseSingleBlock (
1837+ IN NOR_FLASH_INSTANCE *Instance,
1838+ IN UINTN BlockAddress
1839+ );
1840+
1841+/**
1842+ Write a full or portion of a block.
1843+
1844+ @param[in] Instance NOR flash Instance of variable store region.
1845+ @param[in] Lba The starting logical block index to write to.
1846+ @param[in] Offset Offset into the block at which to begin writing.
1847+ @param[in,out] NumBytes The total size of the buffer.
1848+ @param[in] Buffer The pointer to a caller-allocated buffer that
1849+ contains the source for the write.
1850+
1851+ @retval EFI_SUCCESS The write is completed.
1852+**/
1853+EFI_STATUS
1854+NorFlashWriteSingleBlock (
1855+ IN NOR_FLASH_INSTANCE *Instance,
1856+ IN EFI_LBA Lba,
1857+ IN UINTN Offset,
1858+ IN OUT UINTN *NumBytes,
1859+ IN UINT8 *Buffer
1860+ );
1861+
1862+/**
1863+ Write a full block.
1864+
1865+ @param[in] Instance NOR flash Instance of variable store region.
1866+ @param[in] Lba The starting logical block index to write to.
1867+ @param[in] BufferSizeInBytes The number of bytes to write.
1868+ @param[in] Buffer The pointer to a caller-allocated buffer that
1869+ contains the source for the write.
1870+
1871+ @retval EFI_SUCCESS The write is completed.
1872+**/
1873+EFI_STATUS
1874+NorFlashWriteBlocks (
1875+ IN NOR_FLASH_INSTANCE *Instance,
1876+ IN EFI_LBA Lba,
1877+ IN UINTN BufferSizeInBytes,
1878+ IN VOID *Buffer
1879+ );
1880+
1881+/**
1882+ Read a full block.
1883+
1884+ @param[in] Instance NOR flash Instance of variable store region.
1885+ @param[in] Lba The starting logical block index to read from.
1886+ @param[in] BufferSizeInBytes The number of bytes to read.
1887+ @param[out] Buffer The pointer to a caller-allocated buffer that
1888+ should be copied with read data.
1889+
1890+ @retval EFI_SUCCESS The read is completed.
1891+**/
1892+EFI_STATUS
1893+NorFlashReadBlocks (
1894+ IN NOR_FLASH_INSTANCE *Instance,
1895+ IN EFI_LBA Lba,
1896+ IN UINTN BufferSizeInBytes,
1897+ OUT VOID *Buffer
1898+ );
1899+
1900+/**
1901+ Read from nor flash.
1902+
1903+ @param[in] Instance NOR flash Instance of variable store region.
1904+ @param[in] Lba The starting logical block index to read from.
1905+ @param[in] Offset Offset into the block at which to begin reading.
1906+ @param[in] BufferSizeInBytes The number of bytes to read.
1907+ @param[out] Buffer The pointer to a caller-allocated buffer that
1908+ should copied with read data.
1909+
1910+ @retval EFI_SUCCESS The read is completed.
1911+**/
1912+EFI_STATUS
1913+NorFlashRead (
1914+ IN NOR_FLASH_INSTANCE *Instance,
1915+ IN EFI_LBA Lba,
1916+ IN UINTN Offset,
1917+ IN UINTN BufferSizeInBytes,
1918+ OUT VOID *Buffer
1919+ );
1920+
1921+/**
1922+ Read JEDEC ID of NOR flash device.
1923+
1924+ @param[in] Instance NOR flash Instance of variable store region.
1925+ @param[out] JedecId JEDEC ID of NOR flash device.
1926+
1927+ @retval EFI_SUCCESS The write is completed.
1928+**/
1929+EFI_STATUS
1930+NorFlashReadID (
1931+ IN NOR_FLASH_INSTANCE *Instance,
1932+ OUT UINT8 JedecId[3]
1933+ );
1934+
1935+#define SPINOR_OP_WREN 0x06 // Write enable
1936+#define SPINOR_OP_BE_4K 0x20 // Erase 4KiB block
1937+#define SPINOR_OP_RDID 0x9f // Read JEDEC ID
1938+
1939+#endif /* NOR_FLASH_DXE_H_ */
1940diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c
1941new file mode 100644
1942index 00000000..edd84c07
1943--- /dev/null
1944+++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c
1945@@ -0,0 +1,573 @@
1946+/** @file
1947+
1948+ Copyright (c) 2023, ARM Limited. All rights reserved.<BR>
1949+
1950+ SPDX-License-Identifier: BSD-2-Clause-Patent
1951+
1952+**/
1953+
1954+#include <Guid/VariableFormat.h>
1955+#include <Guid/SystemNvDataGuid.h>
1956+
1957+#include <Library/BaseLib.h>
1958+#include <Library/BaseMemoryLib.h>
1959+#include <Library/MemoryAllocationLib.h>
1960+#include <Library/PcdLib.h>
1961+#include <Library/UefiBootServicesTableLib.h>
1962+#include <Library/UefiLib.h>
1963+
1964+#include <PiDxe.h>
1965+
1966+#include "NorFlash.h"
1967+
1968+UINTN mFlashNvStorageVariableBase;
1969+
1970+/**
1971+ Initialize the FV Header and Variable Store Header
1972+ to support variable operations.
1973+
1974+ @param[in] Instance Location to initialise the headers.
1975+
1976+ @retval EFI_SUCCESS Fv init is done.
1977+
1978+**/
1979+EFI_STATUS
1980+InitializeFvAndVariableStoreHeaders (
1981+ IN NOR_FLASH_INSTANCE *Instance
1982+ )
1983+{
1984+ EFI_STATUS Status;
1985+ VOID* Headers;
1986+ UINTN HeadersLength;
1987+ EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
1988+ VARIABLE_STORE_HEADER *VariableStoreHeader;
1989+
1990+ if (!Instance->Initialized && Instance->Initialize) {
1991+ Instance->Initialize (Instance);
1992+ }
1993+
1994+ HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
1995+ sizeof (EFI_FV_BLOCK_MAP_ENTRY) +
1996+ sizeof (VARIABLE_STORE_HEADER);
1997+ Headers = AllocateZeroPool (HeadersLength);
1998+
1999+ FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;
2000+ CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
2001+ FirmwareVolumeHeader->FvLength =
2002+ PcdGet32 (PcdFlashNvStorageVariableSize) +
2003+ PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
2004+ PcdGet32 (PcdFlashNvStorageFtwSpareSize);
2005+ FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
2006+ FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP |
2007+ EFI_FVB2_READ_STATUS |
2008+ EFI_FVB2_STICKY_WRITE |
2009+ EFI_FVB2_MEMORY_MAPPED |
2010+ EFI_FVB2_ERASE_POLARITY |
2011+ EFI_FVB2_WRITE_STATUS |
2012+ EFI_FVB2_WRITE_ENABLED_CAP;
2013+
2014+ FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
2015+ sizeof (EFI_FV_BLOCK_MAP_ENTRY);
2016+ FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
2017+ FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->LastBlock + 1;
2018+ FirmwareVolumeHeader->BlockMap[0].Length = Instance->BlockSize;
2019+ FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
2020+ FirmwareVolumeHeader->BlockMap[1].Length = 0;
2021+ FirmwareVolumeHeader->Checksum = CalculateCheckSum16 (
2022+ (UINT16*)FirmwareVolumeHeader,
2023+ FirmwareVolumeHeader->HeaderLength);
2024+
2025+ VariableStoreHeader = (VOID *)((UINTN)Headers +
2026+ FirmwareVolumeHeader->HeaderLength);
2027+ CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid);
2028+ VariableStoreHeader->Size = PcdGet32 (PcdFlashNvStorageVariableSize) -
2029+ FirmwareVolumeHeader->HeaderLength;
2030+ VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
2031+ VariableStoreHeader->State = VARIABLE_STORE_HEALTHY;
2032+
2033+ // Install the combined super-header in the NorFlash
2034+ Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers);
2035+
2036+ FreePool (Headers);
2037+ return Status;
2038+}
2039+
2040+/**
2041+ Check the integrity of firmware volume header.
2042+
2043+ @param[in] Instance Instance of Nor flash variable region.
2044+
2045+ @retval EFI_SUCCESS The firmware volume is consistent.
2046+ @retval EFI_NOT_FOUND The firmware volume has been corrupted.
2047+
2048+**/
2049+EFI_STATUS
2050+ValidateFvHeader (
2051+ IN NOR_FLASH_INSTANCE *Instance
2052+ )
2053+{
2054+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
2055+ VARIABLE_STORE_HEADER *VariableStoreHeader;
2056+ UINTN VariableStoreLength;
2057+ UINTN FvLength;
2058+
2059+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Instance->RegionBaseAddress;
2060+
2061+ FvLength = PcdGet32 (PcdFlashNvStorageVariableSize) +
2062+ PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
2063+ PcdGet32 (PcdFlashNvStorageFtwSpareSize);
2064+
2065+ if ((FwVolHeader->Revision != EFI_FVH_REVISION)
2066+ || (FwVolHeader->Signature != EFI_FVH_SIGNATURE)
2067+ || (FwVolHeader->FvLength != FvLength)
2068+ )
2069+ {
2070+ DEBUG ((DEBUG_ERROR, "%a: No Firmware Volume header present\n",
2071+ __FUNCTION__));
2072+ return EFI_NOT_FOUND;
2073+ }
2074+
2075+ // Check the Firmware Volume Guid
2076+ if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) {
2077+ DEBUG ((DEBUG_ERROR, "%a: Firmware Volume Guid non-compatible\n",
2078+ __FUNCTION__));
2079+ return EFI_NOT_FOUND;
2080+ }
2081+
2082+ VariableStoreHeader = (VOID *)((UINTN)FwVolHeader +
2083+ FwVolHeader->HeaderLength);
2084+
2085+ // Check the Variable Store Guid
2086+ if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
2087+ !CompareGuid (&VariableStoreHeader->Signature,
2088+ &gEfiAuthenticatedVariableGuid)) {
2089+ DEBUG ((DEBUG_ERROR, "%a: Variable Store Guid non-compatible\n",
2090+ __FUNCTION__));
2091+ return EFI_NOT_FOUND;
2092+ }
2093+
2094+ VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) -
2095+ FwVolHeader->HeaderLength;
2096+ if (VariableStoreHeader->Size != VariableStoreLength) {
2097+ DEBUG ((DEBUG_ERROR, "%a: Variable Store Length does not match\n",
2098+ __FUNCTION__));
2099+ return EFI_NOT_FOUND;
2100+ }
2101+ return EFI_SUCCESS;
2102+}
2103+
2104+/**
2105+ Retrieves the attributes and current settings of the block.
2106+
2107+ @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
2108+
2109+ @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
2110+ current settings are returned.
2111+ Type EFI_FVB_ATTRIBUTES_2 is defined in
2112+ EFI_FIRMWARE_VOLUME_HEADER.
2113+
2114+ @retval EFI_SUCCESS The firmware volume attributes were returned.
2115+
2116+**/
2117+EFI_STATUS
2118+EFIAPI
2119+FvbGetAttributes(
2120+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
2121+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
2122+ )
2123+{
2124+ EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
2125+
2126+ FlashFvbAttributes = EFI_FVB2_READ_ENABLED_CAP | EFI_FVB2_READ_STATUS |
2127+ EFI_FVB2_WRITE_ENABLED_CAP | EFI_FVB2_WRITE_STATUS |
2128+ EFI_FVB2_STICKY_WRITE | EFI_FVB2_MEMORY_MAPPED |
2129+ EFI_FVB2_ERASE_POLARITY;
2130+
2131+ *Attributes = FlashFvbAttributes;
2132+
2133+ DEBUG ((DEBUG_INFO, "FvbGetAttributes(0x%X)\n", *Attributes));
2134+
2135+ return EFI_SUCCESS;
2136+}
2137+
2138+/**
2139+ Sets configurable firmware volume attributes and returns the
2140+ new settings of the firmware volume.
2141+
2142+
2143+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
2144+
2145+ @param[in, out] Attributes On input, Attributes is a pointer to
2146+ EFI_FVB_ATTRIBUTES_2 that contains the desired
2147+ firmware volume settings.
2148+ On successful return, it contains the new
2149+ settings of the firmware volume.
2150+
2151+ @retval EFI_UNSUPPORTED The firmware volume attributes are not supported.
2152+
2153+**/
2154+EFI_STATUS
2155+EFIAPI
2156+FvbSetAttributes(
2157+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
2158+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
2159+ )
2160+{
2161+ DEBUG ((DEBUG_INFO, "FvbSetAttributes(0x%X) is not supported\n",
2162+ *Attributes));
2163+ return EFI_UNSUPPORTED;
2164+}
2165+
2166+/**
2167+ Retrieves the base address of a memory-mapped firmware volume.
2168+ This function should be called only for memory-mapped firmware volumes.
2169+
2170+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
2171+
2172+ @param[out] Address Pointer to a caller-allocated
2173+ EFI_PHYSICAL_ADDRESS that, on successful
2174+ return from GetPhysicalAddress(), contains the
2175+ base address of the firmware volume.
2176+
2177+ @retval EFI_SUCCESS The firmware volume base address was returned.
2178+
2179+**/
2180+EFI_STATUS
2181+EFIAPI
2182+FvbGetPhysicalAddress (
2183+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
2184+ OUT EFI_PHYSICAL_ADDRESS *Address
2185+ )
2186+{
2187+ NOR_FLASH_INSTANCE *Instance;
2188+
2189+ Instance = INSTANCE_FROM_FVB_THIS (This);
2190+
2191+ DEBUG ((DEBUG_INFO, "FvbGetPhysicalAddress(BaseAddress=0x%08x)\n",
2192+ Instance->RegionBaseAddress));
2193+
2194+ ASSERT(Address != NULL);
2195+
2196+ *Address = Instance->RegionBaseAddress;
2197+ return EFI_SUCCESS;
2198+}
2199+
2200+/**
2201+ Retrieves the size of the requested block.
2202+ It also returns the number of additional blocks with the identical size.
2203+ The GetBlockSize() function is used to retrieve the block map
2204+ (see EFI_FIRMWARE_VOLUME_HEADER).
2205+
2206+
2207+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
2208+
2209+ @param[in] Lba Indicates the block whose size to return
2210+
2211+ @param[out] BlockSize Pointer to a caller-allocated UINTN in which
2212+ the size of the block is returned.
2213+
2214+ @param[out] NumberOfBlocks Pointer to a caller-allocated UINTN in
2215+ which the number of consecutive blocks,
2216+ starting with Lba, is returned. All
2217+ blocks in this range have a size of
2218+ BlockSize.
2219+
2220+ @retval EFI_SUCCESS The firmware volume base address was returned.
2221+
2222+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
2223+
2224+**/
2225+EFI_STATUS
2226+EFIAPI
2227+FvbGetBlockSize (
2228+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
2229+ IN EFI_LBA Lba,
2230+ OUT UINTN *BlockSize,
2231+ OUT UINTN *NumberOfBlocks
2232+ )
2233+{
2234+ EFI_STATUS Status;
2235+ NOR_FLASH_INSTANCE *Instance;
2236+
2237+ Instance = INSTANCE_FROM_FVB_THIS (This);
2238+
2239+ DEBUG ((DEBUG_INFO,
2240+ "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n", Lba,
2241+ Instance->BlockSize, Instance->LastBlock));
2242+
2243+ if (Lba > Instance->LastBlock) {
2244+ DEBUG ((DEBUG_ERROR,
2245+ "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (%ld).\n",
2246+ Lba, Instance->LastBlock));
2247+ Status = EFI_INVALID_PARAMETER;
2248+ } else {
2249+ // This is easy because in this platform each NorFlash device has equal sized blocks.
2250+ *BlockSize = (UINTN) Instance->BlockSize;
2251+ *NumberOfBlocks = (UINTN) (Instance->LastBlock - Lba + 1);
2252+
2253+ DEBUG ((DEBUG_INFO,
2254+ "FvbGetBlockSize: *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n", *BlockSize,
2255+ *NumberOfBlocks));
2256+
2257+ Status = EFI_SUCCESS;
2258+ }
2259+
2260+ return Status;
2261+}
2262+
2263+/**
2264+ Reads the specified number of bytes into a buffer from the specified block.
2265+
2266+ The Read() function reads the requested number of bytes from the
2267+ requested block and stores them in the provided buffer.
2268+
2269+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
2270+
2271+ @param[in] Lba The starting logical block index from which to read
2272+
2273+ @param[in] Offset Offset into the block at which to begin reading.
2274+
2275+ @param[in, out] NumBytes Pointer to a UINTN.
2276+ At entry, *NumBytes contains the total size of the
2277+ buffer. *NumBytes should have a non zero value.
2278+ At exit, *NumBytes contains the total number of
2279+ bytes read.
2280+
2281+ @param[in, out] Buffer Pointer to a caller-allocated buffer that will be
2282+ used to hold the data that is read.
2283+
2284+ @retval EFI_SUCCESS The firmware volume was read successfully, and
2285+ contents are in Buffer.
2286+
2287+ @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary.
2288+
2289+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly and
2290+ could not be read.
2291+
2292+**/
2293+EFI_STATUS
2294+EFIAPI
2295+FvbRead (
2296+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
2297+ IN EFI_LBA Lba,
2298+ IN UINTN Offset,
2299+ IN OUT UINTN *NumBytes,
2300+ IN OUT UINT8 *Buffer
2301+ )
2302+{
2303+ EFI_STATUS Status;
2304+ UINTN BlockSize;
2305+ NOR_FLASH_INSTANCE *Instance;
2306+
2307+ Instance = INSTANCE_FROM_FVB_THIS (This);
2308+
2309+ DEBUG ((DEBUG_INFO,
2310+ "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n",
2311+ Instance->StartLba + Lba, Offset, *NumBytes, Buffer));
2312+
2313+ if (!Instance->Initialized && Instance->Initialize) {
2314+ Instance->Initialize(Instance);
2315+ }
2316+
2317+ BlockSize = Instance->BlockSize;
2318+
2319+ DEBUG ((DEBUG_INFO,
2320+ "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n",
2321+ Offset, *NumBytes, BlockSize ));
2322+
2323+ // The read must not span block boundaries.
2324+ // We need to check each variable individually because adding two large
2325+ // values together overflows.
2326+ if (Offset >= BlockSize ||
2327+ *NumBytes > BlockSize ||
2328+ (Offset + *NumBytes) > BlockSize) {
2329+ DEBUG ((DEBUG_ERROR,
2330+ "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
2331+ Offset, *NumBytes, BlockSize ));
2332+ return EFI_BAD_BUFFER_SIZE;
2333+ }
2334+
2335+ // We must have some bytes to read
2336+ if (*NumBytes == 0) {
2337+ return EFI_BAD_BUFFER_SIZE;
2338+ }
2339+
2340+ // Decide if we are doing full block reads or not.
2341+ if (*NumBytes % BlockSize != 0) {
2342+ Status = NorFlashRead (Instance, Instance->StartLba + Lba, Offset,
2343+ *NumBytes, Buffer);
2344+ } else {
2345+ // Read NOR Flash data into shadow buffer
2346+ Status = NorFlashReadBlocks (Instance, Instance->StartLba + Lba,
2347+ BlockSize, Buffer);
2348+ }
2349+ if (EFI_ERROR (Status)) {
2350+ // Return one of the pre-approved error statuses
2351+ return EFI_DEVICE_ERROR;
2352+ }
2353+ return EFI_SUCCESS;
2354+}
2355+
2356+/**
2357+ Writes the specified number of bytes from the input buffer to the block.
2358+
2359+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
2360+
2361+ @param[in] Lba The starting logical block index to write to.
2362+
2363+ @param[in] Offset Offset into the block at which to begin writing.
2364+
2365+ @param[in, out] NumBytes The pointer to a UINTN.
2366+ At entry, *NumBytes contains the total size of the
2367+ buffer.
2368+ At exit, *NumBytes contains the total number of
2369+ bytes actually written.
2370+
2371+ @param[in] Buffer The pointer to a caller-allocated buffer that
2372+ contains the source for the write.
2373+
2374+ @retval EFI_SUCCESS The firmware volume was written successfully.
2375+
2376+**/
2377+EFI_STATUS
2378+EFIAPI
2379+FvbWrite (
2380+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
2381+ IN EFI_LBA Lba,
2382+ IN UINTN Offset,
2383+ IN OUT UINTN *NumBytes,
2384+ IN UINT8 *Buffer
2385+ )
2386+{
2387+ NOR_FLASH_INSTANCE *Instance;
2388+
2389+ Instance = INSTANCE_FROM_FVB_THIS (This);
2390+
2391+ return NorFlashWriteSingleBlock (Instance, Instance->StartLba + Lba, Offset,
2392+ NumBytes, Buffer);
2393+}
2394+
2395+/**
2396+ Erases and initialises a firmware volume block.
2397+
2398+ @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
2399+
2400+ @param[in] ... The variable argument list is a list of tuples.
2401+ Each tuple describes a range of LBAs to erase
2402+ and consists of the following:
2403+ - An EFI_LBA that indicates the starting LBA
2404+ - A UINTN that indicates the number of blocks
2405+ to erase.
2406+
2407+ The list is terminated with an
2408+ EFI_LBA_LIST_TERMINATOR.
2409+
2410+ @retval EFI_SUCCESS The erase request successfully completed.
2411+
2412+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled
2413+ state.
2414+
2415+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly
2416+ and could not be written.
2417+ The firmware device may have been partially
2418+ erased.
2419+
2420+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable
2421+ argument list do not exist in the firmware
2422+ volume.
2423+
2424+**/
2425+EFI_STATUS
2426+EFIAPI
2427+FvbEraseBlocks (
2428+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
2429+ ...
2430+ )
2431+{
2432+ EFI_STATUS Status;
2433+ VA_LIST Args;
2434+ UINTN BlockAddress; // Physical address of Lba to erase
2435+ EFI_LBA StartingLba; // Lba from which we start erasing
2436+ UINTN NumOfLba; // Number of Lba blocks to erase
2437+ NOR_FLASH_INSTANCE *Instance;
2438+
2439+ Instance = INSTANCE_FROM_FVB_THIS (This);
2440+
2441+ DEBUG ((DEBUG_INFO, "FvbEraseBlocks()\n"));
2442+
2443+ Status = EFI_SUCCESS;
2444+
2445+ // Before erasing, check the entire list of parameters to ensure
2446+ // all specified blocks are valid
2447+
2448+ VA_START (Args, This);
2449+ do {
2450+ // Get the Lba from which we start erasing
2451+ StartingLba = VA_ARG (Args, EFI_LBA);
2452+
2453+ // Have we reached the end of the list?
2454+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
2455+ break;
2456+ }
2457+
2458+ // How many Lba blocks are we requested to erase?
2459+ NumOfLba = VA_ARG (Args, UINT32);
2460+
2461+ // All blocks must be within range
2462+ DEBUG ((DEBUG_INFO,
2463+ "FvbEraseBlocks: Check if: ( StartingLba=%ld + NumOfLba=%d - 1 ) > LastBlock=%ld.\n",
2464+ Instance->StartLba + StartingLba, NumOfLba, Instance->LastBlock));
2465+ if (NumOfLba == 0 ||
2466+ (Instance->StartLba + StartingLba + NumOfLba - 1) >
2467+ Instance->LastBlock) {
2468+ VA_END (Args);
2469+ DEBUG ((DEBUG_ERROR,
2470+ "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"));
2471+ return EFI_INVALID_PARAMETER;
2472+ }
2473+ } while (TRUE);
2474+ VA_END (Args);
2475+
2476+ VA_START (Args, This);
2477+ do {
2478+ // Get the Lba from which we start erasing
2479+ StartingLba = VA_ARG (Args, EFI_LBA);
2480+
2481+ // Have we reached the end of the list?
2482+ if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
2483+ // Exit the while loop
2484+ break;
2485+ }
2486+
2487+ // How many Lba blocks are we requested to erase?
2488+ NumOfLba = VA_ARG (Args, UINT32);
2489+
2490+ // Go through each one and erase it
2491+ while (NumOfLba > 0) {
2492+
2493+ // Get the physical address of Lba to erase
2494+ BlockAddress = GET_NOR_BLOCK_ADDRESS (
2495+ Instance->RegionBaseAddress,
2496+ Instance->StartLba + StartingLba,
2497+ Instance->BlockSize
2498+ );
2499+
2500+ // Erase it
2501+ DEBUG ((DEBUG_INFO, "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n",
2502+ Instance->StartLba + StartingLba, BlockAddress));
2503+ Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
2504+ if (EFI_ERROR(Status)) {
2505+ VA_END (Args);
2506+ return EFI_DEVICE_ERROR;
2507+ }
2508+
2509+ // Move to the next Lba
2510+ StartingLba++;
2511+ NumOfLba--;
2512+ }
2513+ } while (TRUE);
2514+ VA_END (Args);
2515+
2516+ return Status;
2517+
2518+}
2519diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dec b/Platform/ARM/N1Sdp/N1SdpPlatform.dec
2520index 16937197..986a078f 100644
2521--- a/Platform/ARM/N1Sdp/N1SdpPlatform.dec
2522+++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dec
2523@@ -1,7 +1,7 @@
2524 ## @file
2525 # Describes the N1Sdp configuration.
2526 #
2527-# Copyright (c) 2021, ARM Limited. All rights reserved.<BR>
2528+# Copyright (c) 2021-2022, ARM Limited. All rights reserved.<BR>
2529 #
2530 # SPDX-License-Identifier: BSD-2-Clause-Patent
2531 ##
2532@@ -89,3 +89,6 @@
2533 # unmapped reserved region results in a DECERR response.
2534 #
2535 gArmN1SdpTokenSpaceGuid.PcdCsComponentSize|0x1000|UINT32|0x00000049
2536+
2537+ # Base address of Cadence QSPI controller configuration registers
2538+ gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress|0x1C0C0000|UINT32|0x0000004A