From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2607:f8b0:4001:c06::22e; helo=mail-io0-x22e.google.com; envelope-from=ard.biesheuvel@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-io0-x22e.google.com (mail-io0-x22e.google.com [IPv6:2607:f8b0:4001:c06::22e]) (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 2535621F3B3FE for ; Sat, 28 Oct 2017 07:13:06 -0700 (PDT) Received: by mail-io0-x22e.google.com with SMTP id b186so18335915iof.8 for ; Sat, 28 Oct 2017 07:16:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc; bh=V/cP413gRHF9K4Lx9bET99EXmgklaHx1serBK0PFEg0=; b=TUs018rFaeCOjV4cx5zTtowBcBPwBRTaOKEbbkE/iir/pNEGzh9vaeSDK8oCJLgt9r TPNTBiB0SK/J0h+XslX0qPF4x6umR+NtT3HVzGIsvin2F9eup+t7vpMHjOBPnOK6lVEb auJBn+yjPYVLV8+GHenRwB8eCPri5ut6n32+A= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc; bh=V/cP413gRHF9K4Lx9bET99EXmgklaHx1serBK0PFEg0=; b=UgTIzD/ixbvO/AwoXfZfCWgFJaYCEFLNfBQF2YiBtwNuXhaEKGIPi0q12xbiQy4lDd si8n3DtjmhnOQXvZMFi/HusCXeWbk2ewiKltAQA8A7HFVsJz6PBApAuuouK7HKOcSMgV kIkHYbOfAvSO8F19PzquceT076l8Zp+i/oUTfHhIWbe+LS22wi3VhwvVEoIbd7QOsZ1k ISLMFEcJqKvsZlljQ7VaszIdxd8N1d8oLuQIvQKvjKf4lFjG3SvgnUCU3CCv7VOwH+sT 3biQsa34WUTNGdMFuzfI5giCSZQNlAjgxMDfhmoJwDE6hbgOIErOl06NPt9dQyJPDN5r Cjig== X-Gm-Message-State: AMCzsaV0yar328yP9KEeuvkBLSwCjBtiB9VT6jqKXAVdq+A3f84LUGZH WoF3PX6L5ZFuZMe9W0xlMHwS+SpCgUocgH0JKVGpXQ== X-Google-Smtp-Source: ABhQp+SGJTd/gsW3Al6G/X2phLB2AoCOMRzsUQKc4dV3mYggjkCZlOPDwMXEc6L0YvZTgnE5K6EkL+oTy3ia122TgiI= X-Received: by 10.36.31.212 with SMTP id d203mr4639429itd.48.1509200211272; Sat, 28 Oct 2017 07:16:51 -0700 (PDT) MIME-Version: 1.0 Received: by 10.107.131.167 with HTTP; Sat, 28 Oct 2017 07:16:50 -0700 (PDT) In-Reply-To: <20171026211939.7qace3rpz4ffnbrz@bivouac.eciton.net> References: <20171025175947.22798-1-ard.biesheuvel@linaro.org> <20171025175947.22798-14-ard.biesheuvel@linaro.org> <20171026211939.7qace3rpz4ffnbrz@bivouac.eciton.net> From: Ard Biesheuvel Date: Sat, 28 Oct 2017 15:16:50 +0100 Message-ID: To: Leif Lindholm Cc: "edk2-devel@lists.01.org" , Daniel Thompson , Masami Hiramatsu , =?UTF-8?B?UGlwYXQv44Oh44K/44Ov44OL44OD44OI44Od44OzIOODlOODkeODg+ODiA==?= 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: Sat, 28 Oct 2017 14:13:07 -0000 Content-Type: text/plain; charset="UTF-8" On 26 October 2017 at 22:19, Leif Lindholm wrote: > 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? > I can fix up the other cosmetic values, but unfortunately, only Socionext can address the comments regarding the use of symbolic constants, because I don't have a clue what they mean. Pipat? I will note that some of the comments below apply to ArmPlatformPkg/Drivers/NorFlashDxe equally. >> +}; >> + >> +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 >>