From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
To: Leif Lindholm <leif.lindholm@linaro.org>
Cc: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
"Daniel Thompson" <daniel.thompson@linaro.org>,
"Masami Hiramatsu" <masami.hiramatsu@linaro.org>,
"Pipat/メタワニットポン ピパット" <methavanitpong.pipat@socionext.com>
Subject: Re: [PATCH edk2-platforms v2 13/23] Silicon/Socionext: add driver for SPI NOR flash
Date: Sat, 28 Oct 2017 15:16:50 +0100 [thread overview]
Message-ID: <CAKv+Gu9H5TUa8MRTUOfEsitoybSkOa6wZk4koWCmX0wyz+FxSw@mail.gmail.com> (raw)
In-Reply-To: <20171026211939.7qace3rpz4ffnbrz@bivouac.eciton.net>
On 26 October 2017 at 22:19, Leif Lindholm <leif.lindholm@linaro.org> wrote:
> On Wed, Oct 25, 2017 at 06:59:37PM +0100, Ard Biesheuvel wrote:
>> From: Pipat Methavanitpong <methavanitpong.pipat@socionext.com>
>>
>> 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 <methavanitpong.pipat@socionext.com>
>>
>> [various tweaks and bugfixes]
>>
>> Contributed-under: TianoCore Contribution Agreement 1.1
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>
> 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.<BR>
>> +#
>> +# 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.<BR>
>> +# Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
>> +#
>> +# 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.<BR>
>> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
>> +
>> + 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.<BR>
>> + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
>> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
>> +
>> + 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 <Library/BaseMemoryLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +
>> +#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.<BR>
>> + Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
>> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
>> +
>> + 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 <Library/UefiLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/PcdLib.h>
>
> 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.<BR>
>> + Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
>> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
>> +
>> + 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 <Base.h>
>> +#include <PiDxe.h>
>> +
>> +#include <Guid/EventGroup.h>
>> +
>> +#include <Protocol/BlockIo.h>
>> +#include <Protocol/DiskIo.h>
>> +#include <Protocol/FirmwareVolumeBlock.h>
>> +
>> +#include <Library/DebugLib.h>
>> +#include <Library/IoLib.h>
>> +#include <Library/NorFlashPlatformLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/UefiRuntimeLib.h>
>> +#include <Library/DxeServicesTableLib.h>
>
> 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.<BR>
>> + Copyright (c) 2017, Socionext Inc. All rights reserved.<BR>
>> + Copyright (c) 2017, Linaro, Ltd. All rights reserved.<BR>
>> +
>> + 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 <PiDxe.h>
>> +
>> +#include <Library/PcdLib.h>
>> +#include <Library/BaseLib.h>
>> +#include <Library/HobLib.h>
>> +#include <Library/UefiLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +
>> +#include <Guid/VariableFormat.h>
>> +#include <Guid/SystemNvDataGuid.h>
>
> 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
>>
next prev parent reply other threads:[~2017-10-28 14:13 UTC|newest]
Thread overview: 54+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-10-25 17:59 [PATCH edk2-platforms v2 00/23] add support for Socionext Synquacer Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 01/23] Silicon/SynQuacer: add package with platform headers Ard Biesheuvel
2017-10-26 14:39 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 02/23] Silicon/Socionext: add driver for NETSEC network controller Ard Biesheuvel
2017-10-26 14:49 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 03/23] Silicon/SynQuacer: add MemoryInitPeiLib implementation Ard Biesheuvel
2017-10-26 14:56 ` Leif Lindholm
2017-10-26 14:57 ` Ard Biesheuvel
2017-10-26 15:05 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 04/23] Platform: add support for Socionext SynQuacer eval board Ard Biesheuvel
2017-10-26 15:02 ` Leif Lindholm
2017-10-26 15:14 ` Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 05/23] Silicon/SynQuacer: implement PciSegmentLib to support dual RCs Ard Biesheuvel
2017-10-26 15:06 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 06/23] Silicon/SynQuacer: implement PciHostBridgeLib support Ard Biesheuvel
2017-10-26 15:10 ` Leif Lindholm
2017-10-26 15:12 ` Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 07/23] Silicon/SynQuacer: implement EFI_CPU_IO2_PROTOCOL Ard Biesheuvel
2017-10-26 15:13 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 08/23] Platform/SynQuacerEvalBoard: add PCI support Ard Biesheuvel
2017-10-26 15:38 ` Leif Lindholm
2017-10-26 15:41 ` Ard Biesheuvel
2017-10-26 21:49 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 09/23] Platform/SynQuacerEvalBoard: add NETSEC driver Ard Biesheuvel
2017-10-26 15:39 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 10/23] Silicon/SynQuacer: add ACPI support Ard Biesheuvel
2017-10-26 17:13 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 11/23] Silicon/SynQuacer: add device tree support for eval board Ard Biesheuvel
2017-10-26 17:15 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 12/23] Silicon/SynQuacer: add NorFlashPlatformLib implementation Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 13/23] Silicon/Socionext: add driver for SPI NOR flash Ard Biesheuvel
2017-10-26 21:19 ` Leif Lindholm
2017-10-28 14:16 ` Ard Biesheuvel [this message]
2017-10-28 21:31 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 14/23] Platform/SynQuacer: incorporate NOR flash and variable drivers Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 15/23] Silicon/SynQuacer: implement PlatformFlashAccessLib Ard Biesheuvel
2017-10-26 21:22 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 16/23] SynQuacer/SynQuacerMemoryInitPeiLib: add capsule support Ard Biesheuvel
2017-10-26 21:27 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 17/23] Socionext/SynQuacerEvalBoard: wire up basic " Ard Biesheuvel
2017-10-26 21:28 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 18/23] Socionext/SynQuacerEvalBoard: switch to execute in place Ard Biesheuvel
2017-10-26 21:30 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 19/23] Platform/SynQuacerEvalBoard: add signed capsule update support Ard Biesheuvel
2017-10-26 21:33 ` Leif Lindholm
2017-10-28 13:48 ` Ard Biesheuvel
2017-10-25 17:59 ` [PATCH edk2-platforms v2 20/23] Silicon/SynQuacer/AcpiTables: hide PCI domain #0 Ard Biesheuvel
2017-10-26 21:34 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 21/23] Silicon/SynQuacerPciHostBridgeLib: add workaround to support 32-bit only cards Ard Biesheuvel
2017-10-26 21:35 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 22/23] Platform/Socionext: add support for Socionext Developer Box rev 0.1 Ard Biesheuvel
2017-10-26 21:46 ` Leif Lindholm
2017-10-25 17:59 ` [PATCH edk2-platforms v2 23/23] Platform/DeveloperBox: add ConsolePrefDxe driver Ard Biesheuvel
2017-10-26 21:46 ` Leif Lindholm
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAKv+Gu9H5TUa8MRTUOfEsitoybSkOa6wZk4koWCmX0wyz+FxSw@mail.gmail.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox