From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail05.groups.io (mail05.groups.io [45.79.224.7]) by spool.mail.gandi.net (Postfix) with ESMTPS id 8D122AC0F0C for ; Thu, 23 May 2024 10:56:10 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=mxJAzUUOG8cr20cfgKEIDGn41TsPs+QsSTajUWxvsP8=; c=relaxed/simple; d=groups.io; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Resent-Date:Resent-From:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding; s=20240206; t=1716461769; v=1; b=uqVTJyXLXrx1qcrL1Vci7Wj0X7lpkoxg81qCE9bgK9rkM5pFjG2Pdt69khT0qFjAGLajdlWh ig4NxkcBwCRGcBz3JBFoi3gP+s39SAgUVLiTWT6st49CImkUyN23UY1gUJdqOAEot8OF/2xHWzI eGdmVyDLKFB5ZekrP3H9YObuVlg5IS0y1qpf/i9zdi70EMklSqpoph3QizUogwo6i2q2ZrsbLMT TFgB7mqr3XwRVLtiLmKeSfJPWA14K/bg6ej1aCZwfGGO9uVgdw22gqqdlrgqdCstH9WsXA0lrcD aQbo6ZaeKI1EEhgwkkbIMess2mR46ApmxgTlhqk4mGBOQ== X-Received: by 127.0.0.2 with SMTP id s6vcYY7687511xPFm8pYX0oN; Thu, 23 May 2024 03:56:09 -0700 X-Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mx.groups.io with SMTP id smtpd.web10.12638.1716461767994877677 for ; Thu, 23 May 2024 03:56:08 -0700 X-Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id C4647DA7; Thu, 23 May 2024 03:56:31 -0700 (PDT) X-Received: from usa.arm.com (a077434.arm.com [10.162.46.143]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id C6A093F766; Thu, 23 May 2024 03:56:05 -0700 (PDT) From: "Sahil Kaushal" To: devel@edk2.groups.io Cc: Ard Biesheuvel , =?UTF-8?q?Leif=20Lindholm=20=C2=A0?= , Sami Mujawar , =?UTF-8?q?sahil=20=C2=A0?= Subject: [edk2-devel] [edk2-platforms][PATCH V3 08/17] Platform/ARM: Add P30NorFlashDeviceLib Library Date: Thu, 23 May 2024 16:25:02 +0530 Message-Id: <20240523105511.13189-9-Sahil.Kaushal@arm.com> In-Reply-To: <20240523105511.13189-1-Sahil.Kaushal@arm.com> References: <20240523105511.13189-1-Sahil.Kaushal@arm.com> MIME-Version: 1.0 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Resent-Date: Thu, 23 May 2024 03:56:08 -0700 Resent-From: sahil.kaushal@arm.com Reply-To: devel@edk2.groups.io,sahil.kaushal@arm.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: VAw3X89EIToCJUhgWCcSjfjnx7686176AA= Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=uqVTJyXL; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=arm.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 45.79.224.7 as permitted sender) smtp.mailfrom=bounce@groups.io From: sahil This patch implements functions to interact with P30 NOR Flash. The code is taken from Platform/ARM/Drivers/NorFlashDxe/NorFlash.c file. Signed-off-by: sahil --- Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.inf | 35 + Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.h | 98 ++ Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.c | 953 += +++++++++++++++++++ 3 files changed, 1086 insertions(+) diff --git a/Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib= .inf b/Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.inf new file mode 100644 index 000000000000..0707edb54442 --- /dev/null +++ b/Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.inf @@ -0,0 +1,35 @@ +#/** @file=0D +#=0D +# Component description file for P30NorFlashDeviceLib library=0D +#=0D +# Copyright (c) 2011 - 2024, Arm Limited. All rights reserved.
=0D +# Copyright (c) 2020, Linaro, Ltd. All rights reserved.
=0D +#=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +#**/=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010005=0D + BASE_NAME =3D P30NorFlashDeviceLib=0D + FILE_GUID =3D ed172366-066b-4998-9b5e-ca7f385a1709=0D + MODULE_TYPE =3D DXE_DRIVER=0D + VERSION_STRING =3D 1.0=0D + LIBRARY_CLASS =3D NorFlashDeviceLib=0D +=0D +[Sources.common]=0D + P30NorFlashDeviceLib.c=0D + P30NorFlashDeviceLib.h=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + Platform/ARM/ARM.dec=0D +=0D +[LibraryClasses]=0D + BaseLib=0D + BaseMemoryLib=0D + DebugLib=0D + IoLib=0D +=0D +[Pcd.common]=0D + gPlatformArmTokenSpaceGuid.PcdNorFlashCheckBlockLocked=0D diff --git a/Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib= .h b/Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.h new file mode 100644 index 000000000000..c310b2310d62 --- /dev/null +++ b/Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.h @@ -0,0 +1,98 @@ +/** @file P30NorFlashDeviceLib.h=0D +=0D + Copyright (c) 2011 - 2024, Arm Limited. All rights reserved.
=0D + Copyright (c) 2020, Linaro, Ltd. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#ifndef P30_NOR_FLASH_DEVICE_LIB_H_=0D +#define P30_NOR_FLASH_DEVICE_LIB_H_=0D +=0D +#define NOR_FLASH_ERASE_RETRY 10=0D +=0D +// Device access macros=0D +// These are necessary because we use 2 x 16bit parts to make up 32bit dat= a=0D +=0D +#define HIGH_16_BITS 0xFFFF0000=0D +#define LOW_16_BITS 0x0000FFFF=0D +#define LOW_8_BITS 0x000000FF=0D +=0D +#define FOLD_32BIT_INTO_16BIT(value) ( ( value >> 16 ) | ( value & LOW_16= _BITS ) )=0D +=0D +#define GET_LOW_BYTE(value) ( value & LOW_8_BITS )=0D +#define GET_HIGH_BYTE(value) ( GET_LOW_BYTE( value >> 16 ) )=0D +=0D +// Each command must be sent simultaneously to both chips,=0D +// i.e. at the lower 16 bits AND at the higher 16 bits=0D +#define CREATE_NOR_ADDRESS(BaseAddr, OffsetAddr) ((BaseAddr) + ((OffsetAd= dr) << 2))=0D +#define CREATE_DUAL_CMD(Cmd) ( ( Cmd << 16) | ( Cmd &= LOW_16_BITS) )=0D +#define SEND_NOR_COMMAND(BaseAddr, Offset, Cmd) MmioWrite32 (CREATE_NOR_= ADDRESS(BaseAddr,Offset), CREATE_DUAL_CMD(Cmd))=0D +=0D +#define BOTH_ALIGNED(a, b, align) ((((UINTN)(a) | (UINTN)(b)) & ((align) = - 1)) =3D=3D 0)=0D +=0D +// Status Register Bits=0D +#define P30_SR_BIT_WRITE (BIT7 << 16 | BIT7)=0D +#define P30_SR_BIT_ERASE_SUSPEND (BIT6 << 16 | BIT6)=0D +#define P30_SR_BIT_ERASE (BIT5 << 16 | BIT5)=0D +#define P30_SR_BIT_PROGRAM (BIT4 << 16 | BIT4)=0D +#define P30_SR_BIT_VPP (BIT3 << 16 | BIT3)=0D +#define P30_SR_BIT_PROGRAM_SUSPEND (BIT2 << 16 | BIT2)=0D +#define P30_SR_BIT_BLOCK_LOCKED (BIT1 << 16 | BIT1)=0D +#define P30_SR_BIT_BEFP (BIT0 << 16 | BIT0)=0D +=0D +// Device Commands for Intel StrataFlash(R) Embedded Memory (P30) Family=0D +=0D +// On chip buffer size for buffered programming operations=0D +// There are 2 chips, each chip can buffer up to 32 (16-bit)words, and eac= h word is 2 bytes.=0D +// Therefore the total size of the buffer is 2 x 32 x 2 =3D 128 bytes=0D +#define P30_MAX_BUFFER_SIZE_IN_BYTES ((UINTN)128)=0D +#define P30_MAX_BUFFER_SIZE_IN_WORDS (P30_MAX_BUFFER_SIZE_IN_BYTES/((UINT= N)4))=0D +#define MAX_BUFFERED_PROG_ITERATIONS 10000000=0D +#define BOUNDARY_OF_32_WORDS 0x7F=0D +=0D +// CFI Addresses=0D +#define P30_CFI_ADDR_QUERY_UNIQUE_QRY 0x10=0D +#define P30_CFI_ADDR_VENDOR_ID 0x13=0D +=0D +// CFI Data=0D +#define CFI_QRY 0x00595251=0D +=0D +// READ Commands=0D +#define P30_CMD_READ_DEVICE_ID 0x0090=0D +#define P30_CMD_READ_STATUS_REGISTER 0x0070=0D +#define P30_CMD_CLEAR_STATUS_REGISTER 0x0050=0D +#define P30_CMD_READ_ARRAY 0x00FF=0D +#define P30_CMD_READ_CFI_QUERY 0x0098=0D +=0D +// WRITE Commands=0D +#define P30_CMD_WORD_PROGRAM_SETUP 0x0040=0D +#define P30_CMD_ALTERNATE_WORD_PROGRAM_SETUP 0x0010=0D +#define P30_CMD_BUFFERED_PROGRAM_SETUP 0x00E8=0D +#define P30_CMD_BUFFERED_PROGRAM_CONFIRM 0x00D0=0D +#define P30_CMD_BEFP_SETUP 0x0080=0D +#define P30_CMD_BEFP_CONFIRM 0x00D0=0D +=0D +// ERASE Commands=0D +#define P30_CMD_BLOCK_ERASE_SETUP 0x0020=0D +#define P30_CMD_BLOCK_ERASE_CONFIRM 0x00D0=0D +=0D +// SUSPEND Commands=0D +#define P30_CMD_PROGRAM_OR_ERASE_SUSPEND 0x00B0=0D +#define P30_CMD_SUSPEND_RESUME 0x00D0=0D +=0D +// BLOCK LOCKING / UNLOCKING Commands=0D +#define P30_CMD_LOCK_BLOCK_SETUP 0x0060=0D +#define P30_CMD_LOCK_BLOCK 0x0001=0D +#define P30_CMD_UNLOCK_BLOCK 0x00D0=0D +#define P30_CMD_LOCK_DOWN_BLOCK 0x002F=0D +=0D +// PROTECTION Commands=0D +#define P30_CMD_PROGRAM_PROTECTION_REGISTER_SETUP 0x00C0=0D +=0D +// CONFIGURATION Commands=0D +#define P30_CMD_READ_CONFIGURATION_REGISTER_SETUP 0x0060=0D +#define P30_CMD_READ_CONFIGURATION_REGISTER 0x0003=0D +=0D +#endif /* P30_NOR_FLASH_DEVICE_LIB_H_ */=0D diff --git a/Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib= .c b/Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.c new file mode 100644 index 000000000000..5af085bdf493 --- /dev/null +++ b/Platform/ARM/Library/P30NorFlashDeviceLib/P30NorFlashDeviceLib.c @@ -0,0 +1,953 @@ +/** @file P30NorFlashDeviceLib.c=0D +=0D + Copyright (c) 2011 - 2024, Arm Limited. All rights reserved.
=0D + Copyright (c) 2020, Linaro, Ltd. All rights reserved.
=0D +=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "P30NorFlashDeviceLib.h"=0D +=0D +STATIC=0D +UINT32=0D +NorFlashReadStatusRegister (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN SR_Address=0D + )=0D +{=0D + // Prepare to read the status register=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_RE= GISTER);=0D + return MmioRead32 (Instance->DeviceBaseAddress);=0D +}=0D +=0D +STATIC=0D +BOOLEAN=0D +NorFlashBlockIsLocked (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + UINT32 LockStatus;=0D +=0D + // Send command for reading device id=0D + SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);=0D +=0D + // Read block lock status=0D + LockStatus =3D MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));=0D +=0D + // Decode block lock status=0D + LockStatus =3D FOLD_32BIT_INTO_16BIT (LockStatus);=0D +=0D + if ((LockStatus & 0x2) !=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOW= N\n"));=0D + }=0D +=0D + return ((LockStatus & 0x1) !=3D 0);=0D +}=0D +=0D +STATIC=0D +EFI_STATUS=0D +NorFlashUnlockSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + UINT32 LockStatus;=0D +=0D + // Raise the Task Priority Level to TPL_NOTIFY to serialise all its oper= ations=0D + // and to protect shared data structures.=0D +=0D + if (FeaturePcdGet (PcdNorFlashCheckBlockLocked) =3D=3D TRUE) {=0D + do {=0D + // Request a lock setup=0D + SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);=0D +=0D + // Request an unlock=0D + SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);=0D +=0D + // Send command for reading device id=0D + SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);=0D +=0D + // Read block lock status=0D + LockStatus =3D MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));=0D +=0D + // Decode block lock status=0D + LockStatus =3D FOLD_32BIT_INTO_16BIT (LockStatus);=0D + } while ((LockStatus & 0x1) =3D=3D 1);=0D + } else {=0D + // Request a lock setup=0D + SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);=0D +=0D + // Request an unlock=0D + SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);=0D +=0D + // Wait until the status register gives us the all clear=0D + do {=0D + LockStatus =3D NorFlashReadStatusRegister (Instance, BlockAddress);= =0D + } while ((LockStatus & P30_SR_BIT_WRITE) !=3D P30_SR_BIT_WRITE);=0D + }=0D +=0D + // Put device back into Read Array mode=0D + SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);=0D +=0D + DEBUG ((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=3D0x%08x\n", Block= Address));=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +STATIC=0D +EFI_STATUS=0D +NorFlashUnlockSingleBlockIfNecessary (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + EFI_STATUS Status;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + if (NorFlashBlockIsLocked (Instance, BlockAddress)) {=0D + Status =3D NorFlashUnlockSingleBlock (Instance, BlockAddress);=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +/**=0D + * The following function presumes that the block has already been unlocke= d.=0D + **/=0D +EFI_STATUS=0D +NorFlashEraseSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT32 StatusRegister;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + // Request a block erase and then confirm it=0D + SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);=0D + SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);=0D +=0D + // Wait until the status register gives us the all clear=0D + do {=0D + StatusRegister =3D NorFlashReadStatusRegister (Instance, BlockAddress)= ;=0D + } while ((StatusRegister & P30_SR_BIT_WRITE) !=3D P30_SR_BIT_WRITE);=0D +=0D + if (StatusRegister & P30_SR_BIT_VPP) {=0D + DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=3D0x%08x: VPP Rang= e Error\n", BlockAddress));=0D + Status =3D EFI_DEVICE_ERROR;=0D + }=0D +=0D + if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) =3D=3D (P= 30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) {=0D + DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=3D0x%08x: Command = Sequence Error\n", BlockAddress));=0D + Status =3D EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (StatusRegister & P30_SR_BIT_ERASE) {=0D + DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=3D0x%08x: Block Er= ase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister));=0D + Status =3D EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {=0D + // The debug level message has been reduced because a device lock migh= t happen. In this case we just retry it ...=0D + DEBUG ((DEBUG_INFO, "EraseSingleBlock(BlockAddress=3D0x%08x: Block Loc= ked Error\n", BlockAddress));=0D + Status =3D EFI_WRITE_PROTECTED;=0D + }=0D +=0D + if (EFI_ERROR (Status)) {=0D + // Clear the Status Register=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS= _REGISTER);=0D + }=0D +=0D + // Put device back into Read Array mode=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);=0D +=0D + return Status;=0D +}=0D +=0D +STATIC=0D +EFI_STATUS=0D +NorFlashWriteSingleWord (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN WordAddress,=0D + IN UINT32 WriteData=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINT32 StatusRegister;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + // Request a write single word command=0D + SEND_NOR_COMMAND (WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);=0D +=0D + // Store the word into NOR Flash;=0D + MmioWrite32 (WordAddress, WriteData);=0D +=0D + // Wait for the write to complete and then check for any errors; i.e. ch= eck the Status Register=0D + do {=0D + // Prepare to read the status register=0D + StatusRegister =3D NorFlashReadStatusRegister (Instance, WordAddress);= =0D + // The chip is busy while the WRITE bit is not asserted=0D + } while ((StatusRegister & P30_SR_BIT_WRITE) !=3D P30_SR_BIT_WRITE);=0D +=0D + // Perform a full status check:=0D + // Mask the relevant bits of Status Register.=0D + // Everything should be zero, if not, we have a problem=0D +=0D + if (StatusRegister & P30_SR_BIT_VPP) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): VPP R= ange Error\n", WordAddress));=0D + Status =3D EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (StatusRegister & P30_SR_BIT_PROGRAM) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Progr= am Error\n", WordAddress));=0D + Status =3D EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Devic= e Protect Error\n", WordAddress));=0D + Status =3D EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (!EFI_ERROR (Status)) {=0D + // Clear the Status Register=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS= _REGISTER);=0D + }=0D +=0D + // Put device back into Read Array mode=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);=0D +=0D + return Status;=0D +}=0D +=0D +/*=0D + * Writes data to the NOR Flash using the Buffered Programming method.=0D + *=0D + * The maximum size of the on-chip buffer is 32-words, because of hardware= restrictions.=0D + * Therefore this function will only handle buffers up to 32 words or 128 = bytes.=0D + * To deal with larger buffers, call this function again.=0D + *=0D + * This function presumes that both the TargetAddress and the TargetAddres= s+BufferSize=0D + * exist entirely within the NOR Flash. Therefore these conditions will no= t be checked here.=0D + *=0D + * In buffered programming, if the target address not at the beginning of = a 32-bit word boundary,=0D + * then programming time is doubled and power consumption is increased.=0D + * Therefore, it is a requirement to align buffer writes to 32-bit word bo= undaries.=0D + * i.e. the last 4 bits of the target start address must be zero: 0x......= 00=0D + */=0D +STATIC=0D +EFI_STATUS=0D +NorFlashWriteBuffer (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN TargetAddress,=0D + IN UINTN BufferSizeInBytes,=0D + IN UINT32 *Buffer=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN BufferSizeInWords;=0D + UINTN Count;=0D + volatile UINT32 *Data;=0D + UINTN WaitForBuffer;=0D + BOOLEAN BufferAvailable;=0D + UINT32 StatusRegister;=0D +=0D + WaitForBuffer =3D MAX_BUFFERED_PROG_ITERATIONS;=0D + BufferAvailable =3D FALSE;=0D +=0D + // Check that the target address does not cross a 32-word boundary.=0D + if ((TargetAddress & BOUNDARY_OF_32_WORDS) !=3D 0) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Check there are some data to program=0D + if (BufferSizeInBytes =3D=3D 0) {=0D + return EFI_BUFFER_TOO_SMALL;=0D + }=0D +=0D + // Check that the buffer size does not exceed the maximum hardware buffe= r size on chip.=0D + if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) {=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // Check that the buffer size is a multiple of 32-bit words=0D + if ((BufferSizeInBytes % 4) !=3D 0) {=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // Pre-programming conditions checked, now start the algorithm.=0D +=0D + // Prepare the data destination address=0D + Data =3D (UINT32 *)TargetAddress;=0D +=0D + // Check the availability of the buffer=0D + do {=0D + // Issue the Buffered Program Setup command=0D + SEND_NOR_COMMAND (TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);=0D +=0D + // Read back the status register bit#7 from the same address=0D + if (((*Data) & P30_SR_BIT_WRITE) =3D=3D P30_SR_BIT_WRITE) {=0D + BufferAvailable =3D TRUE;=0D + }=0D +=0D + // Update the loop counter=0D + WaitForBuffer--;=0D + } while ((WaitForBuffer > 0) && (BufferAvailable =3D=3D FALSE));=0D +=0D + // The buffer was not available for writing=0D + if (WaitForBuffer =3D=3D 0) {=0D + Status =3D EFI_DEVICE_ERROR;=0D + goto EXIT;=0D + }=0D +=0D + // From now on we work in 32-bit words=0D + BufferSizeInWords =3D BufferSizeInBytes / (UINTN)4;=0D +=0D + // Write the word count, which is (buffer_size_in_words - 1),=0D + // because word count 0 means one word.=0D + SEND_NOR_COMMAND (TargetAddress, 0, (BufferSizeInWords - 1));=0D +=0D + // Write the data to the NOR Flash, advancing each address by 4 bytes=0D + for (Count =3D 0; Count < BufferSizeInWords; Count++, Data++, Buffer++) = {=0D + MmioWrite32 ((UINTN)Data, *Buffer);=0D + }=0D +=0D + // Issue the Buffered Program Confirm command, to start the programming = operation=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGR= AM_CONFIRM);=0D +=0D + // Wait for the write to complete and then check for any errors; i.e. ch= eck the Status Register=0D + do {=0D + StatusRegister =3D NorFlashReadStatusRegister (Instance, TargetAddress= );=0D + // The chip is busy while the WRITE bit is not asserted=0D + } while ((StatusRegister & P30_SR_BIT_WRITE) !=3D P30_SR_BIT_WRITE);=0D +=0D + // Perform a full status check:=0D + // Mask the relevant bits of Status Register.=0D + // Everything should be zero, if not, we have a problem=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + if (StatusRegister & P30_SR_BIT_VPP) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): VPP Ran= ge Error\n", TargetAddress));=0D + Status =3D EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (StatusRegister & P30_SR_BIT_PROGRAM) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Program= Error\n", TargetAddress));=0D + Status =3D EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Device = Protect Error\n", TargetAddress));=0D + Status =3D EFI_DEVICE_ERROR;=0D + }=0D +=0D + if (!EFI_ERROR (Status)) {=0D + // Clear the Status Register=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS= _REGISTER);=0D + }=0D +=0D +EXIT:=0D + // Put device back into Read Array mode=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);=0D +=0D + return Status;=0D +}=0D +=0D +EFI_STATUS=0D +NorFlashWriteBlocks (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN BufferSizeInBytes,=0D + IN VOID *Buffer=0D + )=0D +{=0D + UINT32 *pWriteBuffer;=0D + EFI_STATUS Status;=0D + EFI_LBA CurrentBlock;=0D + UINT32 BlockSizeInWords;=0D + UINT32 NumBlocks;=0D + UINT32 BlockCount;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + // The buffer must be valid=0D + if (Buffer =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + if (Instance->Media.ReadOnly =3D=3D TRUE) {=0D + return EFI_WRITE_PROTECTED;=0D + }=0D +=0D + // We must have some bytes to read=0D + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=3D0x%x\n", = BufferSizeInBytes));=0D + if (BufferSizeInBytes =3D=3D 0) {=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // The size of the buffer must be a multiple of the block size=0D + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =3D0x%x\n"= , Instance->Media.BlockSize));=0D + if ((BufferSizeInBytes % Instance->Media.BlockSize) !=3D 0) {=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // All blocks must be within the device=0D + NumBlocks =3D ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize;=0D +=0D + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=3D%d, LastBlock=3D%= ld, Lba=3D%ld.\n", NumBlocks, Instance->Media.LastBlock, Lba));=0D +=0D + if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed l= ast block.\n"));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + BlockSizeInWords =3D Instance->Media.BlockSize / 4;=0D +=0D + // Because the target *Buffer is a pointer to VOID, we must put all the = data into a pointer=0D + // to a proper data type, so use *ReadBuffer=0D + pWriteBuffer =3D (UINT32 *)Buffer;=0D +=0D + CurrentBlock =3D Lba;=0D + for (BlockCount =3D 0; BlockCount < NumBlocks; BlockCount++, CurrentBloc= k++, pWriteBuffer =3D pWriteBuffer + BlockSizeInWords) {=0D + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINT= N)CurrentBlock));=0D +=0D + Status =3D NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffe= r, BlockSizeInWords);=0D +=0D + if (EFI_ERROR (Status)) {=0D + break;=0D + }=0D + }=0D +=0D + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status =3D \"%r\".\n", S= tatus));=0D + return Status;=0D +}=0D +=0D +/**=0D + Copy Length bytes from Source to Destination, using aligned accesses onl= y.=0D + Note that this implementation uses memcpy() semantics rather then memmov= e()=0D + semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.= =0D +=0D + @param DestinationBuffer The target of the copy request.=0D + @param SourceBuffer The place to copy from.=0D + @param Length The number of bytes to copy.=0D +=0D + @return Destination=0D +=0D +**/=0D +STATIC=0D +VOID *=0D +AlignedCopyMem (=0D + OUT VOID *DestinationBuffer,=0D + IN CONST VOID *SourceBuffer,=0D + IN UINTN Length=0D + )=0D +{=0D + UINT8 *Destination8;=0D + CONST UINT8 *Source8;=0D + UINT32 *Destination32;=0D + CONST UINT32 *Source32;=0D + UINT64 *Destination64;=0D + CONST UINT64 *Source64;=0D +=0D + if (BOTH_ALIGNED (DestinationBuffer, SourceBuffer, 8) && (Length >=3D 8)= ) {=0D + Destination64 =3D DestinationBuffer;=0D + Source64 =3D SourceBuffer;=0D + while (Length >=3D 8) {=0D + *Destination64++ =3D *Source64++;=0D + Length -=3D 8;=0D + }=0D +=0D + Destination8 =3D (UINT8 *)Destination64;=0D + Source8 =3D (CONST UINT8 *)Source64;=0D + } else if (BOTH_ALIGNED (DestinationBuffer, SourceBuffer, 4) && (Length = >=3D 4)) {=0D + Destination32 =3D DestinationBuffer;=0D + Source32 =3D SourceBuffer;=0D + while (Length >=3D 4) {=0D + *Destination32++ =3D *Source32++;=0D + Length -=3D 4;=0D + }=0D +=0D + Destination8 =3D (UINT8 *)Destination32;=0D + Source8 =3D (CONST UINT8 *)Source32;=0D + } else {=0D + Destination8 =3D DestinationBuffer;=0D + Source8 =3D SourceBuffer;=0D + }=0D +=0D + while (Length-- !=3D 0) {=0D + *Destination8++ =3D *Source8++;=0D + }=0D +=0D + return DestinationBuffer;=0D +}=0D +=0D +EFI_STATUS=0D +NorFlashReadBlocks (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN BufferSizeInBytes,=0D + OUT VOID *Buffer=0D + )=0D +{=0D + UINT32 NumBlocks;=0D + UINTN StartAddress;=0D +=0D + DEBUG ((=0D + DEBUG_BLKIO,=0D + "NorFlashReadBlocks: BufferSize=3D0x%xB BlockSize=3D0x%xB LastBlock=3D= %ld, Lba=3D%ld.\n",=0D + BufferSizeInBytes,=0D + Instance->Media.BlockSize,=0D + Instance->Media.LastBlock,=0D + Lba=0D + ));=0D +=0D + // The buffer must be valid=0D + if (Buffer =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Return if we have not any byte to read=0D + if (BufferSizeInBytes =3D=3D 0) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + // The size of the buffer must be a multiple of the block size=0D + if ((BufferSizeInBytes % Instance->Media.BlockSize) !=3D 0) {=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // All blocks must be within the device=0D + NumBlocks =3D ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize;=0D +=0D + if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed las= t block\n"));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Get the address to start reading from=0D + StartAddress =3D GET_NOR_BLOCK_ADDRESS (=0D + Instance->RegionBaseAddress,=0D + Lba,=0D + Instance->Media.BlockSize=0D + );=0D +=0D + // Put the device into Read Array mode=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);=0D +=0D + // Readout the data=0D + AlignedCopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +EFI_STATUS=0D +NorFlashRead (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN UINTN BufferSizeInBytes,=0D + OUT VOID *Buffer=0D + )=0D +{=0D + UINTN StartAddress;=0D +=0D + // The buffer must be valid=0D + if (Buffer =3D=3D NULL) {=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Return if we have not any byte to read=0D + if (BufferSizeInBytes =3D=3D 0) {=0D + return EFI_SUCCESS;=0D + }=0D +=0D + if (((Lba * Instance->Media.BlockSize) + Offset + BufferSizeInBytes) > I= nstance->Size) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashRead: ERROR - Read will exceed device si= ze.\n"));=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + // Get the address to start reading from=0D + StartAddress =3D GET_NOR_BLOCK_ADDRESS (=0D + Instance->RegionBaseAddress,=0D + Lba,=0D + Instance->Media.BlockSize=0D + );=0D +=0D + // Put the device into Read Array mode=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);=0D +=0D + // Readout the data=0D + AlignedCopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInByt= es);=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/*=0D + Write a full or portion of a block. It must not span block boundaries; t= hat is,=0D + Offset + *NumBytes <=3D Instance->Media.BlockSize.=0D +*/=0D +EFI_STATUS=0D +NorFlashWriteSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINTN Offset,=0D + IN OUT UINTN *NumBytes,=0D + IN UINT8 *Buffer=0D + )=0D +{=0D + EFI_STATUS TempStatus;=0D + UINT32 Tmp;=0D + UINT32 TmpBuf;=0D + UINT32 WordToWrite;=0D + UINT32 Mask;=0D + BOOLEAN DoErase;=0D + UINTN BytesToWrite;=0D + UINTN CurOffset;=0D + UINTN WordAddr;=0D + UINTN BlockSize;=0D + UINTN BlockAddress;=0D + UINTN PrevBlockAddress;=0D +=0D + PrevBlockAddress =3D 0;=0D +=0D + DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=3D%ld, Of= fset=3D0x%x, *NumBytes=3D0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes,= Buffer));=0D +=0D + // Detect WriteDisabled state=0D + if (Instance->Media.ReadOnly =3D=3D TRUE) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - Can not write:= Device is in WriteDisabled state.\n"));=0D + // It is in WriteDisabled state, return an error right away=0D + return EFI_ACCESS_DENIED;=0D + }=0D +=0D + // Cache the block size to avoid de-referencing pointers all the time=0D + BlockSize =3D Instance->Media.BlockSize;=0D +=0D + // The write must not span block boundaries.=0D + // We need to check each variable individually because adding two large = values together overflows.=0D + if ((Offset >=3D BlockSize) ||=0D + (*NumBytes > BlockSize) ||=0D + ((Offset + *NumBytes) > BlockSize))=0D + {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER= _SIZE: (Offset=3D0x%x + NumBytes=3D0x%x) > BlockSize=3D0x%x\n", Offset, *Nu= mBytes, BlockSize));=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // We must have some bytes to write=0D + if (*NumBytes =3D=3D 0) {=0D + DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER= _SIZE: (Offset=3D0x%x + NumBytes=3D0x%x) > BlockSize=3D0x%x\n", Offset, *Nu= mBytes, BlockSize));=0D + return EFI_BAD_BUFFER_SIZE;=0D + }=0D +=0D + // Pick 128bytes as a good start for word operations as opposed to erasi= ng the=0D + // block and writing the data regardless if an erase is really needed.=0D + // It looks like most individual NV variable writes are smaller than 128= bytes.=0D + if (*NumBytes <=3D 128) {=0D + // Check to see if we need to erase before programming the data into N= OR.=0D + // If the destination bits are only changing from 1s to 0s we can just= write.=0D + // After a block is erased all bits in the block is set to 1.=0D + // If any byte requires us to erase we just give up and rewrite all of= it.=0D + DoErase =3D FALSE;=0D + BytesToWrite =3D *NumBytes;=0D + CurOffset =3D Offset;=0D +=0D + while (BytesToWrite > 0) {=0D + // Read full word from NOR, splice as required. A word is the smalle= st=0D + // unit we can write.=0D + TempStatus =3D NorFlashRead (Instance, Lba, CurOffset & ~(0x3), size= of (Tmp), &Tmp);=0D + if (EFI_ERROR (TempStatus)) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + // Physical address of word in NOR to write.=0D + WordAddr =3D (CurOffset & ~(0x3)) + GET_NOR_BLOCK_ADDRESS (=0D + Instance->RegionBaseAddress,=0D + Lba,=0D + BlockSize=0D + );=0D + // The word of data that is to be written.=0D + TmpBuf =3D *((UINT32 *)(Buffer + (*NumBytes - BytesToWrite)));=0D +=0D + // First do word aligned chunks.=0D + if ((CurOffset & 0x3) =3D=3D 0) {=0D + if (BytesToWrite >=3D 4) {=0D + // Is the destination still in 'erased' state?=0D + if (~Tmp !=3D 0) {=0D + // Check to see if we are only changing bits to zero.=0D + if ((Tmp ^ TmpBuf) & TmpBuf) {=0D + DoErase =3D TRUE;=0D + break;=0D + }=0D + }=0D +=0D + // Write this word to NOR=0D + WordToWrite =3D TmpBuf;=0D + CurOffset +=3D sizeof (TmpBuf);=0D + BytesToWrite -=3D sizeof (TmpBuf);=0D + } else {=0D + // BytesToWrite < 4. Do small writes and left-overs=0D + Mask =3D ~((~0) << (BytesToWrite * 8));=0D + // Mask out the bytes we want.=0D + TmpBuf &=3D Mask;=0D + // Is the destination still in 'erased' state?=0D + if ((Tmp & Mask) !=3D Mask) {=0D + // Check to see if we are only changing bits to zero.=0D + if ((Tmp ^ TmpBuf) & TmpBuf) {=0D + DoErase =3D TRUE;=0D + break;=0D + }=0D + }=0D +=0D + // Merge old and new data. Write merged word to NOR=0D + WordToWrite =3D (Tmp & ~Mask) | TmpBuf;=0D + CurOffset +=3D BytesToWrite;=0D + BytesToWrite =3D 0;=0D + }=0D + } else {=0D + // Do multiple words, but starting unaligned.=0D + if (BytesToWrite > (4 - (CurOffset & 0x3))) {=0D + Mask =3D ((~0) << ((CurOffset & 0x3) * 8));=0D + // Mask out the bytes we want.=0D + TmpBuf &=3D Mask;=0D + // Is the destination still in 'erased' state?=0D + if ((Tmp & Mask) !=3D Mask) {=0D + // Check to see if we are only changing bits to zero.=0D + if ((Tmp ^ TmpBuf) & TmpBuf) {=0D + DoErase =3D TRUE;=0D + break;=0D + }=0D + }=0D +=0D + // Merge old and new data. Write merged word to NOR=0D + WordToWrite =3D (Tmp & ~Mask) | TmpBuf;=0D + BytesToWrite -=3D (4 - (CurOffset & 0x3));=0D + CurOffset +=3D (4 - (CurOffset & 0x3));=0D + } else {=0D + // Unaligned and fits in one word.=0D + Mask =3D (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) *= 8);=0D + // Mask out the bytes we want.=0D + TmpBuf =3D (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;=0D + // Is the destination still in 'erased' state?=0D + if ((Tmp & Mask) !=3D Mask) {=0D + // Check to see if we are only changing bits to zero.=0D + if ((Tmp ^ TmpBuf) & TmpBuf) {=0D + DoErase =3D TRUE;=0D + break;=0D + }=0D + }=0D +=0D + // Merge old and new data. Write merged word to NOR=0D + WordToWrite =3D (Tmp & ~Mask) | TmpBuf;=0D + CurOffset +=3D BytesToWrite;=0D + BytesToWrite =3D 0;=0D + }=0D + }=0D +=0D + //=0D + // Write the word to NOR.=0D + //=0D +=0D + BlockAddress =3D GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress,= Lba, BlockSize);=0D + if (BlockAddress !=3D PrevBlockAddress) {=0D + TempStatus =3D NorFlashUnlockSingleBlockIfNecessary (Instance, Blo= ckAddress);=0D + if (EFI_ERROR (TempStatus)) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + PrevBlockAddress =3D BlockAddress;=0D + }=0D +=0D + TempStatus =3D NorFlashWriteSingleWord (Instance, WordAddr, WordToWr= ite);=0D + if (EFI_ERROR (TempStatus)) {=0D + return EFI_DEVICE_ERROR;=0D + }=0D + }=0D +=0D + // Exit if we got here and could write all the data. Otherwise do the= =0D + // Erase-Write cycle.=0D + if (!DoErase) {=0D + return EFI_SUCCESS;=0D + }=0D + }=0D +=0D + // Check we did get some memory. Buffer is BlockSize.=0D + if (Instance->ShadowBuffer =3D=3D NULL) {=0D + DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + // Read NOR Flash data into shadow buffer=0D + TempStatus =3D NorFlashReadBlocks (Instance, Lba, BlockSize, Instance->S= hadowBuffer);=0D + if (EFI_ERROR (TempStatus)) {=0D + // Return one of the pre-approved error statuses=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + // Put the data at the appropriate location inside the buffer area=0D + CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumB= ytes);=0D +=0D + // Write the modified buffer back to the NorFlash=0D + TempStatus =3D NorFlashWriteBlocks (Instance, Lba, BlockSize, Instance->= ShadowBuffer);=0D + if (EFI_ERROR (TempStatus)) {=0D + // Return one of the pre-approved error statuses=0D + return EFI_DEVICE_ERROR;=0D + }=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + * This function unlock and erase an entire NOR Flash block.=0D + **/=0D +EFI_STATUS=0D +NorFlashUnlockAndEraseSingleBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN UINTN BlockAddress=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN Index;=0D + EFI_TPL OriginalTPL;=0D +=0D + NorFlashLock (&OriginalTPL);=0D +=0D + Index =3D 0;=0D + // The block erase might fail a first time (SW bug ?). Retry it ...=0D + do {=0D + // Unlock the block if we have to=0D + Status =3D NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddres= s);=0D + if (EFI_ERROR (Status)) {=0D + break;=0D + }=0D +=0D + Status =3D NorFlashEraseSingleBlock (Instance, BlockAddress);=0D + Index++;=0D + } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status =3D=3D EFI_WRITE_PRO= TECTED));=0D +=0D + if (Index =3D=3D NOR_FLASH_ERASE_RETRY) {=0D + DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=3D0x%08x: Block Lo= cked Error (try to erase %d times)\n", BlockAddress, Index));=0D + }=0D +=0D + NorFlashUnlock (OriginalTPL);=0D +=0D + return Status;=0D +}=0D +=0D +EFI_STATUS=0D +NorFlashWriteFullBlock (=0D + IN NOR_FLASH_INSTANCE *Instance,=0D + IN EFI_LBA Lba,=0D + IN UINT32 *DataBuffer,=0D + IN UINT32 BlockSizeInWords=0D + )=0D +{=0D + EFI_STATUS Status;=0D + UINTN WordAddress;=0D + UINT32 WordIndex;=0D + UINTN BufferIndex;=0D + UINTN BlockAddress;=0D + UINTN BuffersInBlock;=0D + UINTN RemainingWords;=0D + EFI_TPL OriginalTPL;=0D + UINTN Cnt;=0D +=0D + Status =3D EFI_SUCCESS;=0D +=0D + // Get the physical address of the block=0D + BlockAddress =3D GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba= , BlockSizeInWords * 4);=0D +=0D + // Start writing from the first address at the start of the block=0D + WordAddress =3D BlockAddress;=0D +=0D + NorFlashLock (&OriginalTPL);=0D +=0D + Status =3D NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and E= rase the single block at 0x%X\n", BlockAddress));=0D + goto EXIT;=0D + }=0D +=0D + // To speed up the programming operation, NOR Flash is programmed using = the Buffered Programming method.=0D +=0D + // Check that the address starts at a 32-word boundary, i.e. last 7 bits= must be zero=0D + if ((WordAddress & BOUNDARY_OF_32_WORDS) =3D=3D 0x00) {=0D + // First, break the entire block into buffer-sized chunks.=0D + BuffersInBlock =3D (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE= _IN_BYTES;=0D +=0D + // Then feed each buffer chunk to the NOR Flash=0D + // If a buffer does not contain any data, don't write it.=0D + for (BufferIndex =3D 0;=0D + BufferIndex < BuffersInBlock;=0D + BufferIndex++, WordAddress +=3D P30_MAX_BUFFER_SIZE_IN_BYTES, Dat= aBuffer +=3D P30_MAX_BUFFER_SIZE_IN_WORDS=0D + )=0D + {=0D + // Check the buffer to see if it contains any data (not set all 1s).= =0D + for (Cnt =3D 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {=0D + if (~DataBuffer[Cnt] !=3D 0 ) {=0D + // Some data found, write the buffer.=0D + Status =3D NorFlashWriteBuffer (=0D + Instance,=0D + WordAddress,=0D + P30_MAX_BUFFER_SIZE_IN_BYTES,=0D + DataBuffer=0D + );=0D + if (EFI_ERROR (Status)) {=0D + goto EXIT;=0D + }=0D +=0D + break;=0D + }=0D + }=0D + }=0D +=0D + // Finally, finish off any remaining words that are less than the maxi= mum size of the buffer=0D + RemainingWords =3D BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;=0D +=0D + if (RemainingWords !=3D 0) {=0D + Status =3D NorFlashWriteBuffer (Instance, WordAddress, (RemainingWor= ds * 4), DataBuffer);=0D + if (EFI_ERROR (Status)) {=0D + goto EXIT;=0D + }=0D + }=0D + } else {=0D + // For now, use the single word programming algorithm=0D + // It is unlikely that the NOR Flash will exist in an address which fa= lls within a 32 word boundary range,=0D + // i.e. which ends in the range 0x......01 - 0x......7F.=0D + for (WordIndex =3D 0; WordIndex < BlockSizeInWords; WordIndex++, DataB= uffer++, WordAddress =3D WordAddress + 4) {=0D + Status =3D NorFlashWriteSingleWord (Instance, WordAddress, *DataBuff= er);=0D + if (EFI_ERROR (Status)) {=0D + goto EXIT;=0D + }=0D + }=0D + }=0D +=0D +EXIT:=0D + NorFlashUnlock (OriginalTPL);=0D +=0D + if (EFI_ERROR (Status)) {=0D + DEBUG ((DEBUG_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed = at address 0x%08x. Exit Status =3D \"%r\".\n", WordAddress, Status));=0D + }=0D +=0D + return Status;=0D +}=0D +=0D +EFI_STATUS=0D +NorFlashReset (=0D + IN NOR_FLASH_INSTANCE *Instance=0D + )=0D +{=0D + // As there is no specific RESET to perform, ensure that the devices is = in the default Read Array mode=0D + SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);=0D + return EFI_SUCCESS;=0D +}=0D --=20 2.25.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#119150): https://edk2.groups.io/g/devel/message/119150 Mute This Topic: https://groups.io/mt/106260146/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-