public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Sahil Kaushal" <sahil.kaushal@arm.com>
To: devel@edk2.groups.io
Cc: "Ard Biesheuvel" <ardb+tianocore@kernel.org>,
	"Leif Lindholm  " <quic_llindhol@quicinc.com>,
	"Sami Mujawar" <sami.mujawar@arm.com>, "sahil  " <sahil@arm.com>
Subject: [edk2-devel] [edk2-platforms][PATCH V4 08/17] Platform/ARM: Add P30NorFlashDeviceLib Library
Date: Wed, 29 May 2024 14:25:08 +0530	[thread overview]
Message-ID: <20240529085517.1074417-9-Sahil.Kaushal@arm.com> (raw)
In-Reply-To: <20240529085517.1074417-1-Sahil.Kaushal@arm.com>

From: sahil <sahil@arm.com>

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 <sahil@arm.com>
---
 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
+#
+#  Component description file for P30NorFlashDeviceLib library
+#
+#  Copyright (c) 2011 - 2024, Arm Limited. All rights reserved.<BR>
+#  Copyright (c) 2020, Linaro, Ltd. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  INF_VERSION                = 0x00010005
+  BASE_NAME                  = P30NorFlashDeviceLib
+  FILE_GUID                  = ed172366-066b-4998-9b5e-ca7f385a1709
+  MODULE_TYPE                = DXE_DRIVER
+  VERSION_STRING             = 1.0
+  LIBRARY_CLASS              = NorFlashDeviceLib
+
+[Sources.common]
+  P30NorFlashDeviceLib.c
+  P30NorFlashDeviceLib.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  Platform/ARM/ARM.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  IoLib
+
+[Pcd.common]
+  gPlatformArmTokenSpaceGuid.PcdNorFlashCheckBlockLocked
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
+
+  Copyright (c) 2011 - 2024, Arm Limited. All rights reserved.<BR>
+  Copyright (c) 2020, Linaro, Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef P30_NOR_FLASH_DEVICE_LIB_H_
+#define P30_NOR_FLASH_DEVICE_LIB_H_
+
+#define NOR_FLASH_ERASE_RETRY  10
+
+// Device access macros
+// These are necessary because we use 2 x 16bit parts to make up 32bit data
+
+#define HIGH_16_BITS  0xFFFF0000
+#define LOW_16_BITS   0x0000FFFF
+#define LOW_8_BITS    0x000000FF
+
+#define FOLD_32BIT_INTO_16BIT(value)  ( ( value >> 16 ) | ( value & LOW_16_BITS ) )
+
+#define GET_LOW_BYTE(value)   ( value & LOW_8_BITS )
+#define GET_HIGH_BYTE(value)  ( GET_LOW_BYTE( value >> 16 ) )
+
+// Each command must be sent simultaneously to both chips,
+// i.e. at the lower 16 bits AND at the higher 16 bits
+#define CREATE_NOR_ADDRESS(BaseAddr, OffsetAddr)  ((BaseAddr) + ((OffsetAddr) << 2))
+#define CREATE_DUAL_CMD(Cmd)                      ( ( Cmd << 16) | ( Cmd & LOW_16_BITS) )
+#define SEND_NOR_COMMAND(BaseAddr, Offset, Cmd)   MmioWrite32 (CREATE_NOR_ADDRESS(BaseAddr,Offset), CREATE_DUAL_CMD(Cmd))
+
+#define BOTH_ALIGNED(a, b, align)  ((((UINTN)(a) | (UINTN)(b)) & ((align) - 1)) == 0)
+
+// Status Register Bits
+#define P30_SR_BIT_WRITE            (BIT7 << 16 | BIT7)
+#define P30_SR_BIT_ERASE_SUSPEND    (BIT6 << 16 | BIT6)
+#define P30_SR_BIT_ERASE            (BIT5 << 16 | BIT5)
+#define P30_SR_BIT_PROGRAM          (BIT4 << 16 | BIT4)
+#define P30_SR_BIT_VPP              (BIT3 << 16 | BIT3)
+#define P30_SR_BIT_PROGRAM_SUSPEND  (BIT2 << 16 | BIT2)
+#define P30_SR_BIT_BLOCK_LOCKED     (BIT1 << 16 | BIT1)
+#define P30_SR_BIT_BEFP             (BIT0 << 16 | BIT0)
+
+// Device Commands for Intel StrataFlash(R) Embedded Memory (P30) Family
+
+// On chip buffer size for buffered programming operations
+// There are 2 chips, each chip can buffer up to 32 (16-bit)words, and each word is 2 bytes.
+// Therefore the total size of the buffer is 2 x 32 x 2 = 128 bytes
+#define P30_MAX_BUFFER_SIZE_IN_BYTES  ((UINTN)128)
+#define P30_MAX_BUFFER_SIZE_IN_WORDS  (P30_MAX_BUFFER_SIZE_IN_BYTES/((UINTN)4))
+#define MAX_BUFFERED_PROG_ITERATIONS  10000000
+#define BOUNDARY_OF_32_WORDS          0x7F
+
+// CFI Addresses
+#define P30_CFI_ADDR_QUERY_UNIQUE_QRY  0x10
+#define P30_CFI_ADDR_VENDOR_ID         0x13
+
+// CFI Data
+#define CFI_QRY  0x00595251
+
+// READ Commands
+#define P30_CMD_READ_DEVICE_ID         0x0090
+#define P30_CMD_READ_STATUS_REGISTER   0x0070
+#define P30_CMD_CLEAR_STATUS_REGISTER  0x0050
+#define P30_CMD_READ_ARRAY             0x00FF
+#define P30_CMD_READ_CFI_QUERY         0x0098
+
+// WRITE Commands
+#define P30_CMD_WORD_PROGRAM_SETUP            0x0040
+#define P30_CMD_ALTERNATE_WORD_PROGRAM_SETUP  0x0010
+#define P30_CMD_BUFFERED_PROGRAM_SETUP        0x00E8
+#define P30_CMD_BUFFERED_PROGRAM_CONFIRM      0x00D0
+#define P30_CMD_BEFP_SETUP                    0x0080
+#define P30_CMD_BEFP_CONFIRM                  0x00D0
+
+// ERASE Commands
+#define P30_CMD_BLOCK_ERASE_SETUP    0x0020
+#define P30_CMD_BLOCK_ERASE_CONFIRM  0x00D0
+
+// SUSPEND Commands
+#define P30_CMD_PROGRAM_OR_ERASE_SUSPEND  0x00B0
+#define P30_CMD_SUSPEND_RESUME            0x00D0
+
+// BLOCK LOCKING / UNLOCKING Commands
+#define P30_CMD_LOCK_BLOCK_SETUP  0x0060
+#define P30_CMD_LOCK_BLOCK        0x0001
+#define P30_CMD_UNLOCK_BLOCK      0x00D0
+#define P30_CMD_LOCK_DOWN_BLOCK   0x002F
+
+// PROTECTION Commands
+#define P30_CMD_PROGRAM_PROTECTION_REGISTER_SETUP  0x00C0
+
+// CONFIGURATION Commands
+#define P30_CMD_READ_CONFIGURATION_REGISTER_SETUP  0x0060
+#define P30_CMD_READ_CONFIGURATION_REGISTER        0x0003
+
+#endif /* P30_NOR_FLASH_DEVICE_LIB_H_ */
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
+
+  Copyright (c) 2011 - 2024, Arm Limited. All rights reserved.<BR>
+  Copyright (c) 2020, Linaro, Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/NorFlashDeviceLib.h>
+
+#include "P30NorFlashDeviceLib.h"
+
+STATIC
+UINT32
+NorFlashReadStatusRegister (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               SR_Address
+  )
+{
+  // Prepare to read the status register
+  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);
+  return MmioRead32 (Instance->DeviceBaseAddress);
+}
+
+STATIC
+BOOLEAN
+NorFlashBlockIsLocked (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               BlockAddress
+  )
+{
+  UINT32  LockStatus;
+
+  // Send command for reading device id
+  SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
+
+  // Read block lock status
+  LockStatus = MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));
+
+  // Decode block lock status
+  LockStatus = FOLD_32BIT_INTO_16BIT (LockStatus);
+
+  if ((LockStatus & 0x2) != 0) {
+    DEBUG ((DEBUG_ERROR, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
+  }
+
+  return ((LockStatus & 0x1) != 0);
+}
+
+STATIC
+EFI_STATUS
+NorFlashUnlockSingleBlock (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               BlockAddress
+  )
+{
+  UINT32  LockStatus;
+
+  // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
+  // and to protect shared data structures.
+
+  if (FeaturePcdGet (PcdNorFlashCheckBlockLocked) == TRUE) {
+    do {
+      // Request a lock setup
+      SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
+
+      // Request an unlock
+      SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
+
+      // Send command for reading device id
+      SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
+
+      // Read block lock status
+      LockStatus = MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));
+
+      // Decode block lock status
+      LockStatus = FOLD_32BIT_INTO_16BIT (LockStatus);
+    } while ((LockStatus & 0x1) == 1);
+  } else {
+    // Request a lock setup
+    SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
+
+    // Request an unlock
+    SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
+
+    // Wait until the status register gives us the all clear
+    do {
+      LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress);
+    } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
+  }
+
+  // Put device back into Read Array mode
+  SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);
+
+  DEBUG ((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x\n", 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)) {
+    Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
+  }
+
+  return Status;
+}
+
+/**
+ * The following function presumes that the block has already been unlocked.
+ **/
+EFI_STATUS
+NorFlashEraseSingleBlock (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               BlockAddress
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      StatusRegister;
+
+  Status = EFI_SUCCESS;
+
+  // Request a block erase and then confirm it
+  SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);
+  SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);
+
+  // Wait until the status register gives us the all clear
+  do {
+    StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress);
+  } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
+
+  if (StatusRegister & P30_SR_BIT_VPP) {
+    DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) == (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) {
+    DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (StatusRegister & P30_SR_BIT_ERASE) {
+    DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
+    // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
+    DEBUG ((DEBUG_INFO, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress));
+    Status = EFI_WRITE_PROTECTED;
+  }
+
+  if (EFI_ERROR (Status)) {
+    // Clear the Status Register
+    SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+  }
+
+  // Put device back into Read Array mode
+  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+  return Status;
+}
+
+STATIC
+EFI_STATUS
+NorFlashWriteSingleWord (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               WordAddress,
+  IN UINT32              WriteData
+  )
+{
+  EFI_STATUS  Status;
+  UINT32      StatusRegister;
+
+  Status = EFI_SUCCESS;
+
+  // Request a write single word command
+  SEND_NOR_COMMAND (WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);
+
+  // Store the word into NOR Flash;
+  MmioWrite32 (WordAddress, WriteData);
+
+  // Wait for the write to complete and then check for any errors; i.e. check the Status Register
+  do {
+    // Prepare to read the status register
+    StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress);
+    // The chip is busy while the WRITE bit is not asserted
+  } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
+
+  // Perform a full status check:
+  // Mask the relevant bits of Status Register.
+  // Everything should be zero, if not, we have a problem
+
+  if (StatusRegister & P30_SR_BIT_VPP) {
+    DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n", WordAddress));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (StatusRegister & P30_SR_BIT_PROGRAM) {
+    DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n", WordAddress));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
+    DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n", WordAddress));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (!EFI_ERROR (Status)) {
+    // Clear the Status Register
+    SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+  }
+
+  // Put device back into Read Array mode
+  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+  return Status;
+}
+
+/*
+ * Writes data to the NOR Flash using the Buffered Programming method.
+ *
+ * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
+ * Therefore this function will only handle buffers up to 32 words or 128 bytes.
+ * To deal with larger buffers, call this function again.
+ *
+ * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
+ * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
+ *
+ * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
+ * then programming time is doubled and power consumption is increased.
+ * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
+ * i.e. the last 4 bits of the target start address must be zero: 0x......00
+ */
+STATIC
+EFI_STATUS
+NorFlashWriteBuffer (
+  IN NOR_FLASH_INSTANCE  *Instance,
+  IN UINTN               TargetAddress,
+  IN UINTN               BufferSizeInBytes,
+  IN UINT32              *Buffer
+  )
+{
+  EFI_STATUS       Status;
+  UINTN            BufferSizeInWords;
+  UINTN            Count;
+  volatile UINT32  *Data;
+  UINTN            WaitForBuffer;
+  BOOLEAN          BufferAvailable;
+  UINT32           StatusRegister;
+
+  WaitForBuffer   = MAX_BUFFERED_PROG_ITERATIONS;
+  BufferAvailable = FALSE;
+
+  // Check that the target address does not cross a 32-word boundary.
+  if ((TargetAddress & BOUNDARY_OF_32_WORDS) != 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // Check there are some data to program
+  if (BufferSizeInBytes == 0) {
+    return EFI_BUFFER_TOO_SMALL;
+  }
+
+  // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
+  if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // Check that the buffer size is a multiple of 32-bit words
+  if ((BufferSizeInBytes % 4) != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // Pre-programming conditions checked, now start the algorithm.
+
+  // Prepare the data destination address
+  Data = (UINT32 *)TargetAddress;
+
+  // Check the availability of the buffer
+  do {
+    // Issue the Buffered Program Setup command
+    SEND_NOR_COMMAND (TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);
+
+    // Read back the status register bit#7 from the same address
+    if (((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE) {
+      BufferAvailable = TRUE;
+    }
+
+    // Update the loop counter
+    WaitForBuffer--;
+  } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE));
+
+  // The buffer was not available for writing
+  if (WaitForBuffer == 0) {
+    Status = EFI_DEVICE_ERROR;
+    goto EXIT;
+  }
+
+  // From now on we work in 32-bit words
+  BufferSizeInWords = BufferSizeInBytes / (UINTN)4;
+
+  // Write the word count, which is (buffer_size_in_words - 1),
+  // because word count 0 means one word.
+  SEND_NOR_COMMAND (TargetAddress, 0, (BufferSizeInWords - 1));
+
+  // Write the data to the NOR Flash, advancing each address by 4 bytes
+  for (Count = 0; Count < BufferSizeInWords; Count++, Data++, Buffer++) {
+    MmioWrite32 ((UINTN)Data, *Buffer);
+  }
+
+  // Issue the Buffered Program Confirm command, to start the programming operation
+  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
+
+  // Wait for the write to complete and then check for any errors; i.e. check the Status Register
+  do {
+    StatusRegister = NorFlashReadStatusRegister (Instance, TargetAddress);
+    // The chip is busy while the WRITE bit is not asserted
+  } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
+
+  // Perform a full status check:
+  // Mask the relevant bits of Status Register.
+  // Everything should be zero, if not, we have a problem
+
+  Status = EFI_SUCCESS;
+
+  if (StatusRegister & P30_SR_BIT_VPP) {
+    DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (StatusRegister & P30_SR_BIT_PROGRAM) {
+    DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
+    DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n", TargetAddress));
+    Status = EFI_DEVICE_ERROR;
+  }
+
+  if (!EFI_ERROR (Status)) {
+    // Clear the Status Register
+    SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+  }
+
+EXIT:
+  // Put device back into Read Array mode
+  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+  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_LBA     CurrentBlock;
+  UINT32      BlockSizeInWords;
+  UINT32      NumBlocks;
+  UINT32      BlockCount;
+
+  Status = EFI_SUCCESS;
+
+  // 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
+  pWriteBuffer = (UINT32 *)Buffer;
+
+  CurrentBlock = Lba;
+  for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = 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;
+}
+
+/**
+  Copy Length bytes from Source to Destination, using aligned accesses only.
+  Note that this implementation uses memcpy() semantics rather then memmove()
+  semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.
+
+  @param  DestinationBuffer The target of the copy request.
+  @param  SourceBuffer      The place to copy from.
+  @param  Length            The number of bytes to copy.
+
+  @return Destination
+
+**/
+STATIC
+VOID *
+AlignedCopyMem (
+  OUT     VOID        *DestinationBuffer,
+  IN      CONST VOID  *SourceBuffer,
+  IN      UINTN       Length
+  )
+{
+  UINT8         *Destination8;
+  CONST UINT8   *Source8;
+  UINT32        *Destination32;
+  CONST UINT32  *Source32;
+  UINT64        *Destination64;
+  CONST UINT64  *Source64;
+
+  if (BOTH_ALIGNED (DestinationBuffer, SourceBuffer, 8) && (Length >= 8)) {
+    Destination64 = DestinationBuffer;
+    Source64      = SourceBuffer;
+    while (Length >= 8) {
+      *Destination64++ = *Source64++;
+      Length          -= 8;
+    }
+
+    Destination8 = (UINT8 *)Destination64;
+    Source8      = (CONST UINT8 *)Source64;
+  } else if (BOTH_ALIGNED (DestinationBuffer, SourceBuffer, 4) && (Length >= 4)) {
+    Destination32 = DestinationBuffer;
+    Source32      = SourceBuffer;
+    while (Length >= 4) {
+      *Destination32++ = *Source32++;
+      Length          -= 4;
+    }
+
+    Destination8 = (UINT8 *)Destination32;
+    Source8      = (CONST UINT8 *)Source32;
+  } else {
+    Destination8 = DestinationBuffer;
+    Source8      = SourceBuffer;
+  }
+
+  while (Length-- != 0) {
+    *Destination8++ = *Source8++;
+  }
+
+  return DestinationBuffer;
+}
+
+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
+  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+  // Readout the data
+  AlignedCopyMem (Buffer, (VOID *)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
+  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+  // Readout the data
+  AlignedCopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
+
+  return EFI_SUCCESS;
+}
+
+/*
+  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;
+
+  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;
+}
+
+/**
+ * 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;
+
+  NorFlashLock (&OriginalTPL);
+
+  Index = 0;
+  // The block erase might fail a first time (SW bug ?). Retry it ...
+  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));
+  }
+
+  NorFlashUnlock (OriginalTPL);
+
+  return Status;
+}
+
+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       BufferIndex;
+  UINTN       BlockAddress;
+  UINTN       BuffersInBlock;
+  UINTN       RemainingWords;
+  EFI_TPL     OriginalTPL;
+  UINTN       Cnt;
+
+  Status = EFI_SUCCESS;
+
+  // 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;
+
+  NorFlashLock (&OriginalTPL);
+
+  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;
+  }
+
+  // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
+
+  // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
+  if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {
+    // First, break the entire block into buffer-sized chunks.
+    BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;
+
+    // Then feed each buffer chunk to the NOR Flash
+    // If a buffer does not contain any data, don't write it.
+    for (BufferIndex = 0;
+         BufferIndex < BuffersInBlock;
+         BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS
+         )
+    {
+      // Check the buffer to see if it contains any data (not set all 1s).
+      for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {
+        if (~DataBuffer[Cnt] != 0 ) {
+          // Some data found, write the buffer.
+          Status = NorFlashWriteBuffer (
+                     Instance,
+                     WordAddress,
+                     P30_MAX_BUFFER_SIZE_IN_BYTES,
+                     DataBuffer
+                     );
+          if (EFI_ERROR (Status)) {
+            goto EXIT;
+          }
+
+          break;
+        }
+      }
+    }
+
+    // Finally, finish off any remaining words that are less than the maximum size of the buffer
+    RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;
+
+    if (RemainingWords != 0) {
+      Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer);
+      if (EFI_ERROR (Status)) {
+        goto EXIT;
+      }
+    }
+  } else {
+    // For now, use the single word programming algorithm
+    // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
+    // i.e. which ends in the range 0x......01 - 0x......7F.
+    for (WordIndex = 0; WordIndex < BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {
+      Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
+      if (EFI_ERROR (Status)) {
+        goto EXIT;
+      }
+    }
+  }
+
+EXIT:
+  NorFlashUnlock (OriginalTPL);
+
+  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
+NorFlashReset (
+  IN  NOR_FLASH_INSTANCE  *Instance
+  )
+{
+  // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
+  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+  return EFI_SUCCESS;
+}
-- 
2.25.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#119323): https://edk2.groups.io/g/devel/message/119323
Mute This Topic: https://groups.io/mt/106365458/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  parent reply	other threads:[~2024-05-29  8:55 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-29  8:55 [edk2-devel] [edk2-platforms][PATCH V4 00/17] Split NorFlashDxe driver and add CadenceQspiNorFlashDeviceLib library Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 01/17] Platform/ARM/NorFlashDxe: Move DiskIo related functions out of NorFlash.c Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 02/17] Platform/ARM/NorFlashDxe: Move NorFlashVirtualNotifyEvent Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 03/17] Platform/ARM/NorFlashDxe: Add NorFlashCommon.h header file Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 04/17] Platform/ARM/NorFlashDxe: Move flash specific functions to NorFlash.c Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 05/17] Platform/ARM/NorFlashDxe: Remove unimplemented functions from NorFlash.h Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 06/17] Platform/ARM/NorFlashDxe: Make local functions STATIC Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 07/17] Platform/ARM: Create NorFlashDeviceLib library interface for flash specific functions Sahil Kaushal
2024-05-29  8:55 ` Sahil Kaushal [this message]
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 09/17] Platform/ARM/NorFlashDxe: Switch from NorFlash.c to NorFlashDeviceLib Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 10/17] Platform/ARM: Add HostControllerBaseAddress variable Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 11/17] Platform/ARM/NorFlashDxe: Fix memory leak in NorFlashCreateInstance() Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 12/17] Platform/ARM: Add optional provision to fetch and print NOR Flash info Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 13/17] Silicon/ARM/NeoverseN1Soc: Enable SCP QSPI flash region Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 14/17] Silicon/ARM/NeoverseN1Soc: NOR flash library for N1Sdp Sahil Kaushal
2024-05-29 11:42   ` Sami Mujawar
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 15/17] Platform/ARM: Add CadenceQspiNorFlashDeviceLib for NorFlashDxe Sahil Kaushal
2024-05-29 11:35   ` Sami Mujawar
2024-05-29 11:51     ` Sahil Kaushal
2024-05-29 12:38       ` Sami Mujawar
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 16/17] Platform/ARM/N1Sdp: Persistent storage for N1Sdp Sahil Kaushal
2024-05-29  8:55 ` [edk2-devel] [edk2-platforms][PATCH V4 17/17] Platform/ARM/N1Sdp: Enable FaultTolerantWrite Dxe driver " Sahil Kaushal
2024-05-29 15:27 ` [edk2-devel] [edk2-platforms][PATCH V4 00/17] Split NorFlashDxe driver and add CadenceQspiNorFlashDeviceLib library Sami Mujawar
2024-05-29 15:51 ` Sami Mujawar

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=20240529085517.1074417-9-Sahil.Kaushal@arm.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