From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2a00:1450:400c:c09::22b; helo=mail-wm0-x22b.google.com; envelope-from=leif.lindholm@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-wm0-x22b.google.com (mail-wm0-x22b.google.com [IPv6:2a00:1450:400c:c09::22b]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 4B73320352611 for ; Thu, 26 Oct 2017 14:16:00 -0700 (PDT) Received: by mail-wm0-x22b.google.com with SMTP id m72so75457wmc.1 for ; Thu, 26 Oct 2017 14:19:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=c1xUeSV5Bh/2Uz/oo8wqwp0qAz6doEugtJfOy8k/+1c=; b=O+32lZ2IqJkiLM0ZQX/FIgaMHfQCPGrwHW2De3WHEObvR66CFPnEmN+UoRmZBGTgIU Syc/YJQso2OkCYo6xIrtNlxDy2pPpMmxwjNx1DUvE9+qQN4uk1NjlTSLTi46kF983WWl O6icxx1RUTEi5hidavth45+APzkv2L/pEroNI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=c1xUeSV5Bh/2Uz/oo8wqwp0qAz6doEugtJfOy8k/+1c=; b=PJeWTDofNLwbC1PAOT2fDlnsY5+3uiwthevic2ETKsgM8Px3+kvdUcSFFmbmpwYlGZ THcTzKqkzXi5ABAEDhrDSuos54VDpx3m7VG7IsCNfN4wbOWEClR2M3YblZloUMo8ix7p zEL5TJVweyrhsHGmTs8Ak/pl3LPp+8Uo2342GwF+rwKnvv9pc0YHHYm9xkBWa6OQKxmk La+bsXdarn8xyN/Cs/Dsc3srTQk+hKau+mg163wq/VgcyiRGvhX1AZREEQ8d/DMAZKHl twtx27QF4ST9UedsvFaohRZpB2mQ78IWmLAOsa0F8ExLz0oNtzEDHW7a+Uu8y8w0W3AN Jd6w== X-Gm-Message-State: AMCzsaUpK8q4r0vje4rZiEtNcrvb8f2J1ax2YuXB4NuqJcCQ0UuQWxM9 B3B69LchKhPUFnypfZ234IJTExUSlR0= X-Google-Smtp-Source: ABhQp+RlC6snfr1QPXOPE37gmzKlIGPf55sUEpjakBxNYEA2DInu619wGaBVdbm44EbmBzsiUuBq/A== X-Received: by 10.28.30.22 with SMTP id e22mr172922wme.121.1509052782508; Thu, 26 Oct 2017 14:19:42 -0700 (PDT) Received: from bivouac.eciton.net (bivouac.eciton.net. [2a00:1098:0:86:1000:23:0:2]) by smtp.gmail.com with ESMTPSA id a13sm5050592wrf.48.2017.10.26.14.19.41 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 26 Oct 2017 14:19:41 -0700 (PDT) Date: Thu, 26 Oct 2017 22:19:39 +0100 From: Leif Lindholm To: Ard Biesheuvel Cc: edk2-devel@lists.01.org, daniel.thompson@linaro.org, masami.hiramatsu@linaro.org Message-ID: <20171026211939.7qace3rpz4ffnbrz@bivouac.eciton.net> References: <20171025175947.22798-1-ard.biesheuvel@linaro.org> <20171025175947.22798-14-ard.biesheuvel@linaro.org> MIME-Version: 1.0 In-Reply-To: <20171025175947.22798-14-ard.biesheuvel@linaro.org> User-Agent: NeoMutt/20170113 (1.7.2) Subject: Re: [PATCH edk2-platforms v2 13/23] Silicon/Socionext: add driver for SPI NOR flash X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 26 Oct 2017 21:16:00 -0000 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Wed, Oct 25, 2017 at 06:59:37PM +0100, Ard Biesheuvel wrote: > From: Pipat Methavanitpong > > This imports the driver sources provided by Socionext for the FIP006 > SPI NOR flash device found on SynQuacer SoCs. It has been slightly > tweaked to bring it up to date with the changes made on the EDK2 side > since it was forked. > > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Pipat Methavanitpong > > [various tweaks and bugfixes] > > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Ard Biesheuvel Do we need Contributed-under twice? I'm not sure that carries any legal significane anyway. Sorry, I would love to trim the below, but there are minor comments spread throughout. > --- > Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec | 31 + > Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf | 79 ++ > Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Reg.h | 244 ++++ > Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashBlockIoDxe.c | 138 ++ > Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c | 1376 ++++++++++++++++++++ > Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h | 314 +++++ > Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c | 859 ++++++++++++ > 7 files changed, 3041 insertions(+) > > diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec > new file mode 100644 > index 000000000000..aec95bc82387 > --- /dev/null > +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec > @@ -0,0 +1,31 @@ > +## @file > +# Socionext FIP006 High-Speed SPI Controller with NOR Flash Driver > +# > +# Copyright (c) 2017, Socionext Inc. All rights reserved.
> +# > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > +## > + > +[Defines] > + DEC_SPECIFICATION = 0x0001001A > + PACKAGE_NAME = Fip006DxePkg > + PACKAGE_GUID = ABC7870B-FE82-4DAD-8179-FEC5F5194FA0 > + PACKAGE_VERSION = 0.1 > + > +[Guids] > + gFip006DxeTokenSpaceGuid = {0x4D45399E, 0x98F9, 0x4127, {0x8F, 0xB9,0xF8, 0xDE, 0x22, 0xA1, 0x09, 0x2C}} > + > +[PcdsFixedAtBuild] > + gFip006DxeTokenSpaceGuid.PcdFip006DxeRegBaseAddress|0x0|UINT32|0x00000001 > + gFip006DxeTokenSpaceGuid.PcdFip006DxeMemBaseAddress|0x0|UINT32|0x00000002 > + gFip006DxeTokenSpaceGuid.PcdN25qSlaveId|0x0|UINT8|0x00000003 > + gFip006DxeTokenSpaceGuid.PcdN25qBlockSize|256|UINT32|0x00000004 > + gFip006DxeTokenSpaceGuid.PcdN25qBlockCount|524288|UINT32|0x00000005 > + > diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf > new file mode 100644 > index 000000000000..145aeb442d90 > --- /dev/null > +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf > @@ -0,0 +1,79 @@ > +## @file > +# Socionext FIP006 High-Speed SPI Controller with NOR Flash Driver > +# > +# Copyright (c) 2017, Socionext Inc. All rights reserved.
> +# Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> +# > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > +## > + > + > +[Defines] > + INF_VERSION = 0x0001001A > + BASE_NAME = Fip006Dxe > + FILE_GUID = 44F7D21F-C36F-4766-BC5B-C72E97E6897B > + MODULE_TYPE = DXE_RUNTIME_DRIVER > + VERSION_STRING = 0.1 > + ENTRY_POINT = NorFlashInitialise > + > +[Sources] > + NorFlashDxe.c > + NorFlashBlockIoDxe.c > + NorFlashFvbDxe.c Sort? > + > +[Packages] > + ArmPlatformPkg/ArmPlatformPkg.dec > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + DevicePathLib > + DxeServicesTableLib > + HobLib > + IoLib > + MemoryAllocationLib > + NorFlashPlatformLib > + UefiLib Move down two rows? > + UefiBootServicesTableLib > + UefiDriverEntryPoint > + UefiRuntimeLib > + UefiRuntimeServicesTableLib > + > +[Guids] > + gEfiAuthenticatedVariableGuid > + gEfiEventVirtualAddressChangeGuid > + gEfiSystemNvDataFvGuid > + gEfiVariableGuid > + > +[Protocols] > + gEfiBlockIoProtocolGuid > + gEfiDevicePathProtocolGuid > + gEfiDiskIoProtocolGuid > + gEfiFirmwareVolumeBlockProtocolGuid > + > +[FixedPcd] > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize > + gFip006DxeTokenSpaceGuid.PcdFip006DxeRegBaseAddress > + gFip006DxeTokenSpaceGuid.PcdFip006DxeMemBaseAddress > + > +[Depex] > + # > + # NorFlashDxe must be loaded before VariableRuntimeDxe in case empty flash needs populating with default values > + # > + BEFORE gVariableRuntimeDxeFileGuid > diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Reg.h b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Reg.h > new file mode 100644 > index 000000000000..3d758dc492f6 > --- /dev/null > +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Reg.h > @@ -0,0 +1,244 @@ > +/** @file > + Socionext FIP006 Register List > + > + Copyright (c) 2017, Socionext Inc. All rights reserved.
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> + > + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the BSD License > + which accompanies this distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#ifndef __EFI_FIP006_REG_H__ > +#define __EFI_FIP006_REG_H__ > + > +#define FIP006_REG_MCTRL 0x00 // Module Control > +typedef union { > + UINT32 Raw : 32; > + struct { > + BOOLEAN MEN : 1; > + BOOLEAN CSEN : 1; > +#define MCTRL_CSEN_DIRECT 0 > +#define MCTRL_CSEN_CS 1 > + BOOLEAN CDSS : 1; > +#define MCTRL_CDSS_IHCLK 0 > +#define MCTRL_CDSS_IPCLK 1 > + BOOLEAN MES : 1; > +#define MCTRL_MES_READY 1 > + UINT8 : 4; > + UINT8 : 8; > + UINT8 : 8; > + UINT8 : 8; > + }; > +} FIP006_MCTRL; > + > +#define FIP006_REG_PCC0 0x04 // Peripheral Communication Control 0 > +#define FIP006_REG_PCC1 0x08 // Peripheral Communication Control 1 > +#define FIP006_REG_PCC2 0x0C // Peripheral Communication Control 2 > +#define FIP006_REG_PCC3 0x10 // Peripheral Communication Control 3 > +typedef union { > + UINT32 Raw : 32; > + struct { > + BOOLEAN CPHA : 1; > + BOOLEAN CPOL : 1; > + BOOLEAN ACES : 1; > + BOOLEAN RTM : 1; > + BOOLEAN SSPOL : 1; > + UINT8 SS2CD : 2; > + BOOLEAN SDIR : 1; > +#define PCC_SDIR_MS_BIT 0 > +#define PCC_SDIR_LS_BIT 1 > + BOOLEAN SENDIAN : 1; > +#define PCC_SENDIAN_BIG 0 > +#define PCC_SENDIAN_LITTLE 1 > + UINT8 CDRS : 7; > + BOOLEAN SAFESYNC : 1; > + UINT8 WRDSEL : 4; > + UINT8 RDDSEL : 2; > + UINT8 : 1; > + UINT8 : 8; > + } Reg; > +} FIP006_PCC; > +typedef FIP006_PCC FIP006_PCC0, FIP006_PCC1, FIP006_PCC2, FIP006_PCC3; > + > +#define FIP006_REG_TXF 0x14 // Tx Interrupt Flag > +#define TXF_TSSRS BIT6 > +#define TXF_TFMTS BIT5 > +#define TXF_TFLETS BIT4 > +#define TXF_TFUS BIT3 > +#define TXF_TFOS BIT2 > +#define TXF_TFES BIT1 > +#define TXF_TFFS BIT0 > + > +#define FIP006_REG_TXE 0x18 // Tx Interrupt Enable > +#define TXE_TSSRE BIT6 > +#define TXE_TFMTE BIT5 > +#define TXE_TFLETE BIT4 > +#define TXE_TFUE BIT3 > +#define TXE_TFOE BIT2 > +#define TXE_TFEE BIT1 > +#define TXE_TFFE BIT0 > + > +#define FIP006_REG_TXC 0x1C // Tx Interrupt Clear > +#define TXC_TSSRC BIT6 > +#define TXC_TFMTC BIT5 > +#define TXC_TFLETC BIT4 > +#define TXC_TFUC BIT3 > +#define TXC_TFOC BIT2 > +#define TXC_TFEC BIT1 > +#define TXC_TFFC BIT0 > + > +#define FIP006_REG_RXF 0x20 // Rx Interrupt Flag > +#define RXF_RSSRS BIT6 > +#define RXF_RFMTS BIT5 > +#define RXF_RFLETS BIT4 > +#define RXF_RFUS BIT3 > +#define RXF_RFOS BIT2 > +#define RXF_RFES BIT1 > +#define RXF_RFFS BIT0 > + > +#define FIP006_REG_RXE 0x24 // Rx Interrupt Enable > +#define RXE_RSSRE BIT6 > +#define RXE_RFMTE BIT5 > +#define RXE_RFLETE BIT4 > +#define RXE_RFUE BIT3 > +#define RXE_RFOE BIT2 > +#define RXE_RFEE BIT1 > +#define RXE_RFFE BIT0 > + > +#define FIP006_REG_RXC 0x28 // Rx Interrupt Clear > +#define RXC_RSSRC BIT6 > +#define RXC_RFMTC BIT5 > +#define RXC_RFLETC BIT4 > +#define RXC_RFUC BIT3 > +#define RXC_RFOC BIT2 > +#define RXC_RFEC BIT1 > +#define RXC_RFFC BIT0 > + > +#define FIP006_REG_FAULTF 0x2C // Error Interrupt Status > +#define FAULTF_DRCBSFS BIT4 > +#define FAULTF_DWCBSFS BIT3 > +#define FAULTF_PVFS BIT2 > +#define FAULTF_WAFS BIT1 > +#define FAULTF_UMAFS BIT0 > + > +#define FIP006_REG_FAULTC 0x30 // Error Interrupt Clear > +#define FAULTC_DRCBSFC BIT4 > +#define FAULTC_DWCBSFC BIT3 > +#define FAULTC_PVFC BIT2 > +#define FAULTC_WAFC BIT1 > +#define FAULTC_UMAFC BIT0 > + > +#define FIP006_REG_DM_CFG 0x34 // Direct Mode DMA Configuration > +#define DM_CFG_MSTARTEN BIT2 > +#define DM_CFG_SSDC BIT1 > + > +#define FIP006_REG_DM_DMA 0x35 // Direct Mode DMA Enable > +#define DM_DMA_TXDMAEN BIT1 > +#define DM_DMA_RXDMAEN BIT0 > + > +#define FIP006_REG_DM_START 0x38 // Direct Mode Start Transmission > +#define DM_START BIT0 > +#define FIP006_REG_DM_STOP 0x39 // Direct Mode Stop Transmission > +#define DM_STOP BIT0 > + > +#define FIP006_REG_DM_PSEL 0x3A // Direct Mode Peripheral Select > +#define DM_PSEL (BIT1 | BIT0) > + > +#define FIP006_REG_DM_TRP 0x3B // Direct Mode Transmission Protocol > +#define DM_TRP (BIT3 | BIT2 | BIT1 | BIT0) > + > +#define FIP006_REG_DM_BCC 0x3C // Direct Mode Byte Count Control > +#define FIP006_REG_DM_BCS 0x3E // Direct Mode Byte Count Status > + > +#define FIP006_REG_DM_STATUS 0x40 // Direct Mode Status > +#define DM_STATUS_TXFLEVEL (BIT20 | BIT19 | BIT18 | BIT17 | BIT16) > +#define DM_STATUS_RXFLEVEL (BIT20 | BIT19 | BIT18 | BIT17 | BIT16) > +#define DM_STATUS_TXACTIVE BIT1 > +#define DM_STATUS_RXACTIVE BIT0 > + > +#define FIP006_REG_FIFO_CFG 0x4C // FIFO Configuration > +#define FIFO_CFG_TXFLSH BIT12 > +#define FIFO_CFG_RXFLSH BIT11 > +#define FIFO_CFG_TXCTRL BIT10 > +#define FIFO_CFG_FWIDTH (BIT9 | BIT8) > +#define FIFO_CFG_TXFTH (BIT7 | BIT6 | BIT5 | BIT4) > +#define FIFO_CFG_RXFTH (BIT3 | BIT2 | BIT1 | BIT0) > + > +#define FIP006_REG_FIFO_TX 0x50 // 16 32-bit Tx FIFO > +#define FIP006_REG_FIFO_RX 0x90 // 16 32-bit Rx FIFO > + > +#define FIP006_REG_CS_CFG 0xD0 // Command Sequencer Configuration > +typedef union { > + UINT32 Raw : 32; > + struct { > + BOOLEAN SRAM : 1; > +#define CS_CFG_SRAM_RO 0 > +#define CS_CFG_SRAM_RW 1 > + UINT8 MBM : 2; > +#define CS_CFG_MBM_SINGLE 0 > +#define CS_CFG_MBM_DUAL 1 > +#define CS_CFG_MBM_QUAD 2 > + BOOLEAN SPICHNG : 1; > + BOOLEAN BOOTEN : 1; > + BOOLEAN BSEL : 1; > + UINT8 : 2; > + BOOLEAN SSEL0EN : 1; > + BOOLEAN SSEL1EN : 1; > + BOOLEAN SSEL2EN : 1; > + BOOLEAN SSEL3EN : 1; > + UINT8 : 4; > + BOOLEAN MSEL : 4; > + UINT8 : 4; > + UINT8 : 8; > + } Reg; > +} FIP006_CS_CFG; > + > +#define FIP006_REG_CS_ITIME 0xD4 // Command Sequencer Idle Timer > +typedef union { > + UINT32 Raw : 32; > + struct { > + UINT16 ITIME : 16; > + UINT16 : 16; > + } Reg; > +} FIP006_CS_ITIME; > +#define FIP006_REG_CS_AEXT 0xD8 // Command Sequencer Address Extension > +typedef union { > + UINT32 Raw : 32; > + struct { > + UINT16 : 13; > + UINT32 AEXT : 19; > + } Reg; > +} FIP006_CS_AEXT; > + > +#define FIP006_REG_CS_RD 0xDC // Command Sequencer Read Control > +#define CS_RD_DEPTH 8 > +#define FIP006_REG_CS_WR 0xEC // Command Sequencer Write Control > +#define CS_WR_DEPTH 8 > +typedef union { > + UINT16 Raw : 16; > + struct { > + BOOLEAN DEC : 1; > + UINT8 TRP : 2; > + BOOLEAN CONT : 1; > + UINT8 : 4; > + union { > + UINT8 Data : 8; > + struct { > + UINT8 Data : 3; > + UINT8 : 5; > + } Cmd; > + } Payload; > + } Reg; > +} FIP006_CS_CMD; > +typedef FIP006_CS_CMD FIP006_CS_RD, FIP006_CS_WR; > + > +#define FIP006_REG_MID 0xFC // Command Sequencer Module ID > +typedef UINT32 FIP006_MID; > + > +#endif > diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashBlockIoDxe.c b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashBlockIoDxe.c > new file mode 100644 > index 000000000000..b41f5003217c > --- /dev/null > +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashBlockIoDxe.c > @@ -0,0 +1,138 @@ > +/** @file NorFlashBlockIoDxe.c > + > + Copyright (c) 2011-2013, ARM Ltd. All rights reserved.
> + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> + > + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the BSD License > + which accompanies this distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include > +#include > + > +#include "NorFlashDxe.h" > + > +// > +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.Reset > +// > +EFI_STATUS > +EFIAPI > +NorFlashBlockIoReset ( > + IN EFI_BLOCK_IO_PROTOCOL *This, > + IN BOOLEAN ExtendedVerification > + ) > +{ > + NOR_FLASH_INSTANCE *Instance; > + > + Instance = INSTANCE_FROM_BLKIO_THIS(This); > + > + DEBUG ((DEBUG_BLKIO, "NorFlashBlockIoReset(MediaId=0x%x)\n", > + This->Media->MediaId)); > + > + return NorFlashReset (Instance); > +} > + > +// > +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.ReadBlocks > +// > +EFI_STATUS > +EFIAPI > +NorFlashBlockIoReadBlocks ( > + IN EFI_BLOCK_IO_PROTOCOL *This, > + IN UINT32 MediaId, > + IN EFI_LBA Lba, > + IN UINTN BufferSizeInBytes, > + OUT VOID *Buffer > + ) > +{ > + NOR_FLASH_INSTANCE *Instance; > + EFI_STATUS Status; > + EFI_BLOCK_IO_MEDIA *Media; > + > + if (This == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + Instance = INSTANCE_FROM_BLKIO_THIS(This); > + Media = This->Media; > + > + DEBUG ((DEBUG_BLKIO, > + "NorFlashBlockIoReadBlocks(MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes " > + "(%d kB), BufferPtr @ 0x%08x)\n", MediaId, Lba, BufferSizeInBytes, Buffer)); > + > + if (!Media) { > + Status = EFI_INVALID_PARAMETER; > + } else if (!Media->MediaPresent) { > + Status = EFI_NO_MEDIA; > + } else if (Media->MediaId != MediaId) { > + Status = EFI_MEDIA_CHANGED; > + } else if ((Media->IoAlign > 2) && > + (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) { > + Status = EFI_INVALID_PARAMETER; > + } else { > + Status = NorFlashReadBlocks (Instance, Lba, BufferSizeInBytes, Buffer); > + } > + > + return Status; > +} > + > +// > +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.WriteBlocks > +// > +EFI_STATUS > +EFIAPI > +NorFlashBlockIoWriteBlocks ( > + IN EFI_BLOCK_IO_PROTOCOL *This, > + IN UINT32 MediaId, > + IN EFI_LBA Lba, > + IN UINTN BufferSizeInBytes, > + IN VOID *Buffer > + ) > +{ > + NOR_FLASH_INSTANCE *Instance; > + EFI_STATUS Status; > + > + Instance = INSTANCE_FROM_BLKIO_THIS(This); > + > + DEBUG ((DEBUG_BLKIO, > + "NorFlashBlockIoWriteBlocks(MediaId=0x%x, Lba=%ld, BufferSize=0x%x bytes " > + "(%d kB), BufferPtr @ 0x%08x)\n", MediaId, Lba, BufferSizeInBytes, Buffer)); > + > + if( !This->Media->MediaPresent ) { > + Status = EFI_NO_MEDIA; > + } else if( This->Media->MediaId != MediaId ) { > + Status = EFI_MEDIA_CHANGED; > + } else if( This->Media->ReadOnly ) { > + Status = EFI_WRITE_PROTECTED; > + } else { > + Status = NorFlashWriteBlocks (Instance,Lba,BufferSizeInBytes,Buffer); > + } > + > + return Status; > +} > + > +// > +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.FlushBlocks > +// > +EFI_STATUS > +EFIAPI > +NorFlashBlockIoFlushBlocks ( > + IN EFI_BLOCK_IO_PROTOCOL *This > + ) > +{ > + // No Flush required for the NOR Flash driver > + // because cache operations are not permitted. > + > + DEBUG ((DEBUG_BLKIO, > + "NorFlashBlockIoFlushBlocks: Function NOT IMPLEMENTED (not required).\n")); > + > + // Nothing to do so just return without error > + return EFI_SUCCESS; > +} > diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c > new file mode 100644 > index 000000000000..d9cf11dd5be5 > --- /dev/null > +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c > @@ -0,0 +1,1376 @@ > +/** @file NorFlashDxe.c > + > + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
> + Copyright (c) 2017, Socionext Inc. All rights reserved.
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> + > + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#include > +#include > +#include > +#include > +#include Move up one row? > + > +#include "NorFlashDxe.h" > + > +STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent; > + > +// > +// Global variable declarations > +// > +STATIC NOR_FLASH_INSTANCE **mNorFlashInstances; > +STATIC UINT32 mNorFlashDeviceCount; > + > +STATIC CONST UINT16 mFip006NullCmdSeq[] = { > + CSDC (0x07, 0, CSDC_TRP_MBM, 1), > + CSDC (0x07, 0, CSDC_TRP_MBM, 1), > + CSDC (0x07, 0, CSDC_TRP_MBM, 1), > + CSDC (0x07, 0, CSDC_TRP_MBM, 1), > + CSDC (0x07, 0, CSDC_TRP_MBM, 1), > + CSDC (0x07, 0, CSDC_TRP_MBM, 1), > + CSDC (0x07, 0, CSDC_TRP_MBM, 1), > + CSDC (0x07, 0, CSDC_TRP_MBM, 1) Can we get some helpful #defines for these live-coded values please? > +}; > + > +STATIC CONST CSDC_DEFINITION mN25qCSDCDefTable[] = { > + // Identification Operations > + { 0x9F, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + // Register Operations > + { 0x05, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + { 0x01, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + { 0xE8, TRUE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + { 0x70, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + { 0xB5, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + { 0x85, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + { 0x65, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + // Read Operations > + { 0x13, TRUE, TRUE, FALSE, FALSE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + // Write Operations > + { 0x02, TRUE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, > + { 0x32, TRUE, FALSE, FALSE, TRUE, CS_CFG_MBM_QUAD, CSDC_TRP_SINGLE }, > + // Erase Operations > + { 0xD8, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, CSDC_TRP_SINGLE }, Can we get some helpful #defines for these live-coded values please? > +}; > + > +STATIC > +EFI_STATUS > +NorFlashSetHostCSDC ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN BOOLEAN ReadWrite, > + IN CONST UINT16 CSDC[8] > + ) > +{ > + EFI_PHYSICAL_ADDRESS Dst; > + UINTN Index; > + > + Dst = Instance->HostRegisterBaseAddress > + + (ReadWrite ? FIP006_REG_CS_WR : FIP006_REG_CS_RD); > + for (Index = 0; Index < 8; Index++) { > + MmioWrite16 (Dst + (Index << 1), CSDC[Index]); > + } > + return EFI_SUCCESS; > +} > + > +STATIC > +CONST CSDC_DEFINITION * > +NorFlashGetCmdDef ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINT8 Code > + ) > +{ > + CONST CSDC_DEFINITION *Cmd; > + UINTN Index; > + > + Cmd = NULL; > + for (Index = 0; Index < Instance->CmdTableSize; Index++) { > + if (Code == Instance->CmdTable[Index].Code) { > + Cmd = &Instance->CmdTable[Index]; > + break; > + } > + } > + return Cmd; > +} > + > +STATIC > +EFI_STATUS > +GenCSDC ( > + IN UINT8 Cmd, > + IN BOOLEAN AddrAccess, > + IN BOOLEAN AddrMode4Byte, > + IN BOOLEAN HighZ, > + IN UINT8 TransferMode, > + OUT UINT16 CmdSeq[8] > + ) > +{ > + UINTN Index; > + > + if (!CmdSeq) { > + return EFI_INVALID_PARAMETER; > + } > + > + Index = 0; > + CopyMem (CmdSeq, mFip006NullCmdSeq, 8 * sizeof (UINT16)); > + > + CmdSeq[Index++] = CSDC (Cmd, 0, TransferMode, 0); > + if (AddrAccess) { > + if (AddrMode4Byte) { > + CmdSeq[Index++] = CSDC (0x03, 0, TransferMode, 1); > + } > + CmdSeq[Index++] = CSDC (0x02, 0, TransferMode, 1); > + CmdSeq[Index++] = CSDC (0x01, 0, TransferMode, 1); > + CmdSeq[Index++] = CSDC (0x00, 0, TransferMode, 1); > + } > + if (HighZ) { > + CmdSeq[Index++] = CSDC (0x04, 0, TransferMode, 1); Can we get some helpful #defines for these live-coded values please? (That includes the 1s and 0s. > + } > + > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +NorFlashSetHostCommand ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINT8 Code > + ) > +{ > + CONST CSDC_DEFINITION *Cmd; > + UINT16 CSDC[8]; Feels like we should be able to have a #define for that 8 as well. > + > + Cmd = NorFlashGetCmdDef(Instance, Code); > + if (Cmd == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + GenCSDC ( > + Cmd->Code, > + Cmd->AddrAccess, > + Cmd->AddrMode4Byte, > + Cmd->HighZ, > + Cmd->CsdcTrp, > + CSDC > + ); > + NorFlashSetHostCSDC (Instance, Cmd->ReadWrite, CSDC); > + return EFI_SUCCESS; > +} > + > +STATIC > +UINT8 > +NorFlashReadStatusRegister ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINTN SR_Address > + ) > +{ > + UINT8 StatusRegister; > + > + NorFlashSetHostCommand (Instance, 0x05); > + StatusRegister = NOR_FLASH_READ_BYTE (Instance, 0); > + NorFlashSetHostCommand (Instance, 0x13); Can we get some helpful #defines for these live-coded values please? > + return StatusRegister; > +} > + > +STATIC > +EFI_STATUS > +NorFlashWaitProgramErase ( > + IN NOR_FLASH_INSTANCE *Instance > + ) > +{ > + BOOLEAN SRegDone; > + BOOLEAN FSRegDone; > + > + DEBUG ((DEBUG_BLKIO, "NorFlashWaitProgramErase()\n")); > + > + do { > + SRegDone = (NorFlashReadStatusRegister (Instance, 0) & BIT0) == 0; > + FSRegDone = TRUE; > + if (Instance->Flags & NOR_FLASH_POLL_FSR) { > + NorFlashSetHostCommand (Instance, 0x70); > + FSRegDone = (NOR_FLASH_READ_BYTE (Instance, 0) & BIT7) == BIT7; > + } > + } while (!SRegDone || !FSRegDone); > + NorFlashSetHostCommand (Instance, 0x13); Can we get some helpful #defines for these live-coded values please? (BIT* is no more descriptive than 0x13.) > + return EFI_SUCCESS; > +} > + > +// TODO: implement lock checking > +STATIC > +BOOLEAN > +NorFlashBlockIsLocked ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINTN BlockAddress > + ) > +{ > + return FALSE; > +} > + > +// TODO: implement sector unlocking > +STATIC > +EFI_STATUS > +NorFlashUnlockSingleBlock ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINTN BlockAddress > + ) > +{ > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +NorFlashUnlockSingleBlockIfNecessary ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINTN BlockAddress > + ) > +{ > + EFI_STATUS Status; > + > + Status = EFI_SUCCESS; > + > + if (NorFlashBlockIsLocked (Instance, BlockAddress) == TRUE) { > + Status = NorFlashUnlockSingleBlock (Instance, BlockAddress); > + } > + > + return Status; > +} > + > +STATIC > +EFI_STATUS > +NorFlashEnableWrite ( > + IN NOR_FLASH_INSTANCE *Instance > + ) > +{ > + EFI_STATUS Status; > + UINT8 StatusRegister; > + UINTN Retry; > + > + DEBUG ((DEBUG_BLKIO, "NorFlashEnableWrite()\n")); > + > + Status = EFI_DEVICE_ERROR; > + Retry = 100; Why 100 retries? Use a delay instead? Barrier? > + > + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); > + while (Retry > 0 && EFI_ERROR (Status)) { > + NOR_FLASH_WRITE_BYTE (Instance, 0, 0x06); > + StatusRegister = NorFlashReadStatusRegister (Instance, 0); > + Status = (StatusRegister & BIT1) ? EFI_SUCCESS : EFI_DEVICE_ERROR; Can we get some helpful #defines for these live-coded values please? > + Retry--; > + } > + return Status; > +} > + > +STATIC > +EFI_STATUS > +NorFlashDisableWrite ( > + IN NOR_FLASH_INSTANCE *Instance > + ) > +{ > + EFI_STATUS Status; > + UINT8 StatusRegister; > + UINTN Retry; > + > + DEBUG ((DEBUG_BLKIO, "NorFlashDisableWrite()\n")); > + > + Status = EFI_DEVICE_ERROR; > + Retry = 10; 10 retries is better than 100, but still quite arbitrary. Delay? Barrier? > + > + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); > + while (Retry > 0 && EFI_ERROR (Status)) { > + NOR_FLASH_WRITE_BYTE (Instance, 0, 0x04); > + StatusRegister = NorFlashReadStatusRegister (Instance, 0); > + Status = (StatusRegister & BIT1) ? EFI_DEVICE_ERROR : EFI_SUCCESS; Can we get some helpful #defines for these live-coded values please? > + Retry--; > + } > + return Status; > +} > + > +/** > + * The following function presumes that the block has already been unlocked. > + **/ > +// > +// TODO: Support 4-byte addressing erase block > +// > +// The current implementation supports only 3-byte addressing > +// i.e. 64KB-block 0x00-0xFF can be erased. > +// To make a 3-byte address fits in a memory access, the implementation > +// merges the 1-byte erase cmd and a 3-byte address to form a 4-byte data. > +// > +// To support 4-byte addresing, it could be implemented by either > +// 1. configuring to select bottom/top of a flash device > +// 2. entering 4-byte addressing mode and send erase cmd via cmd sequence > +// and a target 4-byte block address as data > +// > +// TODO: Handle endianess > +// > +// The current implementation assumes CPU is little-endian and > +// FIP006 is set to transfer from big-endian > +// > +// For exmaple: Data = 0xAABBCCDD > +// > +// Addr offset 00 01 02 03 > +// Data DD CC BB AA > +// Transfer Dir <---------- > +// > +STATIC > +EFI_STATUS > +NorFlashEraseSingleBlock ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINTN BlockAddress > + ) > +{ > + > + DEBUG ((DEBUG_BLKIO, "NorFlashEraseSingleBlock(BlockAddress=0x%08x)\n", BlockAddress)); > + > + if (EFI_ERROR (NorFlashEnableWrite (Instance))) { > + return EFI_DEVICE_ERROR; > + } > + > + // > + // The virtual address chosen by the OS may have a different offset modulo > + // 16 MB than the physical address, so we need to subtract the region base > + // address before we can mask off a block index. Note that the relative > + // offset between device base address and region base address may have changed > + // as well, so we cannot use the device base address directly. > + // > + if (EfiAtRuntime()) { > + BlockAddress -= Instance->RegionBaseAddress; > + BlockAddress += Instance->OffsetLba * Instance->Media.BlockSize; > + } > + > + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); > + ((UINT32*)Instance->DeviceBaseAddress)[0] = (SwapBytes32 (BlockAddress & 0x00FFFFFF)) | 0xD8; This looks like a helper macro waiting to happen. > + NorFlashWaitProgramErase (Instance); > + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); > + > + if (EFI_ERROR (NorFlashDisableWrite (Instance))) { > + return EFI_DEVICE_ERROR; > + } > + return EFI_SUCCESS; > +} > + > +/** > + * This function unlock and erase an entire NOR Flash block. > + **/ > +EFI_STATUS > +NorFlashUnlockAndEraseSingleBlock ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINTN BlockAddress > + ) > +{ > + EFI_STATUS Status; > + UINTN Index; > + EFI_TPL OriginalTPL; > + BOOLEAN InterruptsEnabled; > + > + OriginalTPL = 0; > + InterruptsEnabled = FALSE; > + > + if (!EfiAtRuntime ()) { > + // Raise TPL to TPL_HIGH to stop anyone from interrupting us. > + OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); > + } else { > + InterruptsEnabled = SaveAndDisableInterrupts (); > + } > + > + Index = 0; > + // The block erase might fail a first time (SW bug ?). Retry it ... Not just missing barriers? > + do { > + // Unlock the block if we have to > + Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress); > + if (EFI_ERROR (Status)) { > + break; > + } > + Status = NorFlashEraseSingleBlock (Instance, BlockAddress); > + Index++; > + } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED)); > + > + if (Index == NOR_FLASH_ERASE_RETRY) { > + DEBUG ((DEBUG_ERROR, > + "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", > + BlockAddress,Index)); > + } > + > + if (!EfiAtRuntime ()) { > + // Interruptions can resume. > + gBS->RestoreTPL (OriginalTPL); > + } else if (InterruptsEnabled) { > + SetInterruptState (TRUE); > + } > + > + return Status; > +} > + > +STATIC > +EFI_STATUS > +NorFlashWriteSingleWord ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINTN WordAddress, > + IN UINT32 WriteData > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_BLKIO, > + "NorFlashWriteSingleWord(WordAddress=0x%08x, WriteData=0x%08x)\n", > + WordAddress, WriteData)); > + > + Status = EFI_SUCCESS; > + > + if (EFI_ERROR (NorFlashEnableWrite (Instance))) { > + return EFI_DEVICE_ERROR; > + } > + NorFlashSetHostCommand (Instance, 0x02); Can we get a helpful #define for this live-coded value please? > + MmioWrite32 (WordAddress, WriteData); > + NorFlashWaitProgramErase (Instance); > + > + NorFlashDisableWrite (Instance); > + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); > + return Status; > +} > + > +STATIC > +EFI_STATUS > +NorFlashWriteFullBlock ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINT32 *DataBuffer, > + IN UINT32 BlockSizeInWords > + ) > +{ > + EFI_STATUS Status; > + UINTN WordAddress; > + UINT32 WordIndex; > + UINTN BlockAddress; > + EFI_TPL OriginalTPL; > + BOOLEAN InterruptsEnabled; > + > + Status = EFI_SUCCESS; > + OriginalTPL = 0; > + InterruptsEnabled = FALSE; > + > + // Get the physical address of the block > + BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, > + BlockSizeInWords * 4); > + > + // Start writing from the first address at the start of the block > + WordAddress = BlockAddress; > + > + if (!EfiAtRuntime ()) { > + // Raise TPL to TPL_HIGH to stop anyone from interrupting us. > + OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); > + } else { > + InterruptsEnabled = SaveAndDisableInterrupts (); > + } > + > + Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, > + "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", > + BlockAddress)); > + goto EXIT; > + } > + > + for (WordIndex=0; > + WordIndex < BlockSizeInWords; > + WordIndex++, DataBuffer++, WordAddress += 4) { > + Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer); > + if (EFI_ERROR (Status)) { > + goto EXIT; > + } > + } > + > +EXIT: > + if (!EfiAtRuntime ()) { > + // Interruptions can resume. > + gBS->RestoreTPL (OriginalTPL); > + } else if (InterruptsEnabled) { > + SetInterruptState (TRUE); > + } > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, > + "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", > + WordAddress, Status)); > + } > + return Status; > +} > + > +EFI_STATUS > +NorFlashWriteBlocks ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINTN BufferSizeInBytes, > + IN VOID *Buffer > + ) > +{ > + UINT32 *pWriteBuffer; > + EFI_STATUS Status = EFI_SUCCESS; > + EFI_LBA CurrentBlock; > + UINT32 BlockSizeInWords; > + UINT32 NumBlocks; > + UINT32 BlockCount; > + > + // The buffer must be valid > + if (Buffer == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + if(Instance->Media.ReadOnly == TRUE) { > + return EFI_WRITE_PROTECTED; > + } > + > + // We must have some bytes to read > + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", > + BufferSizeInBytes)); > + if(BufferSizeInBytes == 0) { > + return EFI_BAD_BUFFER_SIZE; > + } > + > + // The size of the buffer must be a multiple of the block size > + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", > + Instance->Media.BlockSize)); > + if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) { > + return EFI_BAD_BUFFER_SIZE; > + } > + > + // All blocks must be within the device > + NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ; > + > + DEBUG ((DEBUG_BLKIO, > + "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, > + Instance->Media.LastBlock, Lba)); > + > + if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) { > + DEBUG ((DEBUG_ERROR, > + "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n")); > + return EFI_INVALID_PARAMETER; > + } > + > + BlockSizeInWords = Instance->Media.BlockSize / 4; > + > + // Because the target *Buffer is a pointer to VOID, we must put > + // all the data into a pointer to a proper data type, so use *ReadBuffer May be worth doing an ASSERT ((Buffer & 0x3) == 0) here. or ASSERT ((Buffer & (sizeof (UINT32) - 1))) to be more explicit. > + pWriteBuffer = (UINT32 *)Buffer; > + > + CurrentBlock = Lba; > + for (BlockCount = 0; > + BlockCount < NumBlocks; > + BlockCount++, CurrentBlock++, pWriteBuffer += BlockSizeInWords) { > + > + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", > + (UINTN)CurrentBlock)); > + > + Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, > + BlockSizeInWords); > + > + if (EFI_ERROR (Status)) { > + break; > + } > + } > + > + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status)); > + return Status; > +} > + > +EFI_STATUS > +NorFlashReadBlocks ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINTN BufferSizeInBytes, > + OUT VOID *Buffer > + ) > +{ > + UINT32 NumBlocks; > + UINTN StartAddress; > + > + DEBUG ((DEBUG_BLKIO, > + "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n", > + BufferSizeInBytes, Instance->Media.BlockSize, Instance->Media.LastBlock, > + Lba)); > + > + // The buffer must be valid > + if (Buffer == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // Return if we have not any byte to read > + if (BufferSizeInBytes == 0) { > + return EFI_SUCCESS; > + } > + > + // The size of the buffer must be a multiple of the block size > + if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) { > + return EFI_BAD_BUFFER_SIZE; > + } > + > + // All blocks must be within the device > + NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ; > + > + if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) { > + DEBUG ((DEBUG_ERROR, > + "NorFlashReadBlocks: ERROR - Read will exceed last block\n")); > + return EFI_INVALID_PARAMETER; > + } > + > + // Get the address to start reading from > + StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, > + Instance->Media.BlockSize); > + > + // Put the device into Read Array mode > + NorFlashSetHostCommand (Instance, 0x13); Can we get a helpful #define for this live-coded value please? > + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); > + > + // Readout the data > + CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes); > + > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +NorFlashRead ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINTN Offset, > + IN UINTN BufferSizeInBytes, > + OUT VOID *Buffer > + ) > +{ > + UINTN StartAddress; > + > + // The buffer must be valid > + if (Buffer == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + // Return if we have not any byte to read > + if (BufferSizeInBytes == 0) { > + return EFI_SUCCESS; > + } > + > + if (((Lba * Instance->Media.BlockSize) + Offset + BufferSizeInBytes) > > + Instance->Size) { > + DEBUG ((DEBUG_ERROR, > + "NorFlashRead: ERROR - Read will exceed device size.\n")); > + return EFI_INVALID_PARAMETER; > + } > + > + // Get the address to start reading from > + StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, > + Instance->Media.BlockSize); > + > + // Put the device into Read Array mode > + NorFlashSetHostCommand (Instance, 0x13); Same value, so reuse the same #define? > + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); > + > + // Readout the data > + CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes); > + > + return EFI_SUCCESS; > +} The above two functions look nearly identical. Could one be made to call the other with different parameters, or could the be merged into one with an operation type flag? > + > +/* > + Write a full or portion of a block. It must not span block boundaries; > + that is, Offset + *NumBytes <= Instance->Media.BlockSize. > +*/ > +EFI_STATUS > +NorFlashWriteSingleBlock ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINTN Offset, > + IN OUT UINTN *NumBytes, > + IN UINT8 *Buffer > + ) > +{ > + EFI_STATUS TempStatus; > + UINT32 Tmp; > + UINT32 TmpBuf; > + UINT32 WordToWrite; > + UINT32 Mask; > + BOOLEAN DoErase; > + UINTN BytesToWrite; > + UINTN CurOffset; > + UINTN WordAddr; > + UINTN BlockSize; > + UINTN BlockAddress; > + UINTN PrevBlockAddress; > + > + PrevBlockAddress = 0; > + > + if (!Instance->Initialized && Instance->Initialize) { > + Instance->Initialize(Instance); > + } > + > + DEBUG ((DEBUG_BLKIO, > + "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", > + Lba, Offset, *NumBytes, Buffer)); > + > + // Detect WriteDisabled state > + if (Instance->Media.ReadOnly == TRUE) { > + DEBUG ((DEBUG_ERROR, > + "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n")); > + // It is in WriteDisabled state, return an error right away > + return EFI_ACCESS_DENIED; > + } > + > + // Cache the block size to avoid de-referencing pointers all the time > + BlockSize = Instance->Media.BlockSize; > + > + // The write must not span block boundaries. > + // We need to check each variable individually because adding two large > + // values together overflows. > + if (Offset >= BlockSize || > + *NumBytes > BlockSize || > + (Offset + *NumBytes) > BlockSize) { > + DEBUG ((DEBUG_ERROR, > + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", > + Offset, *NumBytes, BlockSize )); > + return EFI_BAD_BUFFER_SIZE; > + } > + > + // We must have some bytes to write > + if (*NumBytes == 0) { > + DEBUG ((DEBUG_ERROR, > + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", > + Offset, *NumBytes, BlockSize )); > + return EFI_BAD_BUFFER_SIZE; > + } > + > + // Pick 128bytes as a good start for word operations as opposed to erasing the > + // block and writing the data regardless if an erase is really needed. > + // It looks like most individual NV variable writes are smaller than 128bytes. > + if (*NumBytes <= 128) { > + // Check to see if we need to erase before programming the data into NOR. > + // If the destination bits are only changing from 1s to 0s we can just write. > + // After a block is erased all bits in the block is set to 1. > + // If any byte requires us to erase we just give up and rewrite all of it. > + DoErase = FALSE; > + BytesToWrite = *NumBytes; > + CurOffset = Offset; > + > + while (BytesToWrite > 0) { > + // Read full word from NOR, splice as required. A word is the smallest > + // unit we can write. > + TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof(Tmp), > + &Tmp); > + if (EFI_ERROR (TempStatus)) { > + return EFI_DEVICE_ERROR; > + } > + > + // Physical address of word in NOR to write. > + WordAddr = (CurOffset & ~(0x3)) + > + GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, > + BlockSize); > + > + // The word of data that is to be written. > + TmpBuf = *((UINT32*)(Buffer + (*NumBytes - BytesToWrite))); > + > + // First do word aligned chunks. > + if ((CurOffset & 0x3) == 0) { > + if (BytesToWrite >= 4) { > + // Is the destination still in 'erased' state? > + if (~Tmp != 0) { > + // Check to see if we are only changing bits to zero. > + if ((Tmp ^ TmpBuf) & TmpBuf) { > + DoErase = TRUE; > + break; > + } > + } > + // Write this word to NOR > + WordToWrite = TmpBuf; > + CurOffset += sizeof(TmpBuf); > + BytesToWrite -= sizeof(TmpBuf); > + } else { > + // BytesToWrite < 4. Do small writes and left-overs > + Mask = ~((~0) << (BytesToWrite * 8)); > + // Mask out the bytes we want. > + TmpBuf &= Mask; > + // Is the destination still in 'erased' state? > + if ((Tmp & Mask) != Mask) { > + // Check to see if we are only changing bits to zero. > + if ((Tmp ^ TmpBuf) & TmpBuf) { > + DoErase = TRUE; > + break; > + } > + } > + // Merge old and new data. Write merged word to NOR > + WordToWrite = (Tmp & ~Mask) | TmpBuf; > + CurOffset += BytesToWrite; > + BytesToWrite = 0; > + } > + } else { > + // Do multiple words, but starting unaligned. > + if (BytesToWrite > (4 - (CurOffset & 0x3))) { > + Mask = ((~0) << ((CurOffset & 0x3) * 8)); > + // Mask out the bytes we want. > + TmpBuf &= Mask; > + // Is the destination still in 'erased' state? > + if ((Tmp & Mask) != Mask) { > + // Check to see if we are only changing bits to zero. > + if ((Tmp ^ TmpBuf) & TmpBuf) { > + DoErase = TRUE; > + break; > + } > + } > + // Merge old and new data. Write merged word to NOR > + WordToWrite = (Tmp & ~Mask) | TmpBuf; > + BytesToWrite -= (4 - (CurOffset & 0x3)); > + CurOffset += (4 - (CurOffset & 0x3)); > + } else { > + // Unaligned and fits in one word. > + Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8); > + // Mask out the bytes we want. > + TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask; > + // Is the destination still in 'erased' state? > + if ((Tmp & Mask) != Mask) { > + // Check to see if we are only changing bits to zero. > + if ((Tmp ^ TmpBuf) & TmpBuf) { > + DoErase = TRUE; > + break; > + } > + } > + // Merge old and new data. Write merged word to NOR > + WordToWrite = (Tmp & ~Mask) | TmpBuf; > + CurOffset += BytesToWrite; > + BytesToWrite = 0; > + } > + } > + > + // > + // Write the word to NOR. > + // > + > + BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, > + BlockSize); > + if (BlockAddress != PrevBlockAddress) { > + TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance, > + BlockAddress); > + if (EFI_ERROR (TempStatus)) { > + return EFI_DEVICE_ERROR; > + } > + PrevBlockAddress = BlockAddress; > + } > + TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite); > + if (EFI_ERROR (TempStatus)) { > + return EFI_DEVICE_ERROR; > + } > + } > + // Exit if we got here and could write all the data. Otherwise do the > + // Erase-Write cycle. > + if (!DoErase) { > + return EFI_SUCCESS; > + } > + } > + > + // Check we did get some memory. Buffer is BlockSize. > + if (Instance->ShadowBuffer == NULL) { > + DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n")); > + return EFI_DEVICE_ERROR; > + } > + > + // Read NOR Flash data into shadow buffer > + TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize, > + Instance->ShadowBuffer); > + if (EFI_ERROR (TempStatus)) { > + // Return one of the pre-approved error statuses > + return EFI_DEVICE_ERROR; > + } > + > + // Put the data at the appropriate location inside the buffer area > + CopyMem ((VOID*)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes); > + > + // Write the modified buffer back to the NorFlash > + TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize, > + Instance->ShadowBuffer); > + if (EFI_ERROR (TempStatus)) { > + // Return one of the pre-approved error statuses > + return EFI_DEVICE_ERROR; > + } > + > + return EFI_SUCCESS; > +} The above is waaay too long. Can it be broken down with the help of some helper functions please? > + > +/* > + Although DiskIoDxe will automatically install the DiskIO protocol whenever > + we install the BlockIO protocol, its implementation is sub-optimal as it reads > + and writes entire blocks using the BlockIO protocol. In fact we can access > + NOR flash with a finer granularity than that, so we can improve performance > + by directly producing the DiskIO protocol. > +*/ > + > +/** > + Read BufferSize bytes from Offset into Buffer. > + > + @param This Protocol instance pointer. > + @param MediaId Id of the media, changes every time the media is > + replaced. > + @param Offset The starting byte offset to read from > + @param BufferSize Size of Buffer > + @param Buffer Buffer containing read data > + > + @retval EFI_SUCCESS The data was read correctly from the device. > + @retval EFI_DEVICE_ERROR The device reported an error while performing > + the read. > + @retval EFI_NO_MEDIA There is no media in the device. > + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. > + @retval EFI_INVALID_PARAMETER The read request contains device addresses that > + are not valid for the device. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +NorFlashDiskIoReadDisk ( > + IN EFI_DISK_IO_PROTOCOL *This, > + IN UINT32 MediaId, > + IN UINT64 DiskOffset, > + IN UINTN BufferSize, > + OUT VOID *Buffer > + ) > +{ > + NOR_FLASH_INSTANCE *Instance; > + UINT32 BlockSize; > + UINT32 BlockOffset; > + EFI_LBA Lba; > + > + Instance = INSTANCE_FROM_DISKIO_THIS(This); > + > + if (MediaId != Instance->Media.MediaId) { > + return EFI_MEDIA_CHANGED; > + } > + > + BlockSize = Instance->Media.BlockSize; > + Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset); > + > + return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer); > +} > + > +/** > + Writes a specified number of bytes to a device. > + > + @param This Indicates a pointer to the calling context. > + @param MediaId ID of the medium to be written. > + @param Offset The starting byte offset on the logical block I/O device to > + write. > + @param BufferSize The size in bytes of Buffer. The number of bytes to write > + to the device. > + @param Buffer A pointer to the buffer containing the data to be written. > + > + @retval EFI_SUCCESS The data was written correctly to the device. > + @retval EFI_WRITE_PROTECTED The device can not be written to. > + @retval EFI_DEVICE_ERROR The device reported an error while performing > + the write. > + @retval EFI_NO_MEDIA There is no media in the device. > + @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. > + @retval EFI_INVALID_PARAMETER The write request contains device addresses that > + are not valid for the device. > + > +**/ > +STATIC > +EFI_STATUS > +EFIAPI > +NorFlashDiskIoWriteDisk ( > + IN EFI_DISK_IO_PROTOCOL *This, > + IN UINT32 MediaId, > + IN UINT64 DiskOffset, > + IN UINTN BufferSize, > + IN VOID *Buffer > + ) > +{ > + NOR_FLASH_INSTANCE *Instance; > + UINT32 BlockSize; > + UINT32 BlockOffset; > + EFI_LBA Lba; > + UINTN RemainingBytes; > + UINTN WriteSize; > + EFI_STATUS Status; > + > + Instance = INSTANCE_FROM_DISKIO_THIS(This); > + > + if (MediaId != Instance->Media.MediaId) { > + return EFI_MEDIA_CHANGED; > + } > + > + BlockSize = Instance->Media.BlockSize; > + Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset); > + > + RemainingBytes = BufferSize; > + > + // Write either all the remaining bytes, or the number of bytes that bring > + // us up to a block boundary, whichever is less. > + // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next > + // block boundary (even if it is already on one). > + WriteSize = MIN (RemainingBytes, > + ((DiskOffset | (BlockSize - 1)) + 1) - DiskOffset); > + > + do { > + if (WriteSize == BlockSize) { > + // Write a full block > + Status = NorFlashWriteFullBlock (Instance, Lba, Buffer, > + BlockSize / sizeof (UINT32)); > + } else { > + // Write a partial block > + Status = NorFlashWriteSingleBlock (Instance, Lba, BlockOffset, &WriteSize, > + Buffer); > + } > + if (EFI_ERROR (Status)) { > + return Status; > + } > + // Now continue writing either all the remaining bytes or single blocks. > + RemainingBytes -= WriteSize; > + Buffer = (UINT8 *) Buffer + WriteSize; > + Lba++; > + BlockOffset = 0; > + WriteSize = MIN (RemainingBytes, BlockSize); > + } while (RemainingBytes); > + > + return Status; > +} > + > +STATIC CONST NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = { > + NOR_FLASH_SIGNATURE, // Signature > + NULL, // Handle ... NEED TO BE FILLED By what? > + > + FALSE, // Initialized > + NULL, // Initialize > + > + 0, // HostRegisterBaseAddress ... NEED TO BE FILLED > + 0, // DeviceBaseAddress ... NEED TO BE FILLED > + 0, // RegionBaseAddress ... NEED TO BE FILLED > + 0, // Size ... NEED TO BE FILLED > + 0, // StartLba > + 0, // OffsetLba > + > + { > + EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision > + NULL, // Media ... NEED TO BE FILLED > + NorFlashBlockIoReset, // Reset; > + NorFlashBlockIoReadBlocks, // ReadBlocks > + NorFlashBlockIoWriteBlocks, // WriteBlocks > + NorFlashBlockIoFlushBlocks // FlushBlocks > + }, // BlockIoProtocol > + > + { > + 0, // MediaId ... NEED TO BE FILLED > + FALSE, // RemovableMedia > + TRUE, // MediaPresent > + FALSE, // LogicalPartition > + FALSE, // ReadOnly > + FALSE, // WriteCaching; > + 0, // BlockSize ... NEED TO BE FILLED > + 4, // IoAlign > + 0, // LastBlock ... NEED TO BE FILLED > + 0, // LowestAlignedLba > + 1, // LogicalBlocksPerPhysicalBlock > + }, //Media; > + > + { > + EFI_DISK_IO_PROTOCOL_REVISION, // Revision > + NorFlashDiskIoReadDisk, // ReadDisk > + NorFlashDiskIoWriteDisk // WriteDisk > + }, > + { > + FvbGetAttributes, // GetAttributes > + FvbSetAttributes, // SetAttributes > + FvbGetPhysicalAddress, // GetPhysicalAddress > + FvbGetBlockSize, // GetBlockSize > + FvbRead, // Read > + FvbWrite, // Write > + FvbEraseBlocks, // EraseBlocks > + NULL, //ParentHandle > + }, // FvbProtoccol; > + > + NULL, // ShadowBuffer > + { > + { > + { > + HARDWARE_DEVICE_PATH, > + HW_VENDOR_DP, > + { > + (UINT8)sizeof(VENDOR_DEVICE_PATH), > + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8) > + } > + }, > + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }, > + }, > + { > + END_DEVICE_PATH_TYPE, > + END_ENTIRE_DEVICE_PATH_SUBTYPE, > + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } > + } > + }, // DevicePath > + > + NULL, // CmdTable > + 0, // CmdTableSize > + 0 // Flags > +}; > + > +STATIC > +EFI_STATUS > +NorFlashCreateInstance ( > + IN UINTN HostRegisterBase, > + IN UINTN NorFlashDeviceBase, > + IN UINTN NorFlashRegionBase, > + IN UINTN NorFlashSize, > + IN UINT32 MediaId, > + IN UINT32 BlockSize, > + IN BOOLEAN HasVarStore, > + IN CONST GUID *NorFlashGuid, > + IN CONST CSDC_DEFINITION *CommandTable, > + IN UINTN CommandTableSize, > + OUT NOR_FLASH_INSTANCE** NorFlashInstance > + ) > +{ > + EFI_STATUS Status; > + NOR_FLASH_INSTANCE* Instance; > + UINT8 JedecId[3]; > + > + ASSERT(NorFlashInstance != NULL); > + > + Instance = AllocateRuntimeCopyPool (sizeof mNorFlashInstanceTemplate, > + &mNorFlashInstanceTemplate); > + if (Instance == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + Instance->HostRegisterBaseAddress = HostRegisterBase; > + Instance->DeviceBaseAddress = NorFlashDeviceBase; > + Instance->RegionBaseAddress = NorFlashRegionBase; > + Instance->Size = NorFlashSize; > + > + Instance->BlockIoProtocol.Media = &Instance->Media; > + Instance->Media.MediaId = MediaId; > + Instance->Media.BlockSize = BlockSize; > + Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1; - 1; > + Instance->OffsetLba = (NorFlashRegionBase - NorFlashDeviceBase) / BlockSize; > + > + CopyGuid (&Instance->DevicePath.Vendor.Guid, NorFlashGuid); > + > + Instance->CmdTable = CommandTable; > + Instance->CmdTableSize = CommandTableSize; > + NorFlashReset (Instance); > + > + NorFlashReadID (Instance, JedecId); > + // Micron N25Q > + if (JedecId[0] == 0x20 && (JedecId[1] == 0xBB || JedecId[1] == 0xBA)) { > + Instance->Flags = NOR_FLASH_POLL_FSR; > + } > + // Macronix MX66U > + else if (JedecId[0] == 0xC2 && JedecId[1] == 0x25) { Can we get some helpful #defines for these live-coded values please? > + Instance->Flags = 0; > + } > + else { > + Instance->Flags = 0; > + } > + > + Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);; > + if (Instance->ShadowBuffer == NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + if (HasVarStore) { > + Instance->Initialize = NorFlashFvbInitialize; > + } > + > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &Instance->Handle, > + &gEfiDevicePathProtocolGuid, &Instance->DevicePath, > + &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + FreePool (Instance); > + return Status; > + } > + > + *NorFlashInstance = Instance; > + return Status; > +} > + > +EFI_STATUS > +NorFlashReset ( > + IN NOR_FLASH_INSTANCE *Instance > + ) > +{ > + FIP006_CS_CFG CsCfg; > + > + DEBUG ((DEBUG_BLKIO, "NorFlashReset()\n")); > + NOR_FLASH_GET_HOST_REG(Instance, CS_CFG, CsCfg); > + CsCfg.Reg.MBM = CS_CFG_MBM_SINGLE; > + CsCfg.Reg.SRAM = CS_CFG_SRAM_RW; > + NOR_FLASH_SET_HOST_REG(Instance, CS_CFG, CsCfg); > + NorFlashSetHostCommand (Instance, 0x13); Same 0x13 again? > + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); > + return EFI_SUCCESS; > +} > + > +EFI_STATUS > +NorFlashReadID ( > + IN NOR_FLASH_INSTANCE *Instance, > + OUT UINT8 JedecId[3] > + ) > +{ > + if (Instance == NULL || JedecId == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + NorFlashSetHostCommand (Instance, 0x9F); > + JedecId[0] = ((UINT8*)Instance->DeviceBaseAddress)[0]; // Manufacturer ID > + JedecId[1] = ((UINT8*)Instance->DeviceBaseAddress)[1]; // Memory Type > + JedecId[2] = ((UINT8*)Instance->DeviceBaseAddress)[2]; // Memory Capacity > + NorFlashSetHostCommand (Instance, 0x13); > + return EFI_SUCCESS; > +} > + > +/** > + Fixup internal data so that EFI can be call in virtual mode. > + Call the passed in Child Notify event and convert any pointers in > + lib to virtual mode. > + > + @param[in] Event The Event that is being processed > + @param[in] Context Event Context > +**/ > +STATIC > +VOID > +EFIAPI > +NorFlashVirtualNotifyEvent ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + UINTN Index; > + > + for (Index = 0; Index < mNorFlashDeviceCount; Index++) { > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->HostRegisterBaseAddress); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->DeviceBaseAddress); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->RegionBaseAddress); > + > + // Convert BlockIo protocol > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.Reset); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks); > + > + // Convert Fvb > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Read); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes); > + EfiConvertPointer (0x0, > + (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Write); > + > + if (mNorFlashInstances[Index]->ShadowBuffer != NULL) { > + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->ShadowBuffer); > + } > + > + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->CmdTable); > + } > + > + return; > +} > + > +EFI_STATUS > +EFIAPI > +NorFlashInitialise ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + EFI_PHYSICAL_ADDRESS HostRegisterBaseAddress; > + UINT32 Index; > + NOR_FLASH_DESCRIPTION* NorFlashDevices; > + BOOLEAN ContainVariableStorage; > + > + // Register HSSPI FIP006 register region > + HostRegisterBaseAddress = PcdGet32 (PcdFip006DxeRegBaseAddress); > + > + Status = gDS->AddMemorySpace ( > + EfiGcdMemoryTypeMemoryMappedIo, > + HostRegisterBaseAddress, SIZE_4KB, > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status = gDS->SetMemorySpaceAttributes ( > + HostRegisterBaseAddress, SIZE_4KB, > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); > + ASSERT_EFI_ERROR (Status); > + > + Status = NorFlashPlatformInitialization (); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, > + "NorFlashInitialise: Fail to initialize Nor Flash devices\n")); > + return Status; > + } > + > + // Initialize NOR flash instances > + Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR,"NorFlashInitialise: Fail to get Nor Flash devices\n")); > + return Status; > + } > + > + mNorFlashInstances = AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE*) * > + mNorFlashDeviceCount); > + > + for (Index = 0; Index < mNorFlashDeviceCount; Index++) { > + // Check if this NOR Flash device contain the variable storage region > + ContainVariableStorage = > + (NorFlashDevices[Index].RegionBaseAddress <= > + PcdGet32 (PcdFlashNvStorageVariableBase)) && > + (PcdGet32 (PcdFlashNvStorageVariableBase) + > + PcdGet32 (PcdFlashNvStorageVariableSize) <= > + NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size); > + > + Status = NorFlashCreateInstance ( > + HostRegisterBaseAddress, > + NorFlashDevices[Index].DeviceBaseAddress, > + NorFlashDevices[Index].RegionBaseAddress, > + NorFlashDevices[Index].Size, > + Index, > + NorFlashDevices[Index].BlockSize, > + ContainVariableStorage, > + &NorFlashDevices[Index].Guid, > + mN25qCSDCDefTable, > + ARRAY_SIZE (mN25qCSDCDefTable), > + &mNorFlashInstances[Index] > + ); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, > + "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n", > + Index)); > + } > + } > + > + // > + // Register for the virtual address change event > + // > + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, > + NorFlashVirtualNotifyEvent, NULL, > + &gEfiEventVirtualAddressChangeGuid, > + &mNorFlashVirtualAddrChangeEvent); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h > new file mode 100644 > index 000000000000..d5185dba3c63 > --- /dev/null > +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h > @@ -0,0 +1,314 @@ > +/** @file NorFlashDxe.h > + > + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
> + Copyright (c) 2017, Socionext Inc. All rights reserved.
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> + > + This program and the accompanying materials > + are licensed and made available under the terms and conditions of the BSD License > + which accompanies this distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > +**/ > + > +#ifndef __NOR_FLASH_DXE_H__ > +#define __NOR_FLASH_DXE_H__ > + > + > +#include > +#include > + > +#include > + > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include Sorted, please. > + > +#include "Fip006Reg.h" > + > +#define NOR_FLASH_ERASE_RETRY 10 I'm sure I saw a 10 retry count up there somewhere that did not use this #define. It probably should. > + > +#define GET_NOR_BLOCK_ADDRESS(BaseAddr,Lba,LbaSize)( BaseAddr + (UINTN)((Lba) * LbaSize) ) > + > +#define NOR_FLASH_READ_BYTE(Instance, Addr) \ > + (((UINT8*) Instance->RegionBaseAddress + Addr)[0]) > + > +#define NOR_FLASH_WRITE_BYTE(Instance, Addr, Src) \ > + do { \ > + ((UINT8*) Instance->RegionBaseAddress + Addr)[0] = Src; \ > + } while (0) > + Umm, if not using MmioWrite8 (hint, it probably should), this pointer should also flag volatile. x2. > +#define NOR_FLASH_GET_HOST_REG(Instance, Reg, Dst) \ > + do { \ > + Dst.Raw = MmioRead32(Instance->HostRegisterBaseAddress + FIP006_REG_##Reg); \ > + } while (0) > + > +#define NOR_FLASH_SET_HOST_REG(Instance, Reg, Src) \ > + do { \ > + MmioWrite32 (Instance->HostRegisterBaseAddress + FIP006_REG_##Reg, Src.Raw); \ > + } while (0) > + > +#define NOR_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r') > +#define INSTANCE_FROM_FVB_THIS(a) CR(a, NOR_FLASH_INSTANCE, FvbProtocol, NOR_FLASH_SIGNATURE) > +#define INSTANCE_FROM_BLKIO_THIS(a) CR(a, NOR_FLASH_INSTANCE, BlockIoProtocol, NOR_FLASH_SIGNATURE) > +#define INSTANCE_FROM_DISKIO_THIS(a) CR(a, NOR_FLASH_INSTANCE, DiskIoProtocol, NOR_FLASH_SIGNATURE) > + > +#define CSDC(Data, Cont, Trp, Dec) \ > + ((Data << 8) | (Cont << 3) | (Trp << 1) | Dec) Do these need some masking as well, for sanitisation? > +#define CSDC_TRP_MBM 0 > +#define CSDC_TRP_DUAL 1 > +#define CSDC_TRP_QUAD 2 > +#define CSDC_TRP_SINGLE 3 > + > +typedef struct { > + UINT8 Code; > + BOOLEAN AddrAccess; > + BOOLEAN AddrMode4Byte; > + BOOLEAN HighZ; > + BOOLEAN ReadWrite; > + UINT8 CscfgMbm; > + UINT8 CsdcTrp; > +} CSDC_DEFINITION; > + > +typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE; > + > +typedef EFI_STATUS (*NOR_FLASH_INITIALIZE) (NOR_FLASH_INSTANCE* Instance); > + > +typedef struct { > + VENDOR_DEVICE_PATH Vendor; > + EFI_DEVICE_PATH_PROTOCOL End; > +} NOR_FLASH_DEVICE_PATH; > + > +struct _NOR_FLASH_INSTANCE { > + UINT32 Signature; > + EFI_HANDLE Handle; > + > + BOOLEAN Initialized; > + NOR_FLASH_INITIALIZE Initialize; > + > + UINTN HostRegisterBaseAddress; > + UINTN DeviceBaseAddress; > + UINTN RegionBaseAddress; > + UINTN Size; > + EFI_LBA StartLba; > + EFI_LBA OffsetLba; > + > + EFI_BLOCK_IO_PROTOCOL BlockIoProtocol; > + EFI_BLOCK_IO_MEDIA Media; > + EFI_DISK_IO_PROTOCOL DiskIoProtocol; > + > + EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol; > + VOID* ShadowBuffer; > + > + NOR_FLASH_DEVICE_PATH DevicePath; > + > + CONST CSDC_DEFINITION *CmdTable; > + UINTN CmdTableSize; > + > + UINT32 Flags; > +#define NOR_FLASH_POLL_FSR BIT0 > +}; > + > +EFI_STATUS > +NorFlashReadCfiData ( > + IN UINTN DeviceBaseAddress, > + IN UINTN CFI_Offset, > + IN UINT32 NumberOfBytes, > + OUT UINT32 *Data > + ); > + > +EFI_STATUS > +NorFlashWriteBuffer ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINTN TargetAddress, > + IN UINTN BufferSizeInBytes, > + IN UINT32 *Buffer > + ); > + > +// > +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.Reset > +// > +EFI_STATUS > +EFIAPI > +NorFlashBlockIoReset ( > + IN EFI_BLOCK_IO_PROTOCOL *This, > + IN BOOLEAN ExtendedVerification > + ); > + > +// > +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.ReadBlocks > +// > +EFI_STATUS > +EFIAPI > +NorFlashBlockIoReadBlocks ( > + IN EFI_BLOCK_IO_PROTOCOL *This, > + IN UINT32 MediaId, > + IN EFI_LBA Lba, > + IN UINTN BufferSizeInBytes, > + OUT VOID *Buffer > +); > + > +// > +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.WriteBlocks > +// > +EFI_STATUS > +EFIAPI > +NorFlashBlockIoWriteBlocks ( > + IN EFI_BLOCK_IO_PROTOCOL *This, > + IN UINT32 MediaId, > + IN EFI_LBA Lba, > + IN UINTN BufferSizeInBytes, > + IN VOID *Buffer > +); > + > +// > +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.FlushBlocks > +// > +EFI_STATUS > +EFIAPI > +NorFlashBlockIoFlushBlocks ( > + IN EFI_BLOCK_IO_PROTOCOL *This > +); > + > +// > +// NorFlashFvbDxe.c > +// > + > +EFI_STATUS > +EFIAPI > +NorFlashFvbInitialize ( > + IN NOR_FLASH_INSTANCE* Instance > + ); > + > +EFI_STATUS > +EFIAPI > +FvbGetAttributes( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + OUT EFI_FVB_ATTRIBUTES_2 *Attributes > + ); > + > +EFI_STATUS > +EFIAPI > +FvbSetAttributes( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes > + ); > + > +EFI_STATUS > +EFIAPI > +FvbGetPhysicalAddress( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + OUT EFI_PHYSICAL_ADDRESS *Address > + ); > + > +EFI_STATUS > +EFIAPI > +FvbGetBlockSize( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + IN EFI_LBA Lba, > + OUT UINTN *BlockSize, > + OUT UINTN *NumberOfBlocks > + ); > + > +EFI_STATUS > +EFIAPI > +FvbRead( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Offset, > + IN OUT UINTN *NumBytes, > + IN OUT UINT8 *Buffer > + ); > + > +EFI_STATUS > +EFIAPI > +FvbWrite( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Offset, > + IN OUT UINTN *NumBytes, > + IN UINT8 *Buffer > + ); > + > +EFI_STATUS > +EFIAPI > +FvbEraseBlocks( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + ... > + ); > + > +// > +// NorFlashDxe.c > +// > + > +EFI_STATUS > +NorFlashUnlockAndEraseSingleBlock ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN UINTN BlockAddress > + ); > + > +EFI_STATUS > +NorFlashWriteSingleBlock ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINTN Offset, > + IN OUT UINTN *NumBytes, > + IN UINT8 *Buffer > + ); > + > +EFI_STATUS > +NorFlashWriteBlocks ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINTN BufferSizeInBytes, > + IN VOID *Buffer > + ); > + > +EFI_STATUS > +NorFlashReadBlocks ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINTN BufferSizeInBytes, > + OUT VOID *Buffer > + ); > + > +EFI_STATUS > +NorFlashRead ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINTN Offset, > + IN UINTN BufferSizeInBytes, > + OUT VOID *Buffer > + ); > + > +EFI_STATUS > +NorFlashWrite ( > + IN NOR_FLASH_INSTANCE *Instance, > + IN EFI_LBA Lba, > + IN UINTN Offset, > + IN OUT UINTN *NumBytes, > + IN UINT8 *Buffer > + ); > + > +EFI_STATUS > +NorFlashReset ( > + IN NOR_FLASH_INSTANCE *Instance > + ); > + > +EFI_STATUS > +NorFlashReadID ( > + IN NOR_FLASH_INSTANCE *Instance, > + OUT UINT8 JedecId[3] > + ); > + > +#endif /* __NOR_FLASH_DXE_H__ */ > diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c > new file mode 100644 > index 000000000000..6984711df609 > --- /dev/null > +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c > @@ -0,0 +1,859 @@ > +/** @file NorFlashFvbDxe.c > + > + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
> + Copyright (c) 2017, Socionext Inc. All rights reserved.
> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.
> + > + This program and the accompanying materials are licensed and made available > + under the terms and conditions of the BSD License which accompanies this > + distribution. The full text of the license may be found at > + http://opensource.org/licenses/bsd-license.php > + > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > + > + --*/ > + > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include Sorted, please. > + > +#include "NorFlashDxe.h" > + > +STATIC EFI_EVENT mFvbVirtualAddrChangeEvent; > +STATIC UINTN mFlashNvStorageVariableBase; > + > +/// > +/// The Firmware Volume Block Protocol is the low-level interface > +/// to a firmware volume. File-level access to a firmware volume > +/// should not be done using the Firmware Volume Block Protocol. > +/// Normal access to a firmware volume must use the Firmware > +/// Volume Protocol. Typically, only the file system driver that > +/// produces the Firmware Volume Protocol will bind to the > +/// Firmware Volume Block Protocol. > +/// > + > +/** > + Initialises the FV Header and Variable Store Header > + to support variable operations. > + > + @param[in] Ptr - Location to initialise the headers > + > +**/ > +STATIC > +EFI_STATUS > +InitializeFvAndVariableStoreHeaders ( > + IN NOR_FLASH_INSTANCE *Instance > + ) > +{ > + EFI_STATUS Status; > + VOID* Headers; > + UINTN HeadersLength; > + EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader; > + VARIABLE_STORE_HEADER *VariableStoreHeader; > + UINTN BlockSize; > + > + if (!Instance->Initialized && Instance->Initialize) { > + Instance->Initialize (Instance); > + } > + > + HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + > + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + > + sizeof(VARIABLE_STORE_HEADER); > + Headers = AllocateZeroPool(HeadersLength); > + > + BlockSize = Instance->Media.BlockSize; > + > + // FirmwareVolumeHeader->FvLength is declared to have the Variable area > + // AND the FTW working area AND the FTW Spare contiguous. > + ASSERT(PcdGet32(PcdFlashNvStorageVariableBase) + > + PcdGet32(PcdFlashNvStorageVariableSize) == > + PcdGet32(PcdFlashNvStorageFtwWorkingBase)); > + ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase) + > + PcdGet32(PcdFlashNvStorageFtwWorkingSize) == > + PcdGet32(PcdFlashNvStorageFtwSpareBase)); > + > + // Check if the size of the area is at least one block size > + ASSERT((PcdGet32(PcdFlashNvStorageVariableSize) > 0) && > + (PcdGet32(PcdFlashNvStorageVariableSize) / BlockSize > 0)); > + ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingSize) > 0) && > + (PcdGet32(PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0)); > + ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareSize) > 0) && > + (PcdGet32(PcdFlashNvStorageFtwSpareSize) / BlockSize > 0)); > + > + // Ensure the Variable areas are aligned on block size boundaries > + ASSERT((PcdGet32(PcdFlashNvStorageVariableBase) % BlockSize) == 0); > + ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingBase) % BlockSize) == 0); > + ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareBase) % BlockSize) == 0); > + > + // > + // EFI_FIRMWARE_VOLUME_HEADER > + // > + FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers; > + CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid); > + FirmwareVolumeHeader->FvLength = > + PcdGet32(PcdFlashNvStorageVariableSize) + > + PcdGet32(PcdFlashNvStorageFtwWorkingSize) + > + PcdGet32(PcdFlashNvStorageFtwSpareSize); > + FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE; > + FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP | > + EFI_FVB2_READ_STATUS | > + EFI_FVB2_STICKY_WRITE | > + EFI_FVB2_MEMORY_MAPPED | > + EFI_FVB2_ERASE_POLARITY | > + EFI_FVB2_WRITE_STATUS | > + EFI_FVB2_WRITE_ENABLED_CAP; > + > + FirmwareVolumeHeader->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + > + sizeof(EFI_FV_BLOCK_MAP_ENTRY); > + FirmwareVolumeHeader->Revision = EFI_FVH_REVISION; > + FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->Media.LastBlock + 1; > + FirmwareVolumeHeader->BlockMap[0].Length = Instance->Media.BlockSize; > + FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0; > + FirmwareVolumeHeader->BlockMap[1].Length = 0; > + FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ( > + (UINT16*)FirmwareVolumeHeader, > + FirmwareVolumeHeader->HeaderLength); > + > + // > + // VARIABLE_STORE_HEADER > + // > + VariableStoreHeader = (VOID *)((UINTN)Headers + > + FirmwareVolumeHeader->HeaderLength); > + CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid); > + VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - > + FirmwareVolumeHeader->HeaderLength; > + VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED; > + VariableStoreHeader->State = VARIABLE_STORE_HEALTHY; > + > + // Install the combined super-header in the NorFlash > + Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers); > + > + FreePool (Headers); > + return Status; > +} > + > +/** > + Check the integrity of firmware volume header. > + > + @param[in] FwVolHeader - A pointer to a firmware volume header > + > + @retval EFI_SUCCESS - The firmware volume is consistent > + @retval EFI_NOT_FOUND - The firmware volume has been corrupted. > + > +**/ > +EFI_STATUS > +ValidateFvHeader ( > + IN NOR_FLASH_INSTANCE *Instance > + ) > +{ > + UINT16 Checksum; > + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; > + VARIABLE_STORE_HEADER *VariableStoreHeader; > + UINTN VariableStoreLength; > + UINTN FvLength; > + > + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Instance->RegionBaseAddress; > + > + FvLength = PcdGet32(PcdFlashNvStorageVariableSize) + > + PcdGet32(PcdFlashNvStorageFtwWorkingSize) + > + PcdGet32(PcdFlashNvStorageFtwSpareSize); > + > + // > + // Verify the header revision, header signature, length > + // Length of FvBlock cannot be 2**64-1 > + // HeaderLength cannot be an odd number > + // > + if ( (FwVolHeader->Revision != EFI_FVH_REVISION) > + || (FwVolHeader->Signature != EFI_FVH_SIGNATURE) > + || (FwVolHeader->FvLength != FvLength) > + ) > + { > + DEBUG ((DEBUG_INFO, "%a: No Firmware Volume header present\n", > + __FUNCTION__)); > + return EFI_NOT_FOUND; > + } > + > + // Check the Firmware Volume Guid > + if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid)) { > + DEBUG ((DEBUG_INFO, "%a: Firmware Volume Guid non-compatible\n", > + __FUNCTION__)); > + return EFI_NOT_FOUND; > + } > + > + // Verify the header checksum > + Checksum = CalculateSum16((UINT16*)FwVolHeader, FwVolHeader->HeaderLength); > + if (Checksum != 0) { > + DEBUG ((DEBUG_INFO, "%a: FV checksum is invalid (Checksum:0x%X)\n", > + __FUNCTION__, Checksum)); > + return EFI_NOT_FOUND; > + } > + > + VariableStoreHeader = (VOID *)((UINTN)FwVolHeader + > + FwVolHeader->HeaderLength); > + > + // Check the Variable Store Guid > + if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) && > + !CompareGuid (&VariableStoreHeader->Signature, > + &gEfiAuthenticatedVariableGuid)) { > + DEBUG ((DEBUG_INFO, "%a: Variable Store Guid non-compatible\n", > + __FUNCTION__)); > + return EFI_NOT_FOUND; > + } > + > + VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - > + FwVolHeader->HeaderLength; > + if (VariableStoreHeader->Size != VariableStoreLength) { > + DEBUG ((DEBUG_INFO, "%a: Variable Store Length does not match\n", > + __FUNCTION__)); > + return EFI_NOT_FOUND; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + The GetAttributes() function retrieves the attributes and > + current settings of the block. > + > + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. > + > + @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and > + current settings are returned. > + Type EFI_FVB_ATTRIBUTES_2 is defined in > + EFI_FIRMWARE_VOLUME_HEADER. > + > + @retval EFI_SUCCESS The firmware volume attributes were returned. > + > + **/ > +EFI_STATUS > +EFIAPI > +FvbGetAttributes( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + OUT EFI_FVB_ATTRIBUTES_2 *Attributes > + ) > +{ > + EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes; > + NOR_FLASH_INSTANCE *Instance; > + > + Instance = INSTANCE_FROM_FVB_THIS(This); > + > + FlashFvbAttributes = EFI_FVB2_READ_ENABLED_CAP | EFI_FVB2_READ_STATUS | > + EFI_FVB2_STICKY_WRITE | EFI_FVB2_MEMORY_MAPPED | > + EFI_FVB2_ERASE_POLARITY; > + > + // Check if it is write protected > + if (!Instance->Media.ReadOnly) { > + FlashFvbAttributes |= EFI_FVB2_WRITE_STATUS | EFI_FVB2_WRITE_ENABLED_CAP; > + } > + > + *Attributes = FlashFvbAttributes; > + > + DEBUG ((DEBUG_BLKIO, "FvbGetAttributes(0x%X)\n", *Attributes)); > + > + return EFI_SUCCESS; > +} > + > +/** > + The SetAttributes() function sets configurable firmware volume attributes > + and returns the new settings of the firmware volume. > + > + > + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. > + > + @param Attributes On input, Attributes is a pointer to > + EFI_FVB_ATTRIBUTES_2 that contains the desired > + firmware volume settings. > + On successful return, it contains the new > + settings of the firmware volume. > + > + @retval EFI_SUCCESS The firmware volume attributes were returned. > + > + @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with > + the capabilities as declared in the firmware > + volume header. > + > + **/ > +EFI_STATUS > +EFIAPI > +FvbSetAttributes( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes > + ) > +{ > + DEBUG ((DEBUG_BLKIO, "FvbSetAttributes(0x%X) is not supported\n", > + *Attributes)); > + return EFI_UNSUPPORTED; > +} > + > +/** > + The GetPhysicalAddress() function retrieves the base address of > + a memory-mapped firmware volume. This function should be called > + only for memory-mapped firmware volumes. > + > + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. > + > + @param Address Pointer to a caller-allocated > + EFI_PHYSICAL_ADDRESS that, on successful > + return from GetPhysicalAddress(), contains the > + base address of the firmware volume. > + > + @retval EFI_SUCCESS The firmware volume base address was returned. > + > + @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped. > + > + **/ > +EFI_STATUS > +EFIAPI > +FvbGetPhysicalAddress ( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + OUT EFI_PHYSICAL_ADDRESS *Address > + ) > +{ > + NOR_FLASH_INSTANCE *Instance; > + > + Instance = INSTANCE_FROM_FVB_THIS(This); > + > + DEBUG ((DEBUG_BLKIO, "FvbGetPhysicalAddress(BaseAddress=0x%08x)\n", > + Instance->RegionBaseAddress)); > + > + ASSERT(Address != NULL); > + > + *Address = Instance->RegionBaseAddress; > + return EFI_SUCCESS; > +} > + > +/** > + The GetBlockSize() function retrieves the size of the requested > + block. It also returns the number of additional blocks with > + the identical size. The GetBlockSize() function is used to > + retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER). > + > + > + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. > + > + @param Lba Indicates the block whose size to return > + > + @param BlockSize Pointer to a caller-allocated UINTN in which > + the size of the block is returned. > + > + @param NumberOfBlocks Pointer to a caller-allocated UINTN in > + which the number of consecutive blocks, > + starting with Lba, is returned. All > + blocks in this range have a size of > + BlockSize. > + > + > + @retval EFI_SUCCESS The firmware volume base address was returned. > + > + @retval EFI_INVALID_PARAMETER The requested LBA is out of range. > + > + **/ > +EFI_STATUS > +EFIAPI > +FvbGetBlockSize ( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + IN EFI_LBA Lba, > + OUT UINTN *BlockSize, > + OUT UINTN *NumberOfBlocks > + ) > +{ > + EFI_STATUS Status; > + NOR_FLASH_INSTANCE *Instance; > + > + Instance = INSTANCE_FROM_FVB_THIS(This); > + > + DEBUG ((DEBUG_BLKIO, > + "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n", Lba, > + Instance->Media.BlockSize, Instance->Media.LastBlock)); > + > + if (Lba > Instance->Media.LastBlock) { > + DEBUG ((DEBUG_ERROR, > + "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba (%ld).\n", > + Lba, Instance->Media.LastBlock)); > + Status = EFI_INVALID_PARAMETER; > + } else { > + // This is easy because in this platform each NorFlash device has equal sized blocks. > + *BlockSize = (UINTN) Instance->Media.BlockSize; > + *NumberOfBlocks = (UINTN) (Instance->Media.LastBlock - Lba + 1); > + > + DEBUG ((DEBUG_BLKIO, > + "FvbGetBlockSize: *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n", *BlockSize, > + *NumberOfBlocks)); > + > + Status = EFI_SUCCESS; > + } > + > + return Status; > +} > + > +/** > + Reads the specified number of bytes into a buffer from the specified block. > + > + The Read() function reads the requested number of bytes from the > + requested block and stores them in the provided buffer. > + Implementations should be mindful that the firmware volume > + might be in the ReadDisabled state. If it is in this state, > + the Read() function must return the status code > + EFI_ACCESS_DENIED without modifying the contents of the > + buffer. The Read() function must also prevent spanning block > + boundaries. If a read is requested that would span a block > + boundary, the read must read up to the boundary but not > + beyond. The output parameter NumBytes must be set to correctly > + indicate the number of bytes actually read. The caller must be > + aware that a read may be partially completed. > + > + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. > + > + @param Lba The starting logical block index from which to read > + > + @param Offset Offset into the block at which to begin reading. > + > + @param NumBytes Pointer to a UINTN. > + At entry, *NumBytes contains the total size of the > + buffer. > + At exit, *NumBytes contains the total number of > + bytes read. > + > + @param Buffer Pointer to a caller-allocated buffer that will be > + used to hold the data that is read. > + > + @retval EFI_SUCCESS The firmware volume was read successfully, and > + contents are in Buffer. > + > + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary. > + On output, NumBytes contains the total number of > + bytes returned in Buffer. > + > + @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state. > + > + @retval EFI_DEVICE_ERROR The block device is not functioning correctly and > + could not be read. > + > + **/ > +EFI_STATUS > +EFIAPI > +FvbRead ( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Offset, > + IN OUT UINTN *NumBytes, > + IN OUT UINT8 *Buffer > + ) > +{ > + EFI_STATUS TempStatus; > + UINTN BlockSize; > + NOR_FLASH_INSTANCE *Instance; > + > + Instance = INSTANCE_FROM_FVB_THIS(This); > + > + DEBUG ((DEBUG_BLKIO, > + "FvbRead(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", > + Instance->StartLba + Lba, Offset, *NumBytes, Buffer)); > + > + if (!Instance->Initialized && Instance->Initialize) { > + Instance->Initialize(Instance); > + } > + > + TempStatus = EFI_SUCCESS; > + > + // Cache the block size to avoid de-referencing pointers all the time > + BlockSize = Instance->Media.BlockSize; > + > + DEBUG ((DEBUG_BLKIO, > + "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= BlockSize=0x%x\n", > + Offset, *NumBytes, BlockSize )); > + > + // The read must not span block boundaries. > + // We need to check each variable individually because adding two large > + // values together overflows. > + if (Offset >= BlockSize || > + *NumBytes > BlockSize || > + (Offset + *NumBytes) > BlockSize) { > + DEBUG ((DEBUG_ERROR, > + "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", > + Offset, *NumBytes, BlockSize )); > + return EFI_BAD_BUFFER_SIZE; > + } > + > + // We must have some bytes to read > + if (*NumBytes == 0) { > + return EFI_BAD_BUFFER_SIZE; > + } > + > + // Decide if we are doing full block reads or not. > + if (*NumBytes % BlockSize != 0) { > + TempStatus = NorFlashRead (Instance, Instance->StartLba + Lba, Offset, > + *NumBytes, Buffer); > + if (EFI_ERROR (TempStatus)) { > + return EFI_DEVICE_ERROR; > + } > + } else { > + // Read NOR Flash data into shadow buffer > + TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, > + BlockSize, Buffer); > + if (EFI_ERROR (TempStatus)) { > + // Return one of the pre-approved error statuses > + return EFI_DEVICE_ERROR; > + } > + } > + return EFI_SUCCESS; > +} > + > +/** > + Writes the specified number of bytes from the input buffer to the block. > + > + The Write() function writes the specified number of bytes from > + the provided buffer to the specified block and offset. If the > + firmware volume is sticky write, the caller must ensure that > + all the bits of the specified range to write are in the > + EFI_FVB_ERASE_POLARITY state before calling the Write() > + function, or else the result will be unpredictable. This > + unpredictability arises because, for a sticky-write firmware > + volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY > + state but cannot flip it back again. Before calling the > + Write() function, it is recommended for the caller to first call > + the EraseBlocks() function to erase the specified block to > + write. A block erase cycle will transition bits from the > + (NOT)EFI_FVB_ERASE_POLARITY state back to the > + EFI_FVB_ERASE_POLARITY state. Implementations should be > + mindful that the firmware volume might be in the WriteDisabled > + state. If it is in this state, the Write() function must > + return the status code EFI_ACCESS_DENIED without modifying the > + contents of the firmware volume. The Write() function must > + also prevent spanning block boundaries. If a write is > + requested that spans a block boundary, the write must store up > + to the boundary but not beyond. The output parameter NumBytes > + must be set to correctly indicate the number of bytes actually > + written. The caller must be aware that a write may be > + partially completed. All writes, partial or otherwise, must be > + fully flushed to the hardware before the Write() service > + returns. > + > + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. > + > + @param Lba The starting logical block index to write to. > + > + @param Offset Offset into the block at which to begin writing. > + > + @param NumBytes The pointer to a UINTN. > + At entry, *NumBytes contains the total size of the > + buffer. > + At exit, *NumBytes contains the total number of > + bytes actually written. > + > + @param Buffer The pointer to a caller-allocated buffer that > + contains the source for the write. > + > + @retval EFI_SUCCESS The firmware volume was written successfully. > + > + @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary. > + On output, NumBytes contains the total number of > + bytes actually written. > + > + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. > + > + @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be > + written. > + > + > + **/ > +EFI_STATUS > +EFIAPI > +FvbWrite ( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Offset, > + IN OUT UINTN *NumBytes, > + IN UINT8 *Buffer > + ) > +{ > + NOR_FLASH_INSTANCE *Instance; > + > + Instance = INSTANCE_FROM_FVB_THIS (This); > + > + return NorFlashWriteSingleBlock (Instance, Instance->StartLba + Lba, Offset, > + NumBytes, Buffer); > +} > + > +/** > + Erases and initialises a firmware volume block. > + > + The EraseBlocks() function erases one or more blocks as denoted > + by the variable argument list. The entire parameter list of > + blocks must be verified before erasing any blocks. If a block is > + requested that does not exist within the associated firmware > + volume (it has a larger index than the last block of the > + firmware volume), the EraseBlocks() function must return the > + status code EFI_INVALID_PARAMETER without modifying the contents > + of the firmware volume. Implementations should be mindful that > + the firmware volume might be in the WriteDisabled state. If it > + is in this state, the EraseBlocks() function must return the > + status code EFI_ACCESS_DENIED without modifying the contents of > + the firmware volume. All calls to EraseBlocks() must be fully > + flushed to the hardware before the EraseBlocks() service > + returns. > + > + @param This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL > + instance. > + > + @param ... The variable argument list is a list of tuples. > + Each tuple describes a range of LBAs to erase > + and consists of the following: > + - An EFI_LBA that indicates the starting LBA > + - A UINTN that indicates the number of blocks > + to erase. > + > + The list is terminated with an > + EFI_LBA_LIST_TERMINATOR. > + > + @retval EFI_SUCCESS The erase request successfully completed. > + > + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled > + state. > + > + @retval EFI_DEVICE_ERROR The block device is not functioning correctly > + and could not be written. > + The firmware device may have been partially > + erased. > + > + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in the variable > + argument list do not exist in the firmware > + volume. > + > + **/ > +EFI_STATUS > +EFIAPI > +FvbEraseBlocks ( > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > + ... > + ) > +{ > + EFI_STATUS Status; > + VA_LIST Args; > + UINTN BlockAddress; // Physical address of Lba to erase > + EFI_LBA StartingLba; // Lba from which we start erasing > + UINTN NumOfLba; // Number of Lba blocks to erase > + NOR_FLASH_INSTANCE *Instance; > + > + Instance = INSTANCE_FROM_FVB_THIS(This); > + > + DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks()\n")); > + > + Status = EFI_SUCCESS; > + > + // Detect WriteDisabled state > + if (Instance->Media.ReadOnly) { > + // Firmware volume is in WriteDisabled state > + DEBUG ((DEBUG_ERROR, > + "FvbEraseBlocks: ERROR - Device is in WriteDisabled state.\n")); > + return EFI_ACCESS_DENIED; > + } > + > + // Before erasing, check the entire list of parameters to ensure > + // all specified blocks are valid > + > + VA_START (Args, This); > + do { > + // Get the Lba from which we start erasing > + StartingLba = VA_ARG (Args, EFI_LBA); > + > + // Have we reached the end of the list? > + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { > + //Exit the while loop > + break; > + } > + > + // How many Lba blocks are we requested to erase? > + NumOfLba = VA_ARG (Args, UINT32); > + > + // All blocks must be within range > + DEBUG ((DEBUG_BLKIO, > + "FvbEraseBlocks: Check if: ( StartingLba=%ld + NumOfLba=%d - 1 ) > LastBlock=%ld.\n", > + Instance->StartLba + StartingLba, NumOfLba, Instance->Media.LastBlock)); > + if (NumOfLba == 0 || > + (Instance->StartLba + StartingLba + NumOfLba - 1) > > + Instance->Media.LastBlock) { > + VA_END (Args); > + DEBUG ((DEBUG_ERROR, > + "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n")); > + Status = EFI_INVALID_PARAMETER; > + goto EXIT; > + } > + } while (TRUE); > + VA_END (Args); > + > + // > + // To get here, all must be ok, so start erasing > + // > + VA_START (Args, This); > + do { > + // Get the Lba from which we start erasing > + StartingLba = VA_ARG (Args, EFI_LBA); > + > + // Have we reached the end of the list? > + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { > + // Exit the while loop > + break; > + } > + > + // How many Lba blocks are we requested to erase? > + NumOfLba = VA_ARG (Args, UINT32); > + > + // Go through each one and erase it > + while (NumOfLba > 0) { > + > + // Get the physical address of Lba to erase > + BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, > + Instance->StartLba + StartingLba, > + Instance->Media.BlockSize); > + > + // Erase it > + DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n", > + Instance->StartLba + StartingLba, BlockAddress)); > + Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress); > + if (EFI_ERROR(Status)) { > + VA_END (Args); > + Status = EFI_DEVICE_ERROR; > + goto EXIT; > + } > + > + // Move to the next Lba > + StartingLba++; > + NumOfLba--; > + } > + } while (TRUE); > + VA_END (Args); > + > +EXIT: > + return Status; > +} > + > +/** > + Fixup internal data so that EFI can be call in virtual mode. > + Call the passed in Child Notify event and convert any pointers in > + lib to virtual mode. > + > + @param[in] Event The Event that is being processed > + @param[in] Context Event Context > +**/ > +STATIC > +VOID > +EFIAPI > +FvbVirtualNotifyEvent ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase); > + return; > +} > + > +EFI_STATUS > +EFIAPI > +NorFlashFvbInitialize ( > + IN NOR_FLASH_INSTANCE* Instance > + ) > +{ > + EFI_STATUS Status; > + UINT32 FvbNumLba; > + EFI_BOOT_MODE BootMode; > + UINTN RuntimeMmioRegionSize; > + > + DEBUG ((DEBUG_BLKIO,"NorFlashFvbInitialize\n")); > + > + Instance->Initialized = TRUE; > + mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase); > + > + // Set the index of the first LBA for the FVB > + Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - > + Instance->RegionBaseAddress) / > + Instance->Media.BlockSize; > + > + BootMode = GetBootModeHob (); > + if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) { > + Status = EFI_INVALID_PARAMETER; > + } else { > + // Determine if there is a valid header at the beginning of the NorFlash > + Status = ValidateFvHeader (Instance); > + } > + > + // Install the Default FVB header if required > + if (EFI_ERROR(Status)) { > + // There is no valid header, so time to install one. > + DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __FUNCTION__)); > + DEBUG ((DEBUG_INFO, "%a: Installing a correct one for this volume.\n", > + __FUNCTION__)); > + > + // Erase all the NorFlash that is reserved for variable storage > + FvbNumLba = (PcdGet32(PcdFlashNvStorageVariableSize) + > + PcdGet32(PcdFlashNvStorageFtwWorkingSize) + > + PcdGet32(PcdFlashNvStorageFtwSpareSize)) / > + Instance->Media.BlockSize; No need to deal with spill? Or ASSERTs for lacking alignment to BlockSize? > + > + Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, > + EFI_LBA_LIST_TERMINATOR); > + if (EFI_ERROR(Status)) { > + return Status; > + } > + > + // Install all appropriate headers > + Status = InitializeFvAndVariableStoreHeaders (Instance); > + if (EFI_ERROR(Status)) { > + return Status; > + } > + } > + > + // > + // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME > + // > + RuntimeMmioRegionSize = Instance->Size; > + > + Status = gDS->AddMemorySpace ( > + EfiGcdMemoryTypeMemoryMappedIo, > + Instance->RegionBaseAddress, RuntimeMmioRegionSize, > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME > + ); Indentation incorrect (also for several subsequent statements). > + ASSERT_EFI_ERROR (Status); > + > + Status = gDS->AddMemorySpace ( > + EfiGcdMemoryTypeMemoryMappedIo, > + Instance->DeviceBaseAddress, SIZE_4KB, > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME > + ); > + ASSERT_EFI_ERROR (Status); > + > + Status = gDS->SetMemorySpaceAttributes ( > + Instance->RegionBaseAddress, RuntimeMmioRegionSize, > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); > + ASSERT_EFI_ERROR (Status); > + > + Status = gDS->SetMemorySpaceAttributes ( > + Instance->DeviceBaseAddress, SIZE_4KB, > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); > + ASSERT_EFI_ERROR (Status); / Leif > + > + // > + // Register for the virtual address change event > + // > + Status = gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + FvbVirtualNotifyEvent, > + NULL, > + &gEfiEventVirtualAddressChangeGuid, > + &mFvbVirtualAddrChangeEvent > + ); > + ASSERT_EFI_ERROR (Status); > + > + return Status; > +} > -- > 2.11.0 >