From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 9535D74003C for ; Thu, 16 Nov 2023 11:46:13 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=3PRVYwzcS5UP/UOJ+OubcIGEbJh8p4cJxseKLtntEDw=; c=relaxed/simple; d=groups.io; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding; s=20140610; t=1700135172; v=1; b=JE4809cN0FxEbLO5IpsXGtwLc1/RgrdpDESbwfAM11BlbVwIR9drzZH86j33TKNZcoiF62IK DU/02y1iGf0siGIpu53QBxR1UFbciSTLUjaOsJmlc4jzU3pMuxF9CNvfQtZvQ2bYWyfp9NAzrUP 5Qaf9NW7BIphxSreGUZ+3GIQ= X-Received: by 127.0.0.2 with SMTP id 7mDZYY7687511x7iEsuHTctJ; Thu, 16 Nov 2023 03:46:12 -0800 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web11.4942.1700135171466269171 for ; Thu, 16 Nov 2023 03:46:11 -0800 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 2D63F1688; Thu, 16 Nov 2023 03:46:57 -0800 (PST) X-Received: from usa.arm.com (a077434.blr.arm.com [10.162.17.62]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id B2E983F7B4; Thu, 16 Nov 2023 03:46:08 -0800 (PST) From: "sahil" To: devel@edk2.groups.io Cc: Ard Biesheuvel , Leif Lindholm , Sami Mujawar , Sahil Subject: [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver for N1Sdp Date: Thu, 16 Nov 2023 17:15:52 +0530 Message-Id: <20231116114554.4055517-4-sahil@arm.com> In-Reply-To: <20231116114554.4055517-1-sahil@arm.com> References: <20231116114554.4055517-1-sahil@arm.com> MIME-Version: 1.0 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,sahil@arm.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: VKhWr26dXdIJIAKRiJW2nPVBx7686176AA= Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=JE4809cN; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=arm.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io Add NOR flash DXE driver, this brings up NV storage on QSPI's flash device using FVB protocol. Signed-off-by: sahil --- 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/N1Sd= pPlatform.dec index 16937197b8e8..67b5f4c871b6 100644 --- a/Platform/ARM/N1Sdp/N1SdpPlatform.dec +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dec @@ -1,7 +1,7 @@ ## @file=0D # Describes the N1Sdp configuration.=0D #=0D -# Copyright (c) 2021, ARM Limited. All rights reserved.
=0D +# Copyright (c) 2021-2023, ARM Limited. All rights reserved.
=0D #=0D # SPDX-License-Identifier: BSD-2-Clause-Patent=0D ##=0D @@ -89,3 +89,6 @@ # unmapped reserved region results in a DECERR response.=0D #=0D gArmN1SdpTokenSpaceGuid.PcdCsComponentSize|0x1000|UINT32|0x00000049=0D +=0D + # Base address of Cadence QSPI controller configuration registers=0D + gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress|0x1C0C0000|UINT3= 2|0x0000004A=0D 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=0D +# NOR flash DXE=0D +#=0D +# Copyright (c) 2023, ARM Limited. All rights reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x0001001B=0D + BASE_NAME =3D CadenceQspiDxe=0D + FILE_GUID =3D CC8A9713-4442-4A6C-B389-8B46490A0641= =0D + MODULE_TYPE =3D DXE_RUNTIME_DRIVER=0D + VERSION_STRING =3D 0.1=0D + ENTRY_POINT =3D NorFlashInitialise=0D +=0D +[Sources]=0D + CadenceQspiDxe.c=0D + CadenceQspiReg.h=0D + NorFlash.c=0D + NorFlash.h=0D + NorFlashFvb.c=0D +=0D +[Packages]=0D + EmbeddedPkg/EmbeddedPkg.dec=0D + MdeModulePkg/MdeModulePkg.dec=0D + MdePkg/MdePkg.dec=0D + Platform/ARM/ARM.dec=0D + Platform/ARM/N1Sdp/N1SdpPlatform.dec=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + BaseMemoryLib=0D + DebugLib=0D + DevicePathLib=0D + DxeServicesTableLib=0D + HobLib=0D + IoLib=0D + MemoryAllocationLib=0D + NorFlashInfoLib=0D + NorFlashPlatformLib=0D + TimerLib=0D + UefiBootServicesTableLib=0D + UefiDriverEntryPoint=0D + UefiLib=0D + UefiRuntimeLib=0D + UefiRuntimeServicesTableLib=0D +=0D +[Guids]=0D + gEdkiiNvVarStoreFormattedGuid=0D + gEfiAuthenticatedVariableGuid=0D + gEfiEventVirtualAddressChangeGuid=0D + gEfiSystemNvDataFvGuid=0D + gEfiVariableGuid=0D + gEfiGlobalVariableGuid=0D +=0D +[Protocols]=0D + gEfiDevicePathProtocolGuid=0D + gEfiFirmwareVolumeBlockProtocolGuid=0D +=0D +[FixedPcd]=0D + gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase=0D + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize=0D +=0D +[Depex]=0D + gEfiCpuArchProtocolGuid=0D diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h b/P= latform/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=0D +=0D + Copyright (c) 2023, ARM Limited. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef CADENCE_QSPI_REG_H_=0D +#define CADENCE_QSPI_REG_H_=0D +=0D +// QSPI Controller defines=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET 0x90=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE 0x01=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE 0x01=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS 19=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS 16=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT 0x02=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS 24=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE 0x01=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_BYTE_3B 0x02=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS 23=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS 20=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C 0x8=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_BIT_POS 7=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES(x) ((x - 1) << CDNS_Q= SPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS)=0D +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES(x) ((x - 1) << CDNS_Q= SPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS)=0D +=0D +#define CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET 0xA0=0D +=0D +#define CDNS_QSPI_FLASH_CMD_ADDR_REG_OFFSET 0x94=0D +=0D +#endif /* CADENCE_QSPI_REG_H_ */=0D diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h b/Platfor= m/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=0D +=0D + Copyright (c) 2023, ARM Limited. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef NOR_FLASH_DXE_H_=0D +#define NOR_FLASH_DXE_H_=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "CadenceQspiReg.h"=0D +=0D +#define NOR_FLASH_ERASE_RETRY 10=0D +=0D +#define GET_NOR_BLOCK_ADDRESS(BaseAddr, Lba, LbaSize) \=0D + ((BaseAddr) + (UINTN)((Lba) * (LbaSi= ze)))=0D +=0D +#define NOR_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r')=0D +#define INSTANCE_FROM_FVB_THIS(a) CR(a, NOR_FLASH_INSTANCE, FvbProtocol, = \=0D + NOR_FLASH_SIGNATURE)=0D +=0D +#define NOR_FLASH_POLL_FSR BIT0=0D +=0D +typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE;=0D +=0D +typedef EFI_STATUS (*NOR_FLASH_INITIALIZE) (=0D + NOR_FLASH_INSTANCE *Instance=0D + );=0D +=0D +#pragma pack(1)=0D +typedef struct {=0D + VENDOR_DEVICE_PATH Vendor;=0D + UINT8 Index;=0D + EFI_DEVICE_PATH_PROTOCOL End;=0D +} NOR_FLASH_DEVICE_PATH;=0D +#pragma pack()=0D +=0D +struct _NOR_FLASH_INSTANCE {=0D + UINT32 Signature;=0D + EFI_HANDLE Handle;=0D +=0D + BOOLEAN Initialized;=0D + NOR_FLASH_INITIALIZE Initialize;=0D +=0D + UINTN HostRegisterBaseAddress;=0D + UINTN DeviceBaseAddress;=0D + UINTN RegionBaseAddress;=0D + UINTN Size;=0D + UINTN BlockSize;=0D + UINTN LastBlock;=0D + EFI_LBA StartLba;=0D + EFI_LBA OffsetLba;=0D +=0D + EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol;=0D + VOID *ShadowBuffer;=0D +=0D + NOR_FLASH_DEVICE_PATH DevicePath;=0D +=0D + UINT32 Flags;=0D +};=0D +=0D +typedef struct {=0D + EFI_TPL OriginalTPL;=0D + BOOLEAN InterruptsEnabled;=0D +} NOR_FLASH_LOCK_CONTEXT;=0D +=0D +/**=0D + Lock all pending read/write to Nor flash device=0D +=0D + @param[in] Context Nor flash device context structure.=0D +**/=0D +VOID=0D +EFIAPI=0D +NorFlashLock (=0D + IN NOR_FLASH_LOCK_CONTEXT *Context=0D + );=0D +=0D +/**=0D + Unlock all pending read/write to Nor flash device=0D +=0D + @param[in] Context Nor flash device context structure.=0D +**/=0D +VOID=0D +EFIAPI=0D +NorFlashUnlock (=0D + IN NOR_FLASH_LOCK_CONTEXT *Context=0D + );=0D +=0D +extern UINTN mFlashNvStorageVariableBase;=0D +=0D +/**=0D + Create Nor flash Instance for given region.=0D +=0D + @param[in] HostRegisterBase Base address of Nor flash controller= .=0D + @param[in] NorFlashDeviceBase Base address of flash device.=0D + @param[in] NorFlashRegionBase Base address of flash region on devi= ce.=0D + @param[in] NorFlashSize Size of flash region.=0D + @param[in] Index Index of given flash region.=0D + @param[in] BlockSize Block size of NOR flash device.=0D + @param[in] HasVarStore Boolean set for VarStore on given re= gion.=0D + @param[out] NorFlashInstance Instance of given flash region.=0D +=0D + @retval EFI_SUCCESS On successful creation of NOR flash = instance.=0D +**/=0D +EFI_STATUS=0D +NorFlashCreateInstance (=0D + IN UINTN HostRegisterBase,=0D + IN UINTN NorFlashDeviceBase,=0D + IN UINTN NorFlashRegionBase,=0D + IN UINTN NorFlashSize,=0D + IN UINT32 Index,=0D + IN UINT32 BlockSize,=0D + IN BOOLEAN HasVarStore,=0D + OUT NOR_FLASH_INSTANCE **NorFlashInstance=0D + );=0D +=0D +/**=0D + Install Fv block on to variable store region=0D +=0D + @param[in] Instance Instance of Nor flash variable region.=0D +=0D + @retval EFI_SUCCESS The entry point is executed successfully.= =0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +NorFlashFvbInitialize (=0D + IN NOR_FLASH_INSTANCE *Instance=0D + );=0D +=0D +/**=0D + Check the integrity of firmware volume header.=0D +=0D + @param[in] Instance Instance of Nor flash variable region.=0D +=0D + @retval EFI_SUCCESS The firmware volume is consistent.=0D + @retval EFI_NOT_FOUND The firmware volume has been corrupted.=0D +=0D +**/=0D +EFI_STATUS=0D +ValidateFvHeader (=0D + IN NOR_FLASH_INSTANCE *Instance=0D + );=0D +=0D +/**=0D + Initialize the FV Header and Variable Store Header=0D + to support variable operations.=0D +=0D + @param[in] Instance Location to Initialize the headers=0D +=0D + @retval EFI_SUCCESS Fv init is done=0D +=0D +**/=0D +EFI_STATUS=0D +InitializeFvAndVariableStoreHeaders (=0D + IN NOR_FLASH_INSTANCE *Instance=0D + );=0D +=0D +/**=0D + Retrieves the attributes and current settings of the block.=0D +=0D + @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOC= OL instance.=0D +=0D + @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the at= tributes and=0D + current settings are returned.=0D + Type EFI_FVB_ATTRIBUTES_2 is defined in=0D + EFI_FIRMWARE_VOLUME_HEADER.=0D +=0D + @retval EFI_SUCCESS The firmware volume attributes were returned.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbGetAttributes (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D + );=0D +=0D +/**=0D + Sets configurable firmware volume attributes and returns the=0D + new settings of the firmware volume.=0D +=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PR= OTOCOL instance.=0D +=0D + @param[in, out] Attributes On input, Attributes is a poi= nter to=0D + EFI_FVB_ATTRIBUTES_2 that con= tains the desired=0D + firmware volume settings.=0D + On successful return, it cont= ains the new=0D + settings of the firmware volu= me.=0D +=0D + @retval EFI_UNSUPPORTED The firmware volume attribute= s are not supported.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbSetAttributes (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D + );=0D +=0D +/**=0D + Retrieves the base address of a memory-mapped firmware volume.=0D + This function should be called only for memory-mapped firmware volumes.=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL ins= tance.=0D +=0D + @param[out] Address Pointer to a caller-allocated=0D + EFI_PHYSICAL_ADDRESS that, on successfu= l=0D + return from GetPhysicalAddress(), conta= ins the=0D + base address of the firmware volume.=0D +=0D + @retval EFI_SUCCESS The firmware volume base address was re= turned.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbGetPhysicalAddress (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + OUT EFI_PHYSICAL_ADDRESS *Address=0D + );=0D +=0D +/**=0D + Retrieves the size of the requested block.=0D + It also returns the number of additional blocks with the identical size.= =0D + The GetBlockSize() function is used to retrieve the block map=0D + (see EFI_FIRMWARE_VOLUME_HEADER).=0D +=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOC= OL instance.=0D +=0D + @param[in] Lba Indicates the block whose size to= return=0D +=0D + @param[out] BlockSize Pointer to a caller-allocated UIN= TN in which=0D + the size of the block is returned= .=0D +=0D + @param[out] NumberOfBlocks Pointer to a caller-allocated UIN= TN in=0D + which the number of consecutive b= locks,=0D + starting with Lba, is returned. A= ll=0D + blocks in this range have a size = of=0D + BlockSize.=0D +=0D + @retval EFI_SUCCESS The firmware volume base address = was returned.=0D +=0D + @retval EFI_INVALID_PARAMETER The requested LBA is out of range= .=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbGetBlockSize (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + IN EFI_LBA Lba,=0D + OUT UINTN *BlockSize,=0D + OUT UINTN *NumberOfBlocks=0D + );=0D +=0D +/**=0D + Reads the specified number of bytes into a buffer from the specified bloc= k.=0D +=0D + The Read() function reads the requested number of bytes from the=0D + requested block and stores them in the provided buffer.=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL= instance.=0D +=0D + @param[in] Lba The starting logical block index fr= om which to read=0D +=0D + @param[in] Offset Offset into the block at which to b= egin reading.=0D +=0D + @param[in, out] NumBytes Pointer to a UINTN.=0D + At entry, *NumBytes contains the to= tal size of the=0D + buffer. *NumBytes should have a non= zero value.=0D + At exit, *NumBytes contains the tot= al number of=0D + bytes read.=0D +=0D + @param[in out] Buffer Pointer to a caller-allocated buffe= r that will be=0D + used to hold the data that is read.= =0D +=0D + @retval EFI_SUCCESS The firmware volume was read succes= sfully, and=0D + contents are in Buffer.=0D +=0D + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA bounda= ry.=0D +=0D + @retval EFI_DEVICE_ERROR The block device is not functioning= correctly and=0D + could not be read.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbRead (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN OUT UINT8 *Buffer=0D + );=0D +=0D +/**=0D + Writes the specified number of bytes from the input buffer to the block.= =0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCO= L instance.=0D +=0D + @param[in] Lba The starting logical block index t= o write to.=0D +=0D + @param[in] Offset Offset into the block at which to = begin writing.=0D +=0D + @param[in, out] NumBytes The pointer to a UINTN.=0D + At entry, *NumBytes contains the t= otal size of the=0D + buffer.=0D + At exit, *NumBytes contains the to= tal number of=0D + bytes actually written.=0D +=0D + @param[in] Buffer The pointer to a caller-allocated = buffer that=0D + contains the source for the write.= =0D +=0D + @retval EFI_SUCCESS The firmware volume was written su= ccessfully.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbWrite (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + );=0D +=0D +/**=0D + Erases and initialises a firmware volume block.=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL= =0D +=0D + @param[in] ... The variable argument list is a lis= t of tuples.=0D + Each tuple describes a range of LBA= s to erase=0D + and consists of the following:=0D + - An EFI_LBA that indicates the sta= rting LBA=0D + - A UINTN that indicates the number= of blocks=0D + to erase.=0D +=0D + The list is terminated with an=0D + EFI_LBA_LIST_TERMINATOR.=0D +=0D + @retval EFI_SUCCESS The erase request successfully comp= leted.=0D +=0D + @retval EFI_ACCESS_DENIED The firmware volume is in the Write= Disabled=0D + state.=0D +=0D + @retval EFI_DEVICE_ERROR The block device is not functioning= correctly=0D + and could not be written.=0D + The firmware device may have been p= artially=0D + erased.=0D +=0D + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in t= he variable=0D + argument list do not exist in the f= irmware=0D + volume.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbEraseBlocks (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + ...=0D + );=0D +=0D +/**=0D + This function unlock and erase an entire NOR Flash block.=0D +=0D + @param[in] Instance NOR flash Instance of variable store regio= n.=0D + @param[in] BlockAddress Block address within the variable store re= gion.=0D +=0D + @retval EFI_SUCCESS The erase and unlock successfully complete= d.=0D +**/=0D +EFI_STATUS=0D +NorFlashUnlockAndEraseSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + );=0D +=0D +/**=0D + Write a full or portion of a block.=0D +=0D + @param[in] Instance NOR flash Instance of variable store regi= on.=0D + @param[in] Lba The starting logical block index to write= to.=0D + @param[in] Offset Offset into the block at which to begin w= riting.=0D + @param[in,out] NumBytes The total size of the buffer.=0D + @param[in] Buffer The pointer to a caller-allocated buffer = that=0D + contains the source for the write.=0D +=0D + @retval EFI_SUCCESS The write is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashWriteSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + );=0D +=0D +/**=0D + Write a full block.=0D +=0D + @param[in] Instance NOR flash Instance of variable store = region.=0D + @param[in] Lba The starting logical block index to w= rite to.=0D + @param[in] BufferSizeInBytes The number of bytes to write.=0D + @param[in] Buffer The pointer to a caller-allocated buf= fer that=0D + contains the source for the write.=0D +=0D + @retval EFI_SUCCESS The write is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashWriteBlocks (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN BufferSizeInBytes,=0D + IN VOID *Buffer=0D + );=0D +=0D +/**=0D + Read a full block.=0D +=0D + @param[in] Instance NOR flash Instance of variable store r= egion.=0D + @param[in] Lba The starting logical block index to re= ad from.=0D + @param[in] BufferSizeInBytes The number of bytes to read.=0D + @param[out] Buffer The pointer to a caller-allocated buff= er that=0D + should be copied with read data.=0D +=0D + @retval EFI_SUCCESS The read is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashReadBlocks (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN BufferSizeInBytes,=0D + OUT VOID *Buffer=0D + );=0D +=0D +/**=0D + Read from nor flash.=0D +=0D + @param[in] Instance NOR flash Instance of variable store r= egion.=0D + @param[in] Lba The starting logical block index to re= ad from.=0D + @param[in] Offset Offset into the block at which to begi= n reading.=0D + @param[in] BufferSizeInBytes The number of bytes to read.=0D + @param[out] Buffer The pointer to a caller-allocated buff= er that=0D + should copied with read data.=0D +=0D + @retval EFI_SUCCESS The read is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashRead (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN UINTN BufferSizeInBytes,=0D + OUT VOID *Buffer=0D + );=0D +=0D +/**=0D + Read JEDEC ID of NOR flash device.=0D +=0D + @param[in] Instance NOR flash Instance of variable store region.= =0D + @param[out] JedecId JEDEC ID of NOR flash device.=0D +=0D + @retval EFI_SUCCESS The write is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashReadID (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + OUT UINT8 JedecId[3]=0D + );=0D +=0D +#define SPINOR_SR_WIP BIT0 // Write in progress=0D +=0D +#define SPINOR_OP_WREN 0x06 // Write enable=0D +#define SPINOR_OP_BE_4K 0x20 // Erase 4KiB block=0D +#define SPINOR_OP_RDID 0x9f // Read JEDEC ID=0D +#define SPINOR_OP_RDSR 0x05 // Read status register=0D +=0D +#define SPINOR_SR_WIP_POLL_TIMEOUT_MS 1000u // Status Register read timeo= ut=0D +=0D +#endif /* NOR_FLASH_DXE_H_ */=0D diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c b/P= latform/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=0D + NOR flash DXE=0D +=0D + Copyright (c) 2023, ARM Limited. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "NorFlash.h"=0D +=0D +STATIC NOR_FLASH_INSTANCE **mNorFlashInstances;=0D +STATIC UINT32 mNorFlashDeviceCount;=0D +=0D +STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent;=0D +=0D +/**=0D + Install Fv block onto variable store region=0D +=0D + @param[in] Instance Instance of Nor flash variable region.=0D +=0D + @retval EFI_SUCCESS The entry point is executed successfully.= =0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +NorFlashFvbInitialize (=0D + IN NOR_FLASH_INSTANCE *Instance=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT32 FvbNumLba;=0D + EFI_BOOT_MODE BootMode;=0D + UINTN RuntimeMmioRegionSize;=0D + UINTN RuntimeMmioDeviceSize;=0D + UINTN BlockSize;=0D +=0D + DEBUG ((DEBUG_INFO, "NorFlashFvbInitialize\n"));=0D +=0D + BlockSize =3D Instance->BlockSize;=0D +=0D + // FirmwareVolumeHeader->FvLength is declared to have the Variable area= =0D + // AND the FTW working area AND the FTW Spare contiguous.=0D + ASSERT (=0D + PcdGet32 (PcdFlashNvStorageVariableBase) +=0D + PcdGet32 (PcdFlashNvStorageVariableSize) =3D=3D=0D + PcdGet32 (PcdFlashNvStorageFtwWorkingBase)=0D + );=0D + ASSERT (=0D + PcdGet32 (PcdFlashNvStorageFtwWorkingBase) +=0D + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) =3D=3D=0D + PcdGet32 (PcdFlashNvStorageFtwSpareBase)=0D + );=0D +=0D + // Check if the size of the area is at least one block size.=0D + ASSERT (=0D + (PcdGet32 (PcdFlashNvStorageVariableSize) > 0) &&=0D + (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0)=0D + );=0D + ASSERT (=0D + (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) &&=0D + (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0)=0D + );=0D + ASSERT (=0D + (PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) &&=0D + (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0)=0D + );=0D +=0D + // Ensure the Variable areas are aligned on block size boundaries.=0D + ASSERT ((PcdGet32 (PcdFlashNvStorageVariableBase) % BlockSize) =3D=3D 0)= ;=0D + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) % BlockSize) =3D=3D = 0);=0D + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareBase) % BlockSize) =3D=3D 0)= ;=0D +=0D + Instance->Initialized =3D TRUE;=0D + mFlashNvStorageVariableBase =3D FixedPcdGet32 (PcdFlashNvStorageVariable= Base);=0D +=0D + // Set the index of the first LBA for the FVB.=0D + Instance->StartLba =3D (PcdGet32 (PcdFlashNvStorageVariableBase) -=0D + Instance->RegionBaseAddress) / BlockSize;=0D +=0D + BootMode =3D GetBootModeHob ();=0D + if (BootMode =3D=3D BOOT_WITH_DEFAULT_SETTINGS) {=0D + Status =3D EFI_INVALID_PARAMETER;=0D + } else {=0D + // Determine if there is a valid header at the beginning of the NorFla= sh.=0D + Status =3D ValidateFvHeader (Instance);=0D + }=0D +=0D + // Install the Default FVB header if required.=0D + if (EFI_ERROR (Status)) {=0D + // There is no valid header, so time to install one.=0D + DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __func__));= =0D + DEBUG ((=0D + DEBUG_INFO,=0D + "%a: Installing a correct one for this volume.\n",=0D + __func__=0D + ));=0D +=0D + // Erase all the NorFlash that is reserved for variable storage.=0D + FvbNumLba =3D (PcdGet32 (PcdFlashNvStorageVariableSize) +=0D + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +=0D + PcdGet32 (PcdFlashNvStorageFtwSpareSize)) /=0D + Instance->BlockSize;=0D +=0D + Status =3D FvbEraseBlocks (=0D + &Instance->FvbProtocol,=0D + (EFI_LBA)0,=0D + FvbNumLba,=0D + EFI_LBA_LIST_TERMINATOR=0D + );=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + // Install all appropriate headers.=0D + Status =3D InitializeFvAndVariableStoreHeaders (Instance);=0D + if (EFI_ERROR (Status)) {=0D + return Status;=0D + }=0D +=0D + // validate FV header again if FV was created successfully.=0D + Status =3D ValidateFvHeader (Instance);=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "ValidateFvHeader is failed \n"));=0D + return Status;=0D + }=0D + }=0D +=0D + // The driver implementing the variable read service can now be dispatch= ed;=0D + // the varstore headers are in place.=0D + Status =3D gBS->InstallProtocolInterface (=0D + &gImageHandle,=0D + &gEdkiiNvVarStoreFormattedGuid,=0D + EFI_NATIVE_INTERFACE,=0D + NULL=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "%a: Failed to install gEdkiiNvVarStoreFormattedGuid\n",=0D + __func__=0D + ));=0D + return Status;=0D + }=0D +=0D + // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME.=0D + RuntimeMmioRegionSize =3D Instance->Size;=0D + RuntimeMmioDeviceSize =3D Instance->RegionBaseAddress - Instance->Device= BaseAddress;=0D +=0D + Status =3D gDS->AddMemorySpace (=0D + EfiGcdMemoryTypeMemoryMappedIo,=0D + Instance->RegionBaseAddress,=0D + RuntimeMmioRegionSize,=0D + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gDS->AddMemorySpace (=0D + EfiGcdMemoryTypeMemoryMappedIo,=0D + Instance->DeviceBaseAddress,=0D + RuntimeMmioDeviceSize,=0D + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gDS->SetMemorySpaceAttributes (=0D + Instance->RegionBaseAddress,=0D + RuntimeMmioRegionSize,=0D + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gDS->SetMemorySpaceAttributes (=0D + Instance->DeviceBaseAddress,=0D + RuntimeMmioDeviceSize,=0D + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Fixup internal data so that EFI can be called in virtual mode.=0D + convert any pointers in lib to virtual mode.=0D +=0D + @param[in] Event The Event that is being processed=0D + @param[in] Context Event Context=0D +**/=0D +STATIC=0D +VOID=0D +EFIAPI=0D +NorFlashVirtualNotifyEvent (=0D + IN EFI_EVENT Event,=0D + IN VOID *Context=0D + )=0D +{=0D + UINTN Index;=0D +=0D + EfiConvertPointer (0x0, (VOID **)&mFlashNvStorageVariableBase);=0D +=0D + for (Index =3D 0; Index < mNorFlashDeviceCount; Index++) {=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->HostRegisterBaseAddress=0D + );=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress=0D + );=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress=0D + );=0D +=0D + // Convert Fvb.=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks=0D + );=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes=0D + );=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize=0D + );=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress= =0D + );=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read=0D + );=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes=0D + );=0D + EfiConvertPointer (=0D + 0x0,=0D + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write=0D + );=0D +=0D + if (mNorFlashInstances[Index]->ShadowBuffer !=3D NULL) {=0D + EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowB= uffer);=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Entrypoint of Platform Nor flash DXE driver=0D +=0D + @param[in] ImageHandle The firmware allocated handle for the EFI = image.=0D + @param[in] SystemTable A pointer to the EFI System Table.=0D +=0D + @retval EFI_SUCCESS The entry point is executed successfully.= =0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +NorFlashInitialise (=0D + IN EFI_HANDLE ImageHandle,=0D + IN EFI_SYSTEM_TABLE *SystemTable=0D + )=0D +{=0D + EFI_STATUS Status;=0D + EFI_PHYSICAL_ADDRESS HostRegisterBaseAddress;=0D + UINT32 Index;=0D + NOR_FLASH_DESCRIPTION *NorFlashDevices;=0D + BOOLEAN ContainVariableStorage;=0D +=0D + HostRegisterBaseAddress =3D PcdGet32 (PcdCadenceQspiDxeRegBaseAddress);= =0D +=0D + Status =3D gDS->AddMemorySpace (=0D + EfiGcdMemoryTypeMemoryMappedIo,=0D + HostRegisterBaseAddress,=0D + SIZE_64KB,=0D + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + Status =3D gDS->SetMemorySpaceAttributes (=0D + HostRegisterBaseAddress,=0D + SIZE_64KB,=0D + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + // Initialize NOR flash instances.=0D + Status =3D NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDevic= eCount);=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to get Nor Flash device= s\n"));=0D + return Status;=0D + }=0D +=0D + mNorFlashInstances =3D AllocateRuntimePool (=0D + sizeof (NOR_FLASH_INSTANCE *) *=0D + mNorFlashDeviceCount=0D + );=0D +=0D + if (mNorFlashInstances =3D=3D NULL) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NorFlashInitialise: Failed to allocate mem for NorFlashInstance\n"= =0D + ));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + for (Index =3D 0; Index < mNorFlashDeviceCount; Index++) {=0D + // Check if this NOR Flash device contain the variable storage region.= =0D + ContainVariableStorage =3D=0D + (NorFlashDevices[Index].RegionBaseAddress <=3D=0D + PcdGet32 (PcdFlashNvStorageVariableBase)) &&=0D + (PcdGet32 (PcdFlashNvStorageVariableBase) +=0D + PcdGet32 (PcdFlashNvStorageVariableSize) <=3D=0D + NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].S= ize);=0D +=0D + Status =3D NorFlashCreateInstance (=0D + HostRegisterBaseAddress,=0D + NorFlashDevices[Index].DeviceBaseAddress,=0D + NorFlashDevices[Index].RegionBaseAddress,=0D + NorFlashDevices[Index].Size,=0D + Index,=0D + NorFlashDevices[Index].BlockSize,=0D + ContainVariableStorage,=0D + &mNorFlashInstances[Index]=0D + );=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",= =0D + Index=0D + ));=0D + continue;=0D + }=0D +=0D + Status =3D gBS->InstallMultipleProtocolInterfaces (=0D + &mNorFlashInstances[Index]->Handle,=0D + &gEfiDevicePathProtocolGuid,=0D + &mNorFlashInstances[Index]->DevicePath,=0D + &gEfiFirmwareVolumeBlockProtocolGuid,=0D + &mNorFlashInstances[Index]->FvbProtocol,=0D + NULL=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D + }=0D +=0D + // Register for the virtual address change event.=0D + Status =3D gBS->CreateEventEx (=0D + EVT_NOTIFY_SIGNAL,=0D + TPL_NOTIFY,=0D + NorFlashVirtualNotifyEvent,=0D + NULL,=0D + &gEfiEventVirtualAddressChangeGuid,=0D + &mNorFlashVirtualAddrChangeEvent=0D + );=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Lock all pending read/write to Nor flash device=0D +=0D + @param[in] Context Nor flash device context structure.=0D +**/=0D +VOID=0D +EFIAPI=0D +NorFlashLock (=0D + IN NOR_FLASH_LOCK_CONTEXT *Context=0D + )=0D +{=0D + if (!EfiAtRuntime ()) {=0D + // Raise TPL to TPL_HIGH to stop anyone from interrupting us.=0D + Context->OriginalTPL =3D gBS->RaiseTPL (TPL_HIGH_LEVEL);=0D + } else {=0D + Context->InterruptsEnabled =3D SaveAndDisableInterrupts ();=0D + }=0D +}=0D +=0D +/**=0D + Unlock all pending read/write to Nor flash device=0D +=0D + @param[in] Context Nor flash device context structure.=0D +**/=0D +VOID=0D +EFIAPI=0D +NorFlashUnlock (=0D + IN NOR_FLASH_LOCK_CONTEXT *Context=0D + )=0D +{=0D + if (!EfiAtRuntime ()) {=0D + // Interruptions can resume.=0D + gBS->RestoreTPL (Context->OriginalTPL);=0D + } else if (Context->InterruptsEnabled) {=0D + SetInterruptState (TRUE);=0D + }=0D +}=0D diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c b/Platfor= m/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=0D +=0D + Copyright (c) 2023 ARM Limited. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "NorFlash.h"=0D +=0D +STATIC CONST NOR_FLASH_INSTANCE mNorFlashInstanceTemplate =3D {=0D + NOR_FLASH_SIGNATURE, // Signature=0D + NULL, // Handle=0D +=0D + FALSE, // Initialized=0D + NULL, // Initialize=0D +=0D + 0, // HostRegisterBaseAddress=0D + 0, // DeviceBaseAddress=0D + 0, // RegionBaseAddress=0D + 0, // Size=0D + 0, // BlockSize=0D + 0, // LastBlock=0D + 0, // StartLba=0D + 0, // OffsetLba=0D +=0D + {=0D + FvbGetAttributes, // GetAttributes=0D + FvbSetAttributes, // SetAttributes=0D + FvbGetPhysicalAddress, // GetPhysicalAddress=0D + FvbGetBlockSize, // GetBlockSize=0D + FvbRead, // Read=0D + FvbWrite, // Write=0D + FvbEraseBlocks, // EraseBlocks=0D + NULL, // ParentHandle=0D + }, // FvbProtoccol;=0D + NULL, // ShadowBuffer=0D +=0D + {=0D + {=0D + {=0D + HARDWARE_DEVICE_PATH,=0D + HW_VENDOR_DP,=0D + {=0D + (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),=0D + (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)=0D + }=0D + },=0D + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0,= 0x0, 0x0, 0x0, 0x0 }=0D + },=0D + },=0D + 0, // Index=0D +=0D + {=0D + END_DEVICE_PATH_TYPE,=0D + END_ENTIRE_DEVICE_PATH_SUBTYPE,=0D + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }=0D + }=0D + }, // DevicePath=0D + 0 // Flags=0D +};=0D +=0D +/**=0D + Execute Flash cmd ctrl and Read Status.=0D +=0D + @param[in] Instance NOR flash Instance.=0D + @param[in] Val Value to be written to Flash cmd ctrl R= egister.=0D +=0D + @retval EFI_SUCCESS Request is executed successfully.=0D +=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +CdnsQspiExecuteCommand (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINT32 Val=0D + )=0D +{=0D + // Set the command=0D + MmioWrite32 (=0D + Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSE= T,=0D + Val=0D + );=0D + // Execute the command=0D + MmioWrite32 (=0D + Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSE= T,=0D + Val | CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE=0D + );=0D +=0D + // Wait until command has been executed=0D + while ((MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_= CMD_CTRL_REG_OFFSET)=0D + & CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT) =3D=3D CDNS_QSPI_FLAS= H_CMD_CTRL_REG_STATUS_BIT)=0D + {=0D + continue;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Create Nor flash Instance for given region.=0D +=0D + @param[in] HostRegisterBase Base address of Nor flash controller= .=0D + @param[in] NorFlashDeviceBase Base address of flash device.=0D + @param[in] NorFlashRegionBase Base address of flash region on devi= ce.=0D + @param[in] NorFlashSize Size of flash region.=0D + @param[in] Index Index of given flash region.=0D + @param[in] BlockSize Block size of NOR flash device.=0D + @param[in] HasVarStore Boolean set for VarStore on given re= gion.=0D + @param[out] NorFlashInstance Instance of given flash region.=0D +=0D + @retval EFI_SUCCESS On successful creation of NOR flash = instance.=0D +**/=0D +EFI_STATUS=0D +NorFlashCreateInstance (=0D + IN UINTN HostRegisterBase,=0D + IN UINTN NorFlashDeviceBase,=0D + IN UINTN NorFlashRegionBase,=0D + IN UINTN NorFlashSize,=0D + IN UINT32 Index,=0D + IN UINT32 BlockSize,=0D + IN BOOLEAN HasVarStore,=0D + OUT NOR_FLASH_INSTANCE **NorFlashInstance=0D + )=0D +{=0D + EFI_STATUS Status;=0D + NOR_FLASH_INSTANCE *Instance;=0D + NOR_FLASH_INFO *FlashInfo;=0D + UINT8 JedecId[3];=0D +=0D + ASSERT (NorFlashInstance !=3D NULL);=0D + Instance =3D AllocateRuntimeCopyPool (=0D + sizeof (mNorFlashInstanceTemplate),=0D + &mNorFlashInstanceTemplate=0D + );=0D + if (Instance =3D=3D NULL) {=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + Instance->HostRegisterBaseAddress =3D HostRegisterBase;=0D + Instance->DeviceBaseAddress =3D NorFlashDeviceBase;=0D + Instance->RegionBaseAddress =3D NorFlashRegionBase;=0D + Instance->Size =3D NorFlashSize;=0D + Instance->BlockSize =3D BlockSize;=0D + Instance->LastBlock =3D (NorFlashSize / BlockSize) - 1;=0D +=0D + Instance->OffsetLba =3D (NorFlashRegionBase - NorFlashDeviceBase) / Bloc= kSize;=0D +=0D + CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);=0D + Instance->DevicePath.Index =3D (UINT8)Index;=0D +=0D + Status =3D NorFlashReadID (Instance, JedecId);=0D + if (EFI_ERROR (Status)) {=0D + goto FreeInstance;=0D + }=0D +=0D + Status =3D NorFlashGetInfo (JedecId, &FlashInfo, TRUE);=0D + if (EFI_ERROR (Status)) {=0D + goto FreeInstance;=0D + }=0D +=0D + NorFlashPrintInfo (FlashInfo);=0D +=0D + Instance->Flags =3D 0;=0D + if (FlashInfo->Flags & NOR_FLASH_WRITE_FSR) {=0D + Instance->Flags =3D NOR_FLASH_POLL_FSR;=0D + }=0D +=0D + Instance->ShadowBuffer =3D AllocateRuntimePool (BlockSize);=0D + if (Instance->ShadowBuffer =3D=3D NULL) {=0D + Status =3D EFI_OUT_OF_RESOURCES;=0D + goto FreeInstance;=0D + }=0D +=0D + if (HasVarStore) {=0D + Instance->Initialize =3D NorFlashFvbInitialize;=0D + }=0D +=0D + *NorFlashInstance =3D Instance;=0D + FreePool (FlashInfo);=0D + return EFI_SUCCESS;=0D +=0D +FreeInstance:=0D + FreePool (Instance);=0D + return Status;=0D +}=0D +=0D +/**=0D + Converts milliseconds into number of ticks of the performance counter.=0D +=0D + @param[in] Milliseconds Milliseconds to convert into ticks.=0D +=0D + @retval Milliseconds expressed as number of ticks.=0D +=0D +**/=0D +STATIC=0D +UINT64=0D +MilliSecondsToTicks (=0D + IN UINTN Milliseconds=0D + )=0D +{=0D + CONST UINT64 NanoSecondsPerTick =3D GetTimeInNanoSecond (1);=0D +=0D + return (Milliseconds * 1000000) / NanoSecondsPerTick;=0D +}=0D +=0D +/**=0D + Poll Status register for NOR flash erase/write completion.=0D +=0D + @param[in] Instance NOR flash Instance.=0D +=0D + @retval EFI_SUCCESS Request is executed successfully.=0D + @retval EFI_TIMEOUT Operation timed out.=0D + @retval EFI_DEVICE_ERROR Controller operartion failed.=0D +=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +NorFlashPollStatusRegister (=0D + IN NOR_FLASH_INSTANCE *Instance=0D + )=0D +{=0D + BOOLEAN SRegDone;=0D + UINT32 val;=0D +=0D + val =3D SPINOR_OP_RDSR << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |= =0D + CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_CT= RL_REG_READEN_BIT_POS |=0D + CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES (1) |=0D + CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C << CDNS_QSPI_FLASH_CMD_CTRL_= REG_DUMMY_BIT_POS;=0D +=0D + CONST UINT64 TickOut =3D=0D + GetPerformanceCounter () + MilliSecondsToTicks (SPINOR_SR_WIP_POLL_TIM= EOUT_MS);=0D +=0D + do {=0D + if (GetPerformanceCounter () > TickOut) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NorFlashPollStatusRegister: Timeout waiting for erase/write.\n"=0D + ));=0D + return EFI_TIMEOUT;=0D + }=0D +=0D + if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + SRegDone =3D=0D + (MmioRead8 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_= READ_DATA_REG_OFFSET)=0D + & SPINOR_SR_WIP) =3D=3D 0;=0D + } while (!SRegDone);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Check whether NOR flash opertions are Locked.=0D +=0D + @param[in] Instance NOR flash Instance.=0D + @param[in] BlockAddress BlockAddress in NOR flash device.=0D +=0D + @retval FALSE If NOR flash is not locked.=0D +**/=0D +STATIC=0D +BOOLEAN=0D +NorFlashBlockIsLocked (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + return FALSE;=0D +}=0D +=0D +/**=0D + Unlock NOR flash operations on given block.=0D +=0D + @param[in] Instance NOR flash instance.=0D + @param[in] BlockAddress BlockAddress in NOR flash device.=0D +=0D + @retval EFI_SUCCESS NOR flash operations is unlocked.=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +NorFlashUnlockSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Unlock NOR flash operations if it is necessary.=0D +=0D + @param[in] Instance NOR flash instance.=0D + @param[in] BlockAddress BlockAddress in NOR flash device.=0D +=0D + @retval EFI_SUCCESS Request is executed successfully.=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +NorFlashUnlockSingleBlockIfNecessary (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + if (!NorFlashBlockIsLocked (Instance, BlockAddress)) {=0D + Status =3D NorFlashUnlockSingleBlock (Instance, BlockAddress);=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Enable write to NOR flash device.=0D +=0D + @param[in] Instance NOR flash instance.=0D +=0D + @retval EFI_SUCCESS Request is executed successfully.=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +NorFlashEnableWrite (=0D + IN NOR_FLASH_INSTANCE *Instance=0D + )=0D +{=0D + UINT32 val;=0D +=0D + DEBUG ((DEBUG_INFO, "NorFlashEnableWrite()\n"));=0D + val =3D (SPINOR_OP_WREN << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS);= =0D + if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + The following function presumes that the block has already been unlocked= .=0D +=0D + @param[in] Instance NOR flash instance.=0D + @param[in] BlockAddress Block address within the variable regio= n.=0D +=0D + @retval EFI_SUCCESS Request is executed successfully.=0D + **/=0D +EFI_STATUS=0D +NorFlashEraseSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + UINT32 DevConfigVal;=0D + UINT32 EraseOffset;=0D +=0D + EraseOffset =3D 0x0;=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "NorFlashEraseSingleBlock(BlockAddress=3D0x%08x)\n",=0D + BlockAddress=0D + ));=0D +=0D + if (EFI_ERROR (NorFlashEnableWrite (Instance))) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + EraseOffset =3D BlockAddress - Instance->DeviceBaseAddress;=0D +=0D + MmioWrite32 (=0D + Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_ADDR_REG_OFFSE= T,=0D + EraseOffset=0D + );=0D +=0D + DevConfigVal =3D SPINOR_OP_BE_4K << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_= BIT_POS |=0D + CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE << CDNS_QSPI_FLA= SH_CMD_CTRL_REG_ADDR_BIT_POS |=0D + CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES (3);=0D +=0D + if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, DevConfigVal))) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + This function unlock and erase an entire NOR Flash block.=0D +=0D + @param[in] Instance NOR flash Instance of variable store regio= n.=0D + @param[in] BlockAddress Block address within the variable store re= gion.=0D +=0D + @retval EFI_SUCCESS The erase and unlock successfully complete= d.=0D +**/=0D +EFI_STATUS=0D +NorFlashUnlockAndEraseSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN Index;=0D + NOR_FLASH_LOCK_CONTEXT Lock;=0D +=0D + NorFlashLock (&Lock);=0D +=0D + Index =3D 0;=0D + do {=0D + // Unlock the block if we have to=0D + Status =3D NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddres= s);=0D + if (EFI_ERROR (Status)) {=0D + break;=0D + }=0D +=0D + Status =3D NorFlashEraseSingleBlock (Instance, BlockAddress);=0D + if (EFI_ERROR (Status)) {=0D + break;=0D + }=0D +=0D + Index++;=0D + } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status =3D=3D EFI_WRITE_PRO= TECTED));=0D +=0D + if (Index =3D=3D NOR_FLASH_ERASE_RETRY) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "EraseSingleBlock(BlockAddress=3D0x%08x: Block Locked Error (try to = erase %d times)\n",=0D + BlockAddress,=0D + Index=0D + ));=0D + }=0D +=0D + NorFlashUnlock (&Lock);=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Write a single word to given location.=0D +=0D + @param[in] Instance NOR flash Instance of variable store region.= =0D + @param[in] WordAddress The address in NOR flash to write given word.= =0D + @param[in] WriteData The data to write into NOR flash location.=0D +=0D + @retval EFI_SUCCESS The write is completed.=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +NorFlashWriteSingleWord (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN WordAddress,=0D + IN UINT32 WriteData=0D + )=0D +{=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "NorFlashWriteSingleWord(WordAddress=3D0x%08x, WriteData=3D0x%08x)\n",= =0D + WordAddress,=0D + WriteData=0D + ));=0D +=0D + if (EFI_ERROR (NorFlashEnableWrite (Instance))) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + MmioWrite32 (WordAddress, WriteData);=0D + if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Write a full block to given location.=0D +=0D + @param[in] Instance NOR flash Instance of variable store re= gion.=0D + @param[in] Lba The logical block address in NOR flash.= =0D + @param[in] DataBuffer The data to write into NOR flash locati= on.=0D + @param[in] BlockSizeInWords The number of bytes to write.=0D +=0D + @retval EFI_SUCCESS The write is completed.=0D +**/=0D +STATIC=0D +EFI_STATUS=0D +NorFlashWriteFullBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINT32 *DataBuffer,=0D + IN UINT32 BlockSizeInWords=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN WordAddress;=0D + UINT32 WordIndex;=0D + UINTN BlockAddress;=0D + NOR_FLASH_LOCK_CONTEXT Lock;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + // Get the physical address of the block=0D + BlockAddress =3D GET_NOR_BLOCK_ADDRESS (=0D + Instance->RegionBaseAddress,=0D + Lba,=0D + BlockSizeInWords * 4=0D + );=0D +=0D + // Start writing from the first address at the start of the block=0D + WordAddress =3D BlockAddress;=0D +=0D + NorFlashLock (&Lock);=0D +=0D + Status =3D NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single blo= ck at 0x%X\n",=0D + BlockAddress=0D + ));=0D + goto EXIT;=0D + }=0D +=0D + for (WordIndex =3D 0;=0D + WordIndex < BlockSizeInWords;=0D + WordIndex++, DataBuffer++, WordAddress +=3D 4)=0D + {=0D + Status =3D NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer= );=0D + if (EFI_ERROR (Status)) {=0D + goto EXIT;=0D + }=0D + }=0D +=0D +EXIT:=0D + NorFlashUnlock (&Lock);=0D +=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. = Exit Status =3D %r.\n",=0D + WordAddress,=0D + Status=0D + ));=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Write a full block.=0D +=0D + @param[in] Instance NOR flash Instance of variable store re= gion.=0D + @param[in] Lba The starting logical block index.=0D + @param[in] BufferSizeInBytes The number of bytes to read.=0D + @param[in] Buffer The pointer to a caller-allocated buffe= r that=0D + contains the source for the write.=0D +=0D + @retval EFI_SUCCESS The write is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashWriteBlocks (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN BufferSizeInBytes,=0D + IN VOID *Buffer=0D + )=0D +{=0D + UINT32 *pWriteBuffer;=0D + EFI_STATUS Status;=0D + EFI_LBA CurrentBlock;=0D + UINT32 BlockSizeInWords;=0D + UINT32 NumBlocks;=0D + UINT32 BlockCount;=0D +=0D + Status =3D EFI_SUCCESS;=0D + // The buffer must be valid=0D + if (Buffer =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // We must have some bytes to read=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "NorFlashWriteBlocks: BufferSizeInBytes=3D0x%x\n",=0D + BufferSizeInBytes=0D + ));=0D + if (BufferSizeInBytes =3D=3D 0) {=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // The size of the buffer must be a multiple of the block size=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "NorFlashWriteBlocks: BlockSize in bytes =3D0x%x\n",=0D + Instance->BlockSize=0D + ));=0D + if ((BufferSizeInBytes % Instance->BlockSize) !=3D 0) {=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // All blocks must be within the device=0D + NumBlocks =3D ((UINT32)BufferSizeInBytes) / Instance->BlockSize;=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "NorFlashWriteBlocks: NumBlocks=3D%d, LastBlock=3D%ld, Lba=3D%ld.\n",= =0D + NumBlocks,=0D + Instance->LastBlock,=0D + Lba=0D + ));=0D +=0D + if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"=0D + ));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + ASSERT (((UINTN)Buffer % sizeof (UINT32)) =3D=3D 0);=0D +=0D + BlockSizeInWords =3D Instance->BlockSize / 4;=0D +=0D + // Because the target *Buffer is a pointer to VOID, we must put=0D + // all the data into a pointer to a proper data type, so use *ReadBuffer= =0D + pWriteBuffer =3D (UINT32 *)Buffer;=0D +=0D + CurrentBlock =3D Lba;=0D + for (BlockCount =3D 0;=0D + BlockCount < NumBlocks;=0D + BlockCount++, CurrentBlock++, pWriteBuffer +=3D BlockSizeInWords)=0D + {=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "NorFlashWriteBlocks: Writing block #%d\n",=0D + (UINTN)CurrentBlock=0D + ));=0D +=0D + Status =3D NorFlashWriteFullBlock (=0D + Instance,=0D + CurrentBlock,=0D + pWriteBuffer,=0D + BlockSizeInWords=0D + );=0D +=0D + if (EFI_ERROR (Status)) {=0D + break;=0D + }=0D + }=0D +=0D + DEBUG ((DEBUG_INFO, "NorFlashWriteBlocks: Exit Status =3D %r.\n", Status= ));=0D + return Status;=0D +}=0D +=0D +/**=0D + Read a full block.=0D +=0D + @param[in] Instance NOR flash Instance of variable store r= egion.=0D + @param[in] Lba The starting logical block index to re= ad from.=0D + @param[in] BufferSizeInBytes The number of bytes to read.=0D + @param[out] Buffer The pointer to a caller-allocated buff= er that=0D + should be copied with read data.=0D +=0D + @retval EFI_SUCCESS The read is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashReadBlocks (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN BufferSizeInBytes,=0D + OUT VOID *Buffer=0D + )=0D +{=0D + UINT32 NumBlocks;=0D + UINTN StartAddress;=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "NorFlashReadBlocks: BufferSize=3D0x%xB BlockSize=3D0x%xB LastBlock=3D= %ld, Lba=3D%ld.\n",=0D + BufferSizeInBytes,=0D + Instance->BlockSize,=0D + Instance->LastBlock,=0D + Lba=0D + ));=0D +=0D + // The buffer must be valid=0D + if (Buffer =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Return if we do not have any byte to read=0D + if (BufferSizeInBytes =3D=3D 0) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + // The size of the buffer must be a multiple of the block size=0D + if ((BufferSizeInBytes % Instance->BlockSize) !=3D 0) {=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + NumBlocks =3D ((UINT32)BufferSizeInBytes) / Instance->BlockSize;=0D +=0D + if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NorFlashReadBlocks: ERROR - Read will exceed last block\n"=0D + ));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Get the address to start reading from=0D + StartAddress =3D GET_NOR_BLOCK_ADDRESS (=0D + Instance->RegionBaseAddress,=0D + Lba,=0D + Instance->BlockSize=0D + );=0D +=0D + // Readout the data=0D + CopyMem (Buffer, (UINTN *)StartAddress, BufferSizeInBytes);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Read from nor flash.=0D +=0D + @param[in] Instance NOR flash Instance of variable store r= egion.=0D + @param[in] Lba The starting logical block index to re= ad from.=0D + @param[in] Offset Offset into the block at which to begi= n reading.=0D + @param[in] BufferSizeInBytes The number of bytes to read.=0D + @param[out] Buffer The pointer to a caller-allocated buff= er that=0D + should copied with read data.=0D +=0D + @retval EFI_SUCCESS The read is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashRead (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN UINTN BufferSizeInBytes,=0D + OUT VOID *Buffer=0D + )=0D +{=0D + UINTN StartAddress;=0D +=0D + // The buffer must be valid=0D + if (Buffer =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Return if we do not have any byte to read=0D + if (BufferSizeInBytes =3D=3D 0) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + if (((Lba * Instance->BlockSize) + Offset + BufferSizeInBytes) >=0D + Instance->Size)=0D + {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NorFlashRead: ERROR - Read will exceed device size.\n"=0D + ));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Get the address to start reading from=0D + StartAddress =3D GET_NOR_BLOCK_ADDRESS (=0D + Instance->RegionBaseAddress,=0D + Lba,=0D + Instance->BlockSize=0D + );=0D +=0D + // Readout the data=0D + CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Write a full or portion of a block.=0D +=0D + @param[in] Instance NOR flash Instance of variable store reg= ion.=0D + @param[in] Lba The starting logical block index to writ= e to.=0D + @param[in] Offset Offset into the block at which to begin = writing.=0D + @param[in, out] NumBytes The total size of the buffer.=0D + @param[in] Buffer The pointer to a caller-allocated buffer= that=0D + contains the source for the write.=0D +=0D + @retval EFI_SUCCESS The write is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashWriteSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT32 Tmp;=0D + UINT32 TmpBuf;=0D + UINT32 WordToWrite;=0D + UINT32 Mask;=0D + BOOLEAN DoErase;=0D + UINTN BytesToWrite;=0D + UINTN CurOffset;=0D + UINTN WordAddr;=0D + UINTN BlockSize;=0D + UINTN BlockAddress;=0D + UINTN PrevBlockAddress;=0D +=0D + if (Buffer =3D=3D NULL) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NorFlashWriteSingleBlock: ERROR - Buffer is invalid\n"=0D + ));=0D + return EFI_OUT_OF_RESOURCES;=0D + }=0D +=0D + PrevBlockAddress =3D 0;=0D + if (!Instance->Initialized && Instance->Initialize) {=0D + Instance->Initialize (Instance);=0D + }=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "NorFlashWriteSingleBlock(Parameters: Lba=3D%ld, Offset=3D0x%x, *NumBy= tes=3D0x%x, Buffer @ 0x%08x)\n",=0D + Lba,=0D + Offset,=0D + *NumBytes,=0D + Buffer=0D + ));=0D +=0D + // Localise the block size to avoid de-referencing pointers all the time= =0D + BlockSize =3D Instance->BlockSize;=0D +=0D + // The write must not span block boundaries.=0D + // We need to check each variable individually because adding two large= =0D + // values together overflows.=0D + if ((Offset >=3D BlockSize) ||=0D + (*NumBytes > BlockSize) ||=0D + ((Offset + *NumBytes) > BlockSize))=0D + {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=3D0x= %x + NumBytes=3D0x%x) > BlockSize=3D0x%x\n",=0D + Offset,=0D + *NumBytes,=0D + BlockSize=0D + ));=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // We must have some bytes to write=0D + if (*NumBytes =3D=3D 0) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=3D0x= %x + NumBytes=3D0x%x) > BlockSize=3D0x%x\n",=0D + Offset,=0D + *NumBytes,=0D + BlockSize=0D + ));=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // Pick 128bytes as a good start for word operations as opposed to erasi= ng the=0D + // block and writing the data regardless if an erase is really needed.=0D + // It looks like most individual NV variable writes are smaller than 128= bytes.=0D + if (*NumBytes <=3D 128) {=0D + // Check to see if we need to erase before programming the data into N= OR.=0D + // If the destination bits are only changing from 1s to 0s we can just= write.=0D + // After a block is erased all bits in the block is set to 1.=0D + // If any byte requires us to erase we just give up and rewrite all of= it.=0D + DoErase =3D FALSE;=0D + BytesToWrite =3D *NumBytes;=0D + CurOffset =3D Offset;=0D +=0D + while (BytesToWrite > 0) {=0D + // Read full word from NOR, splice as required. A word is the smalle= st=0D + // unit we can write.=0D + Status =3D NorFlashRead (=0D + Instance,=0D + Lba,=0D + CurOffset & ~(0x3),=0D + sizeof (Tmp),=0D + &Tmp=0D + );=0D + if (EFI_ERROR (Status)) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + // Physical address of word in NOR to write.=0D + WordAddr =3D (CurOffset & ~(0x3)) +=0D + GET_NOR_BLOCK_ADDRESS (=0D + Instance->RegionBaseAddress,=0D + Lba,=0D + BlockSize=0D + );=0D +=0D + // The word of data that is to be written.=0D + TmpBuf =3D ReadUnaligned32 ((UINT32 *)(Buffer + (*NumBytes - BytesTo= Write)));=0D +=0D + // First do word aligned chunks.=0D + if ((CurOffset & 0x3) =3D=3D 0) {=0D + if (BytesToWrite >=3D 4) {=0D + // Is the destination still in 'erased' state?=0D + if (~Tmp !=3D 0) {=0D + // Check to see if we are only changing bits to zero.=0D + if ((Tmp ^ TmpBuf) & TmpBuf) {=0D + DoErase =3D TRUE;=0D + break;=0D + }=0D + }=0D +=0D + // Write this word to NOR=0D + WordToWrite =3D TmpBuf;=0D + CurOffset +=3D sizeof (TmpBuf);=0D + BytesToWrite -=3D sizeof (TmpBuf);=0D + } else {=0D + // BytesToWrite < 4. Do small writes and left-overs=0D + Mask =3D ~((~0) << (BytesToWrite * 8));=0D + // Mask out the bytes we want.=0D + TmpBuf &=3D Mask;=0D + // Is the destination still in 'erased' state?=0D + if ((Tmp & Mask) !=3D Mask) {=0D + // Check to see if we are only changing bits to zero.=0D + if ((Tmp ^ TmpBuf) & TmpBuf) {=0D + DoErase =3D TRUE;=0D + break;=0D + }=0D + }=0D +=0D + // Merge old and new data. Write merged word to NOR=0D + WordToWrite =3D (Tmp & ~Mask) | TmpBuf;=0D + CurOffset +=3D BytesToWrite;=0D + BytesToWrite =3D 0;=0D + }=0D + } else {=0D + // Do multiple words, but starting unaligned.=0D + if (BytesToWrite > (4 - (CurOffset & 0x3))) {=0D + Mask =3D ((~0) << ((CurOffset & 0x3) * 8));=0D + // Mask out the bytes we want.=0D + TmpBuf &=3D Mask;=0D + // Is the destination still in 'erased' state?=0D + if ((Tmp & Mask) !=3D Mask) {=0D + // Check to see if we are only changing bits to zero.=0D + if ((Tmp ^ TmpBuf) & TmpBuf) {=0D + DoErase =3D TRUE;=0D + break;=0D + }=0D + }=0D +=0D + // Merge old and new data. Write merged word to NOR=0D + WordToWrite =3D (Tmp & ~Mask) | TmpBuf;=0D + BytesToWrite -=3D (4 - (CurOffset & 0x3));=0D + CurOffset +=3D (4 - (CurOffset & 0x3));=0D + } else {=0D + // Unaligned and fits in one word.=0D + Mask =3D (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) *= 8);=0D + // Mask out the bytes we want.=0D + TmpBuf =3D (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;=0D + // Is the destination still in 'erased' state?=0D + if ((Tmp & Mask) !=3D Mask) {=0D + // Check to see if we are only changing bits to zero.=0D + if ((Tmp ^ TmpBuf) & TmpBuf) {=0D + DoErase =3D TRUE;=0D + break;=0D + }=0D + }=0D +=0D + // Merge old and new data. Write merged word to NOR=0D + WordToWrite =3D (Tmp & ~Mask) | TmpBuf;=0D + CurOffset +=3D BytesToWrite;=0D + BytesToWrite =3D 0;=0D + }=0D + }=0D +=0D + BlockAddress =3D GET_NOR_BLOCK_ADDRESS (=0D + Instance->RegionBaseAddress,=0D + Lba,=0D + BlockSize=0D + );=0D + if (BlockAddress !=3D PrevBlockAddress) {=0D + Status =3D NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAd= dress);=0D + if (EFI_ERROR (Status)) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + PrevBlockAddress =3D BlockAddress;=0D + }=0D +=0D + Status =3D NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite)= ;=0D + if (EFI_ERROR (Status)) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D + }=0D +=0D + // Exit if we got here and could write all the data. Otherwise do the= =0D + // Erase-Write cycle.=0D + if (!DoErase) {=0D + return EFI_SUCCESS;=0D + }=0D + }=0D +=0D + // Check we did get some memory. Buffer is BlockSize.=0D + if (Instance->ShadowBuffer =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + // Read NOR Flash data into shadow buffer=0D + Status =3D NorFlashReadBlocks (=0D + Instance,=0D + Lba,=0D + BlockSize,=0D + Instance->ShadowBuffer=0D + );=0D + if (EFI_ERROR (Status)) {=0D + // Return one of the pre-approved error statuses=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + // Put the data at the appropriate location inside the buffer area=0D + CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumB= ytes);=0D +=0D + // Write the modified buffer back to the NorFlash=0D + Status =3D NorFlashWriteBlocks (=0D + Instance,=0D + Lba,=0D + BlockSize,=0D + Instance->ShadowBuffer=0D + );=0D + if (EFI_ERROR (Status)) {=0D + // Return one of the pre-approved error statuses=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Read JEDEC ID of NOR flash device.=0D +=0D + @param[in] Instance NOR flash Instance of variable store region.= =0D + @param[out] JedecId JEDEC ID of NOR flash device.=0D +=0D + @retval EFI_SUCCESS The write is completed.=0D +**/=0D +EFI_STATUS=0D +NorFlashReadID (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + OUT UINT8 JedecId[3]=0D + )=0D +{=0D + UINT32 val;=0D +=0D + if ((Instance =3D=3D NULL) || (JedecId =3D=3D NULL)) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + val =3D SPINOR_OP_RDID << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS |= =0D + CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_CT= RL_REG_READEN_BIT_POS |=0D + CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES (3);=0D +=0D + if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + val =3D MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_= CMD_READ_DATA_REG_OFFSET);=0D +=0D + // Manu.ID field=0D + JedecId[0] =3D (UINT8)val;=0D + // Type field=0D + JedecId[1] =3D (UINT8)(val >> 8);=0D + // Capacity field=0D + JedecId[2] =3D (UINT8)(val >> 16);=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "Nor flash detected, Jedec ID, Manu.Id=3D%x Type=3D%x Capacity=3D%x \n= ",=0D + JedecId[0],=0D + JedecId[1],=0D + JedecId[2]=0D + ));=0D +=0D + return EFI_SUCCESS;=0D +}=0D diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c b/Plat= form/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=0D +=0D + Copyright (c) 2023, ARM Limited. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include =0D +=0D +#include "NorFlash.h"=0D +=0D +UINTN mFlashNvStorageVariableBase;=0D +=0D +/**=0D + Initialize the FV Header and Variable Store Header=0D + to support variable operations.=0D +=0D + @param[in] Instance Location to initialise the headers.=0D +=0D + @retval EFI_SUCCESS Fv init is done.=0D +=0D +**/=0D +EFI_STATUS=0D +InitializeFvAndVariableStoreHeaders (=0D + IN NOR_FLASH_INSTANCE *Instance=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VOID *Headers;=0D + UINTN HeadersLength;=0D + EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;=0D + VARIABLE_STORE_HEADER *VariableStoreHeader;=0D +=0D + if (!Instance->Initialized && Instance->Initialize) {=0D + Instance->Initialize (Instance);=0D + }=0D +=0D + HeadersLength =3D sizeof (EFI_FIRMWARE_VOLUME_HEADER) +=0D + sizeof (EFI_FV_BLOCK_MAP_ENTRY) +=0D + sizeof (VARIABLE_STORE_HEADER);=0D + Headers =3D AllocateZeroPool (HeadersLength);=0D +=0D + FirmwareVolumeHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)Headers;=0D + CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid= );=0D + FirmwareVolumeHeader->FvLength =3D=0D + PcdGet32 (PcdFlashNvStorageVariableSize) +=0D + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +=0D + PcdGet32 (PcdFlashNvStorageFtwSpareSize);=0D + FirmwareVolumeHeader->Signature =3D EFI_FVH_SIGNATURE;=0D + FirmwareVolumeHeader->Attributes =3D EFI_FVB2_READ_ENABLED_CAP |=0D + EFI_FVB2_READ_STATUS |=0D + EFI_FVB2_STICKY_WRITE |=0D + EFI_FVB2_MEMORY_MAPPED |=0D + EFI_FVB2_ERASE_POLARITY |=0D + EFI_FVB2_WRITE_STATUS |=0D + EFI_FVB2_WRITE_ENABLED_CAP;=0D +=0D + FirmwareVolumeHeader->HeaderLength =3D sizeof (EFI_FIRMWARE_VOLUME_HEADE= R) +=0D + sizeof (EFI_FV_BLOCK_MAP_ENTRY);=0D + FirmwareVolumeHeader->Revision =3D EFI_FVH_REVISION;=0D + FirmwareVolumeHeader->BlockMap[0].NumBlocks =3D Instance->LastBlock + 1;= =0D + FirmwareVolumeHeader->BlockMap[0].Length =3D Instance->BlockSize;=0D + FirmwareVolumeHeader->BlockMap[1].NumBlocks =3D 0;=0D + FirmwareVolumeHeader->BlockMap[1].Length =3D 0;=0D + FirmwareVolumeHeader->Checksum =3D CalculateCheckSum16 (=0D + (UINT16 *)FirmwareVolume= Header,=0D + FirmwareVolumeHeader->He= aderLength=0D + );=0D +=0D + VariableStoreHeader =3D (VOID *)((UINTN)Headers +=0D + FirmwareVolumeHeader->HeaderLength);=0D + CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGui= d);=0D + VariableStoreHeader->Size =3D PcdGet32 (PcdFlashNvStorageVariableSize) -= =0D + FirmwareVolumeHeader->HeaderLength;=0D + VariableStoreHeader->Format =3D VARIABLE_STORE_FORMATTED;=0D + VariableStoreHeader->State =3D VARIABLE_STORE_HEALTHY;=0D +=0D + // Install the combined super-header in the NorFlash=0D + Status =3D FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Heade= rs);=0D +=0D + FreePool (Headers);=0D + return Status;=0D +}=0D +=0D +/**=0D + Check the integrity of firmware volume header.=0D +=0D + @param[in] Instance Instance of Nor flash variable region.=0D +=0D + @retval EFI_SUCCESS The firmware volume is consistent.=0D + @retval EFI_NOT_FOUND The firmware volume has been corrupted.=0D +=0D +**/=0D +EFI_STATUS=0D +ValidateFvHeader (=0D + IN NOR_FLASH_INSTANCE *Instance=0D + )=0D +{=0D + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;=0D + VARIABLE_STORE_HEADER *VariableStoreHeader;=0D + UINTN VariableStoreLength;=0D + UINTN FvLength;=0D +=0D + FwVolHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)Instance->RegionBaseAddres= s;=0D +=0D + FvLength =3D PcdGet32 (PcdFlashNvStorageVariableSize) +=0D + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +=0D + PcdGet32 (PcdFlashNvStorageFtwSpareSize);=0D +=0D + if ( (FwVolHeader->Revision !=3D EFI_FVH_REVISION)=0D + || (FwVolHeader->Signature !=3D EFI_FVH_SIGNATURE)=0D + || (FwVolHeader->FvLength !=3D FvLength)=0D + )=0D + {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "%a: No Firmware Volume header present\n",=0D + __func__=0D + ));=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + // Check the Firmware Volume Guid=0D + if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)= ) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "%a: Firmware Volume Guid non-compatible\n",=0D + __func__=0D + ));=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + VariableStoreHeader =3D (VOID *)((UINTN)FwVolHeader +=0D + FwVolHeader->HeaderLength);=0D +=0D + // Check the Variable Store Guid=0D + if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&= =0D + !CompareGuid (=0D + &VariableStoreHeader->Signature,=0D + &gEfiAuthenticatedVariableGuid=0D + ))=0D + {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "%a: Variable Store Guid non-compatible\n",=0D + __func__=0D + ));=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + VariableStoreLength =3D PcdGet32 (PcdFlashNvStorageVariableSize) -=0D + FwVolHeader->HeaderLength;=0D + if (VariableStoreHeader->Size !=3D VariableStoreLength) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "%a: Variable Store Length does not match\n",=0D + __func__=0D + ));=0D + return EFI_NOT_FOUND;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Retrieves the attributes and current settings of the block.=0D +=0D + @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOC= OL instance.=0D +=0D + @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the at= tributes and=0D + current settings are returned.=0D + Type EFI_FVB_ATTRIBUTES_2 is defined in=0D + EFI_FIRMWARE_VOLUME_HEADER.=0D +=0D + @retval EFI_SUCCESS The firmware volume attributes were returned.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbGetAttributes (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D + )=0D +{=0D + EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;=0D +=0D + FlashFvbAttributes =3D EFI_FVB2_READ_ENABLED_CAP | EFI_FVB2_READ_STATUS = |=0D + EFI_FVB2_WRITE_ENABLED_CAP | EFI_FVB2_WRITE_STATUS = |=0D + EFI_FVB2_STICKY_WRITE | EFI_FVB2_MEMORY_MAPPED |=0D + EFI_FVB2_ERASE_POLARITY;=0D +=0D + *Attributes =3D FlashFvbAttributes;=0D +=0D + DEBUG ((DEBUG_INFO, "FvbGetAttributes(0x%X)\n", *Attributes));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Sets configurable firmware volume attributes and returns the=0D + new settings of the firmware volume.=0D +=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PR= OTOCOL instance.=0D +=0D + @param[in, out] Attributes On input, Attributes is a poi= nter to=0D + EFI_FVB_ATTRIBUTES_2 that con= tains the desired=0D + firmware volume settings.=0D + On successful return, it cont= ains the new=0D + settings of the firmware volu= me.=0D +=0D + @retval EFI_UNSUPPORTED The firmware volume attribute= s are not supported.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbSetAttributes (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D + )=0D +{=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "FvbSetAttributes(0x%X) is not supported\n",=0D + *Attributes=0D + ));=0D + return EFI_UNSUPPORTED;=0D +}=0D +=0D +/**=0D + Retrieves the base address of a memory-mapped firmware volume.=0D + This function should be called only for memory-mapped firmware volumes.=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL ins= tance.=0D +=0D + @param[out] Address Pointer to a caller-allocated=0D + EFI_PHYSICAL_ADDRESS that, on successfu= l=0D + return from GetPhysicalAddress(), conta= ins the=0D + base address of the firmware volume.=0D +=0D + @retval EFI_SUCCESS The firmware volume base address was re= turned.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbGetPhysicalAddress (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + OUT EFI_PHYSICAL_ADDRESS *Address=0D + )=0D +{=0D + NOR_FLASH_INSTANCE *Instance;=0D +=0D + Instance =3D INSTANCE_FROM_FVB_THIS (This);=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "FvbGetPhysicalAddress(BaseAddress=3D0x%08x)\n",=0D + Instance->RegionBaseAddress=0D + ));=0D +=0D + ASSERT (Address !=3D NULL);=0D +=0D + *Address =3D Instance->RegionBaseAddress;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Retrieves the size of the requested block.=0D + It also returns the number of additional blocks with the identical size.= =0D + The GetBlockSize() function is used to retrieve the block map=0D + (see EFI_FIRMWARE_VOLUME_HEADER).=0D +=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOC= OL instance.=0D +=0D + @param[in] Lba Indicates the block whose size to= return=0D +=0D + @param[out] BlockSize Pointer to a caller-allocated UIN= TN in which=0D + the size of the block is returned= .=0D +=0D + @param[out] NumberOfBlocks Pointer to a caller-allocated UIN= TN in=0D + which the number of consecutive b= locks,=0D + starting with Lba, is returned. A= ll=0D + blocks in this range have a size = of=0D + BlockSize.=0D +=0D + @retval EFI_SUCCESS The firmware volume base address = was returned.=0D +=0D + @retval EFI_INVALID_PARAMETER The requested LBA is out of range= .=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbGetBlockSize (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + IN EFI_LBA Lba,=0D + OUT UINTN *BlockSize,=0D + OUT UINTN *NumberOfBlocks=0D + )=0D +{=0D + EFI_STATUS Status;=0D + NOR_FLASH_INSTANCE *Instance;=0D +=0D + Instance =3D INSTANCE_FROM_FVB_THIS (This);=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "FvbGetBlockSize(Lba=3D%ld, BlockSize=3D0x%x, LastBlock=3D%ld)\n",=0D + Lba,=0D + Instance->BlockSize,=0D + Instance->LastBlock=0D + ));=0D +=0D + if (Lba > Instance->LastBlock) {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (= %ld).\n",=0D + Lba,=0D + Instance->LastBlock=0D + ));=0D + Status =3D EFI_INVALID_PARAMETER;=0D + } else {=0D + // This is easy because in this platform each NorFlash device has equa= l sized blocks.=0D + *BlockSize =3D (UINTN)Instance->BlockSize;=0D + *NumberOfBlocks =3D (UINTN)(Instance->LastBlock - Lba + 1);=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "FvbGetBlockSize: *BlockSize=3D0x%x, *NumberOfBlocks=3D0x%x.\n",=0D + *BlockSize,=0D + *NumberOfBlocks=0D + ));=0D +=0D + Status =3D EFI_SUCCESS;=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + Reads the specified number of bytes into a buffer from the specified bloc= k.=0D +=0D + The Read() function reads the requested number of bytes from the=0D + requested block and stores them in the provided buffer.=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL= instance.=0D +=0D + @param[in] Lba The starting logical block index fr= om which to read=0D +=0D + @param[in] Offset Offset into the block at which to b= egin reading.=0D +=0D + @param[in, out] NumBytes Pointer to a UINTN.=0D + At entry, *NumBytes contains the to= tal size of the=0D + buffer. *NumBytes should have a non= zero value.=0D + At exit, *NumBytes contains the tot= al number of=0D + bytes read.=0D +=0D + @param[in, out] Buffer Pointer to a caller-allocated buffe= r that will be=0D + used to hold the data that is read.= =0D +=0D + @retval EFI_SUCCESS The firmware volume was read succes= sfully, and=0D + contents are in Buffer.=0D +=0D + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA bounda= ry.=0D +=0D + @retval EFI_DEVICE_ERROR The block device is not functioning= correctly and=0D + could not be read.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbRead (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN OUT UINT8 *Buffer=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN BlockSize;=0D + NOR_FLASH_INSTANCE *Instance;=0D +=0D + Instance =3D INSTANCE_FROM_FVB_THIS (This);=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "FvbRead(Parameters: Lba=3D%ld, Offset=3D0x%x, *NumBytes=3D0x%x, Buffe= r @ 0x%08x)\n",=0D + Instance->StartLba + Lba,=0D + Offset,=0D + *NumBytes,=0D + Buffer=0D + ));=0D +=0D + if (!Instance->Initialized && Instance->Initialize) {=0D + Instance->Initialize (Instance);=0D + }=0D +=0D + BlockSize =3D Instance->BlockSize;=0D +=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "FvbRead: Check if (Offset=3D0x%x + NumBytes=3D0x%x) <=3D BlockSize=3D= 0x%x\n",=0D + Offset,=0D + *NumBytes,=0D + BlockSize=0D + ));=0D +=0D + // The read must not span block boundaries.=0D + // We need to check each variable individually because adding two large= =0D + // values together overflows.=0D + if ((Offset >=3D BlockSize) ||=0D + (*NumBytes > BlockSize) ||=0D + ((Offset + *NumBytes) > BlockSize))=0D + {=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=3D0x%x + NumBytes=3D0= x%x) > BlockSize=3D0x%x\n",=0D + Offset,=0D + *NumBytes,=0D + BlockSize=0D + ));=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // We must have some bytes to read=0D + if (*NumBytes =3D=3D 0) {=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // Decide if we are doing full block reads or not.=0D + if (*NumBytes % BlockSize !=3D 0) {=0D + Status =3D NorFlashRead (=0D + Instance,=0D + Instance->StartLba + Lba,=0D + Offset,=0D + *NumBytes,=0D + Buffer=0D + );=0D + } else {=0D + // Read NOR Flash data into shadow buffer=0D + Status =3D NorFlashReadBlocks (=0D + Instance,=0D + Instance->StartLba + Lba,=0D + BlockSize,=0D + Buffer=0D + );=0D + }=0D +=0D + if (EFI_ERROR (Status)) {=0D + // Return one of the pre-approved error statuses=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Writes the specified number of bytes from the input buffer to the block.= =0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCO= L instance.=0D +=0D + @param[in] Lba The starting logical block index t= o write to.=0D +=0D + @param[in] Offset Offset into the block at which to = begin writing.=0D +=0D + @param[in, out] NumBytes The pointer to a UINTN.=0D + At entry, *NumBytes contains the t= otal size of the=0D + buffer.=0D + At exit, *NumBytes contains the to= tal number of=0D + bytes actually written.=0D +=0D + @param[in] Buffer The pointer to a caller-allocated = buffer that=0D + contains the source for the write.= =0D +=0D + @retval EFI_SUCCESS The firmware volume was written su= ccessfully.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbWrite (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + )=0D +{=0D + NOR_FLASH_INSTANCE *Instance;=0D +=0D + Instance =3D INSTANCE_FROM_FVB_THIS (This);=0D +=0D + return NorFlashWriteSingleBlock (=0D + Instance,=0D + Instance->StartLba + Lba,=0D + Offset,=0D + NumBytes,=0D + Buffer=0D + );=0D +}=0D +=0D +/**=0D + Erases and initialises a firmware volume block.=0D +=0D + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL= =0D +=0D + @param[in] ... The variable argument list is a lis= t of tuples.=0D + Each tuple describes a range of LBA= s to erase=0D + and consists of the following:=0D + - An EFI_LBA that indicates the sta= rting LBA=0D + - A UINTN that indicates the number= of blocks=0D + to erase.=0D +=0D + The list is terminated with an=0D + EFI_LBA_LIST_TERMINATOR.=0D +=0D + @retval EFI_SUCCESS The erase request successfully comp= leted.=0D +=0D + @retval EFI_ACCESS_DENIED The firmware volume is in the Write= Disabled=0D + state.=0D +=0D + @retval EFI_DEVICE_ERROR The block device is not functioning= correctly=0D + and could not be written.=0D + The firmware device may have been p= artially=0D + erased.=0D +=0D + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in th= e variable=0D + argument list do not exist in the fi= rmware=0D + volume.=0D +=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +FvbEraseBlocks (=0D + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,=0D + ...=0D + )=0D +{=0D + EFI_STATUS Status;=0D + VA_LIST Args;=0D + UINTN BlockAddress; // Physical address of Lba to erase=0D + EFI_LBA StartingLba; // Lba from which we start erasing=0D + UINTN NumOfLba; // Number of Lba blocks to erase=0D + NOR_FLASH_INSTANCE *Instance;=0D +=0D + Instance =3D INSTANCE_FROM_FVB_THIS (This);=0D +=0D + DEBUG ((DEBUG_INFO, "FvbEraseBlocks()\n"));=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + // Before erasing, check the entire list of parameters to ensure=0D + // all specified blocks are valid=0D +=0D + VA_START (Args, This);=0D + do {=0D + // Get the Lba from which we start erasing=0D + StartingLba =3D VA_ARG (Args, EFI_LBA);=0D +=0D + // Have we reached the end of the list?=0D + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) {=0D + break;=0D + }=0D +=0D + // How many Lba blocks are we requested to erase?=0D + NumOfLba =3D VA_ARG (Args, UINT32);=0D +=0D + // All blocks must be within range=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "FvbEraseBlocks: Check if: ( StartingLba=3D%ld + NumOfLba=3D%d - 1 )= > LastBlock=3D%ld.\n",=0D + Instance->StartLba + StartingLba,=0D + NumOfLba,=0D + Instance->LastBlock=0D + ));=0D + if ((NumOfLba =3D=3D 0) ||=0D + ((Instance->StartLba + StartingLba + NumOfLba - 1) >=0D + Instance->LastBlock))=0D + {=0D + VA_END (Args);=0D + DEBUG ((=0D + DEBUG_ERROR,=0D + "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"=0D + ));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D + } while (TRUE);=0D +=0D + VA_END (Args);=0D +=0D + VA_START (Args, This);=0D + do {=0D + // Get the Lba from which we start erasing=0D + StartingLba =3D VA_ARG (Args, EFI_LBA);=0D +=0D + // Have we reached the end of the list?=0D + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) {=0D + // Exit the while loop=0D + break;=0D + }=0D +=0D + // How many Lba blocks are we requested to erase?=0D + NumOfLba =3D VA_ARG (Args, UINT32);=0D +=0D + // Go through each one and erase it=0D + while (NumOfLba > 0) {=0D + // Get the physical address of Lba to erase=0D + BlockAddress =3D GET_NOR_BLOCK_ADDRESS (=0D + Instance->RegionBaseAddress,=0D + Instance->StartLba + StartingLba,=0D + Instance->BlockSize=0D + );=0D +=0D + // Erase it=0D + DEBUG ((=0D + DEBUG_INFO,=0D + "FvbEraseBlocks: Erasing Lba=3D%ld @ 0x%08x.\n",=0D + Instance->StartLba + StartingLba,=0D + BlockAddress=0D + ));=0D + Status =3D NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress= );=0D + if (EFI_ERROR (Status)) {=0D + VA_END (Args);=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + // Move to the next Lba=0D + StartingLba++;=0D + NumOfLba--;=0D + }=0D + } while (TRUE);=0D +=0D + VA_END (Args);=0D +=0D + return Status;=0D +}=0D --=20 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] -=-=-=-=-=-=-=-=-=-=-=-