Home | History | Annotate | Download | only in NorFlashDxe
      1 /** @file  NorFlashDxe.c
      2 
      3   Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
      4 
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <Library/UefiLib.h>
     16 #include <Library/BaseMemoryLib.h>
     17 #include <Library/MemoryAllocationLib.h>
     18 #include <Library/UefiBootServicesTableLib.h>
     19 #include <Library/PcdLib.h>
     20 
     21 #include "NorFlashDxe.h"
     22 
     23 STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent;
     24 
     25 //
     26 // Global variable declarations
     27 //
     28 NOR_FLASH_INSTANCE **mNorFlashInstances;
     29 UINT32               mNorFlashDeviceCount;
     30 
     31 NOR_FLASH_INSTANCE  mNorFlashInstanceTemplate = {
     32   NOR_FLASH_SIGNATURE, // Signature
     33   NULL, // Handle ... NEED TO BE FILLED
     34 
     35   FALSE, // Initialized
     36   NULL, // Initialize
     37 
     38   0, // DeviceBaseAddress ... NEED TO BE FILLED
     39   0, // RegionBaseAddress ... NEED TO BE FILLED
     40   0, // Size ... NEED TO BE FILLED
     41   0, // StartLba
     42 
     43   {
     44     EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision
     45     NULL, // Media ... NEED TO BE FILLED
     46     NorFlashBlockIoReset, // Reset;
     47     NorFlashBlockIoReadBlocks,          // ReadBlocks
     48     NorFlashBlockIoWriteBlocks,         // WriteBlocks
     49     NorFlashBlockIoFlushBlocks          // FlushBlocks
     50   }, // BlockIoProtocol
     51 
     52   {
     53     0, // MediaId ... NEED TO BE FILLED
     54     FALSE, // RemovableMedia
     55     TRUE, // MediaPresent
     56     FALSE, // LogicalPartition
     57     FALSE, // ReadOnly
     58     FALSE, // WriteCaching;
     59     0, // BlockSize ... NEED TO BE FILLED
     60     4, //  IoAlign
     61     0, // LastBlock ... NEED TO BE FILLED
     62     0, // LowestAlignedLba
     63     1, // LogicalBlocksPerPhysicalBlock
     64   }, //Media;
     65 
     66   {
     67     EFI_DISK_IO_PROTOCOL_REVISION, // Revision
     68     NorFlashDiskIoReadDisk,        // ReadDisk
     69     NorFlashDiskIoWriteDisk        // WriteDisk
     70   },
     71 
     72   FALSE, // SupportFvb ... NEED TO BE FILLED
     73   {
     74     FvbGetAttributes, // GetAttributes
     75     FvbSetAttributes, // SetAttributes
     76     FvbGetPhysicalAddress,  // GetPhysicalAddress
     77     FvbGetBlockSize,  // GetBlockSize
     78     FvbRead,  // Read
     79     FvbWrite, // Write
     80     FvbEraseBlocks, // EraseBlocks
     81     NULL, //ParentHandle
     82   }, //  FvbProtoccol;
     83   NULL, // ShadowBuffer
     84   {
     85     {
     86       {
     87         HARDWARE_DEVICE_PATH,
     88         HW_VENDOR_DP,
     89         { (UINT8)sizeof(VENDOR_DEVICE_PATH), (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8) }
     90       },
     91       { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }, // GUID ... NEED TO BE FILLED
     92     },
     93     {
     94       END_DEVICE_PATH_TYPE,
     95       END_ENTIRE_DEVICE_PATH_SUBTYPE,
     96       { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
     97     }
     98     } // DevicePath
     99 };
    100 
    101 EFI_STATUS
    102 NorFlashCreateInstance (
    103   IN UINTN                  NorFlashDeviceBase,
    104   IN UINTN                  NorFlashRegionBase,
    105   IN UINTN                  NorFlashSize,
    106   IN UINT32                 MediaId,
    107   IN UINT32                 BlockSize,
    108   IN BOOLEAN                SupportFvb,
    109   IN CONST GUID             *NorFlashGuid,
    110   OUT NOR_FLASH_INSTANCE**  NorFlashInstance
    111   )
    112 {
    113   EFI_STATUS Status;
    114   NOR_FLASH_INSTANCE* Instance;
    115 
    116   ASSERT(NorFlashInstance != NULL);
    117 
    118   Instance = AllocateRuntimeCopyPool (sizeof(NOR_FLASH_INSTANCE),&mNorFlashInstanceTemplate);
    119   if (Instance == NULL) {
    120     return EFI_OUT_OF_RESOURCES;
    121   }
    122 
    123   Instance->DeviceBaseAddress = NorFlashDeviceBase;
    124   Instance->RegionBaseAddress = NorFlashRegionBase;
    125   Instance->Size = NorFlashSize;
    126 
    127   Instance->BlockIoProtocol.Media = &Instance->Media;
    128   Instance->Media.MediaId = MediaId;
    129   Instance->Media.BlockSize = BlockSize;
    130   Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1;
    131 
    132   CopyGuid (&Instance->DevicePath.Vendor.Guid, NorFlashGuid);
    133 
    134   Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);;
    135   if (Instance->ShadowBuffer == NULL) {
    136     return EFI_OUT_OF_RESOURCES;
    137   }
    138 
    139   if (SupportFvb) {
    140     Instance->SupportFvb = TRUE;
    141     Instance->Initialize = NorFlashFvbInitialize;
    142 
    143     Status = gBS->InstallMultipleProtocolInterfaces (
    144                   &Instance->Handle,
    145                   &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
    146                   &gEfiBlockIoProtocolGuid,  &Instance->BlockIoProtocol,
    147                   &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol,
    148                   NULL
    149                   );
    150     if (EFI_ERROR(Status)) {
    151       FreePool (Instance);
    152       return Status;
    153     }
    154   } else {
    155     Instance->Initialized = TRUE;
    156 
    157     Status = gBS->InstallMultipleProtocolInterfaces (
    158                     &Instance->Handle,
    159                     &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
    160                     &gEfiBlockIoProtocolGuid,  &Instance->BlockIoProtocol,
    161                     &gEfiDiskIoProtocolGuid, &Instance->DiskIoProtocol,
    162                     NULL
    163                     );
    164     if (EFI_ERROR(Status)) {
    165       FreePool (Instance);
    166       return Status;
    167     }
    168   }
    169 
    170   *NorFlashInstance = Instance;
    171   return Status;
    172 }
    173 
    174 UINT32
    175 NorFlashReadStatusRegister (
    176   IN NOR_FLASH_INSTANCE     *Instance,
    177   IN UINTN                  SR_Address
    178   )
    179 {
    180   // Prepare to read the status register
    181   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);
    182   return MmioRead32 (Instance->DeviceBaseAddress);
    183 }
    184 
    185 STATIC
    186 BOOLEAN
    187 NorFlashBlockIsLocked (
    188   IN NOR_FLASH_INSTANCE     *Instance,
    189   IN UINTN                  BlockAddress
    190   )
    191 {
    192   UINT32                LockStatus;
    193 
    194   // Send command for reading device id
    195   SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
    196 
    197   // Read block lock status
    198   LockStatus = MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress, 2));
    199 
    200   // Decode block lock status
    201   LockStatus = FOLD_32BIT_INTO_16BIT(LockStatus);
    202 
    203   if ((LockStatus & 0x2) != 0) {
    204     DEBUG((EFI_D_ERROR, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
    205   }
    206 
    207   return ((LockStatus & 0x1) != 0);
    208 }
    209 
    210 STATIC
    211 EFI_STATUS
    212 NorFlashUnlockSingleBlock (
    213   IN NOR_FLASH_INSTANCE     *Instance,
    214   IN UINTN                  BlockAddress
    215   )
    216 {
    217   UINT32                LockStatus;
    218 
    219   // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
    220   // and to protect shared data structures.
    221 
    222   if (FeaturePcdGet (PcdNorFlashCheckBlockLocked) == TRUE) {
    223     do {
    224       // Request a lock setup
    225       SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
    226 
    227       // Request an unlock
    228       SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
    229 
    230       // Send command for reading device id
    231       SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
    232 
    233       // Read block lock status
    234       LockStatus = MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress, 2));
    235 
    236       // Decode block lock status
    237       LockStatus = FOLD_32BIT_INTO_16BIT(LockStatus);
    238     } while ((LockStatus & 0x1) == 1);
    239   } else {
    240     // Request a lock setup
    241     SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
    242 
    243     // Request an unlock
    244     SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
    245 
    246     // Wait until the status register gives us the all clear
    247     do {
    248       LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress);
    249     } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
    250   }
    251 
    252   // Put device back into Read Array mode
    253   SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);
    254 
    255   DEBUG((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress));
    256 
    257   return EFI_SUCCESS;
    258 }
    259 
    260 STATIC
    261 EFI_STATUS
    262 NorFlashUnlockSingleBlockIfNecessary (
    263   IN NOR_FLASH_INSTANCE     *Instance,
    264   IN UINTN                  BlockAddress
    265   )
    266 {
    267   EFI_STATUS Status;
    268 
    269   Status = EFI_SUCCESS;
    270 
    271   if (NorFlashBlockIsLocked (Instance, BlockAddress) == TRUE) {
    272     Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
    273   }
    274 
    275   return Status;
    276 }
    277 
    278 
    279 /**
    280  * The following function presumes that the block has already been unlocked.
    281  **/
    282 STATIC
    283 EFI_STATUS
    284 NorFlashEraseSingleBlock (
    285   IN NOR_FLASH_INSTANCE     *Instance,
    286   IN UINTN                  BlockAddress
    287   )
    288 {
    289   EFI_STATUS            Status;
    290   UINT32                StatusRegister;
    291 
    292   Status = EFI_SUCCESS;
    293 
    294   // Request a block erase and then confirm it
    295   SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);
    296   SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);
    297 
    298   // Wait until the status register gives us the all clear
    299   do {
    300     StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress);
    301   } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
    302 
    303   if (StatusRegister & P30_SR_BIT_VPP) {
    304     DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress));
    305     Status = EFI_DEVICE_ERROR;
    306   }
    307 
    308   if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) == (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) {
    309     DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress));
    310     Status = EFI_DEVICE_ERROR;
    311   }
    312 
    313   if (StatusRegister & P30_SR_BIT_ERASE) {
    314     DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister));
    315     Status = EFI_DEVICE_ERROR;
    316   }
    317 
    318   if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
    319     // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
    320     DEBUG((EFI_D_INFO,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress));
    321     Status = EFI_WRITE_PROTECTED;
    322   }
    323 
    324   if (EFI_ERROR(Status)) {
    325     // Clear the Status Register
    326     SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
    327   }
    328 
    329   // Put device back into Read Array mode
    330   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
    331 
    332   return Status;
    333 }
    334 
    335 /**
    336  * This function unlock and erase an entire NOR Flash block.
    337  **/
    338 EFI_STATUS
    339 NorFlashUnlockAndEraseSingleBlock (
    340   IN NOR_FLASH_INSTANCE     *Instance,
    341   IN UINTN                  BlockAddress
    342   )
    343 {
    344   EFI_STATUS      Status;
    345   UINTN           Index;
    346   EFI_TPL         OriginalTPL;
    347 
    348   if (!EfiAtRuntime ()) {
    349     // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
    350     OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
    351   } else {
    352     // This initialization is only to prevent the compiler to complain about the
    353     // use of uninitialized variables
    354     OriginalTPL = TPL_HIGH_LEVEL;
    355   }
    356 
    357   Index = 0;
    358   // The block erase might fail a first time (SW bug ?). Retry it ...
    359   do {
    360     // Unlock the block if we have to
    361     Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
    362     if (EFI_ERROR (Status)) {
    363       break;
    364     }
    365     Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
    366     Index++;
    367   } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
    368 
    369   if (Index == NOR_FLASH_ERASE_RETRY) {
    370     DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress,Index));
    371   }
    372 
    373   if (!EfiAtRuntime ()) {
    374     // Interruptions can resume.
    375     gBS->RestoreTPL (OriginalTPL);
    376   }
    377 
    378   return Status;
    379 }
    380 
    381 
    382 STATIC
    383 EFI_STATUS
    384 NorFlashWriteSingleWord (
    385   IN NOR_FLASH_INSTANCE     *Instance,
    386   IN UINTN                  WordAddress,
    387   IN UINT32                 WriteData
    388   )
    389 {
    390   EFI_STATUS            Status;
    391   UINT32                StatusRegister;
    392 
    393   Status = EFI_SUCCESS;
    394 
    395   // Request a write single word command
    396   SEND_NOR_COMMAND(WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);
    397 
    398   // Store the word into NOR Flash;
    399   MmioWrite32 (WordAddress, WriteData);
    400 
    401   // Wait for the write to complete and then check for any errors; i.e. check the Status Register
    402   do {
    403     // Prepare to read the status register
    404     StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress);
    405     // The chip is busy while the WRITE bit is not asserted
    406   } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
    407 
    408 
    409   // Perform a full status check:
    410   // Mask the relevant bits of Status Register.
    411   // Everything should be zero, if not, we have a problem
    412 
    413   if (StatusRegister & P30_SR_BIT_VPP) {
    414     DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n",WordAddress));
    415     Status = EFI_DEVICE_ERROR;
    416   }
    417 
    418   if (StatusRegister & P30_SR_BIT_PROGRAM) {
    419     DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n",WordAddress));
    420     Status = EFI_DEVICE_ERROR;
    421   }
    422 
    423   if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
    424     DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n",WordAddress));
    425     Status = EFI_DEVICE_ERROR;
    426   }
    427 
    428   if (!EFI_ERROR(Status)) {
    429     // Clear the Status Register
    430     SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
    431   }
    432 
    433   // Put device back into Read Array mode
    434   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
    435 
    436   return Status;
    437 }
    438 
    439 /*
    440  * Writes data to the NOR Flash using the Buffered Programming method.
    441  *
    442  * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
    443  * Therefore this function will only handle buffers up to 32 words or 128 bytes.
    444  * To deal with larger buffers, call this function again.
    445  *
    446  * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
    447  * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
    448  *
    449  * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
    450  * then programming time is doubled and power consumption is increased.
    451  * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
    452  * i.e. the last 4 bits of the target start address must be zero: 0x......00
    453  */
    454 EFI_STATUS
    455 NorFlashWriteBuffer (
    456   IN NOR_FLASH_INSTANCE     *Instance,
    457   IN UINTN                  TargetAddress,
    458   IN UINTN                  BufferSizeInBytes,
    459   IN UINT32                 *Buffer
    460   )
    461 {
    462   EFI_STATUS            Status;
    463   UINTN                 BufferSizeInWords;
    464   UINTN                 Count;
    465   volatile UINT32       *Data;
    466   UINTN                 WaitForBuffer;
    467   BOOLEAN               BufferAvailable;
    468   UINT32                StatusRegister;
    469 
    470   WaitForBuffer   = MAX_BUFFERED_PROG_ITERATIONS;
    471   BufferAvailable = FALSE;
    472 
    473   // Check that the target address does not cross a 32-word boundary.
    474   if ((TargetAddress & BOUNDARY_OF_32_WORDS) != 0) {
    475     return EFI_INVALID_PARAMETER;
    476   }
    477 
    478   // Check there are some data to program
    479   if (BufferSizeInBytes == 0) {
    480     return EFI_BUFFER_TOO_SMALL;
    481   }
    482 
    483   // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
    484   if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) {
    485     return EFI_BAD_BUFFER_SIZE;
    486   }
    487 
    488   // Check that the buffer size is a multiple of 32-bit words
    489   if ((BufferSizeInBytes % 4) != 0) {
    490     return EFI_BAD_BUFFER_SIZE;
    491   }
    492 
    493   // Pre-programming conditions checked, now start the algorithm.
    494 
    495   // Prepare the data destination address
    496   Data = (UINT32 *)TargetAddress;
    497 
    498   // Check the availability of the buffer
    499   do {
    500     // Issue the Buffered Program Setup command
    501     SEND_NOR_COMMAND(TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);
    502 
    503     // Read back the status register bit#7 from the same address
    504     if (((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE) {
    505       BufferAvailable = TRUE;
    506     }
    507 
    508     // Update the loop counter
    509     WaitForBuffer--;
    510 
    511   } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE));
    512 
    513   // The buffer was not available for writing
    514   if (WaitForBuffer == 0) {
    515     Status = EFI_DEVICE_ERROR;
    516     goto EXIT;
    517   }
    518 
    519   // From now on we work in 32-bit words
    520   BufferSizeInWords = BufferSizeInBytes / (UINTN)4;
    521 
    522   // Write the word count, which is (buffer_size_in_words - 1),
    523   // because word count 0 means one word.
    524   SEND_NOR_COMMAND(TargetAddress, 0, (BufferSizeInWords - 1));
    525 
    526   // Write the data to the NOR Flash, advancing each address by 4 bytes
    527   for(Count=0; Count < BufferSizeInWords; Count++, Data++, Buffer++) {
    528     MmioWrite32 ((UINTN)Data, *Buffer);
    529   }
    530 
    531   // Issue the Buffered Program Confirm command, to start the programming operation
    532   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
    533 
    534   // Wait for the write to complete and then check for any errors; i.e. check the Status Register
    535   do {
    536     StatusRegister = NorFlashReadStatusRegister (Instance, TargetAddress);
    537     // The chip is busy while the WRITE bit is not asserted
    538   } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
    539 
    540 
    541   // Perform a full status check:
    542   // Mask the relevant bits of Status Register.
    543   // Everything should be zero, if not, we have a problem
    544 
    545   Status          = EFI_SUCCESS;
    546 
    547   if (StatusRegister & P30_SR_BIT_VPP) {
    548     DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress));
    549     Status = EFI_DEVICE_ERROR;
    550   }
    551 
    552   if (StatusRegister & P30_SR_BIT_PROGRAM) {
    553     DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress));
    554     Status = EFI_DEVICE_ERROR;
    555   }
    556 
    557   if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
    558     DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n",TargetAddress));
    559     Status = EFI_DEVICE_ERROR;
    560   }
    561 
    562   if (!EFI_ERROR(Status)) {
    563     // Clear the Status Register
    564     SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
    565   }
    566 
    567 EXIT:
    568   // Put device back into Read Array mode
    569   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
    570 
    571   return Status;
    572 }
    573 
    574 STATIC
    575 EFI_STATUS
    576 NorFlashWriteFullBlock (
    577   IN NOR_FLASH_INSTANCE     *Instance,
    578   IN EFI_LBA                Lba,
    579   IN UINT32                 *DataBuffer,
    580   IN UINT32                 BlockSizeInWords
    581   )
    582 {
    583   EFI_STATUS    Status;
    584   UINTN         WordAddress;
    585   UINT32        WordIndex;
    586   UINTN         BufferIndex;
    587   UINTN         BlockAddress;
    588   UINTN         BuffersInBlock;
    589   UINTN         RemainingWords;
    590   EFI_TPL       OriginalTPL;
    591   UINTN         Cnt;
    592 
    593   Status = EFI_SUCCESS;
    594 
    595   // Get the physical address of the block
    596   BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4);
    597 
    598   // Start writing from the first address at the start of the block
    599   WordAddress = BlockAddress;
    600 
    601   if (!EfiAtRuntime ()) {
    602     // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
    603     OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
    604   } else {
    605     // This initialization is only to prevent the compiler to complain about the
    606     // use of uninitialized variables
    607     OriginalTPL = TPL_HIGH_LEVEL;
    608   }
    609 
    610   Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
    611   if (EFI_ERROR(Status)) {
    612     DEBUG((EFI_D_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));
    613     goto EXIT;
    614   }
    615 
    616   // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
    617 
    618   // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
    619   if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {
    620 
    621     // First, break the entire block into buffer-sized chunks.
    622     BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;
    623 
    624     // Then feed each buffer chunk to the NOR Flash
    625     // If a buffer does not contain any data, don't write it.
    626     for(BufferIndex=0;
    627          BufferIndex < BuffersInBlock;
    628          BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS
    629       ) {
    630       // Check the buffer to see if it contains any data (not set all 1s).
    631       for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {
    632         if (~DataBuffer[Cnt] != 0 ) {
    633           // Some data found, write the buffer.
    634           Status = NorFlashWriteBuffer (Instance, WordAddress, P30_MAX_BUFFER_SIZE_IN_BYTES,
    635                                         DataBuffer);
    636           if (EFI_ERROR(Status)) {
    637             goto EXIT;
    638           }
    639           break;
    640         }
    641       }
    642     }
    643 
    644     // Finally, finish off any remaining words that are less than the maximum size of the buffer
    645     RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;
    646 
    647     if(RemainingWords != 0) {
    648       Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer);
    649       if (EFI_ERROR(Status)) {
    650         goto EXIT;
    651       }
    652     }
    653 
    654   } else {
    655     // For now, use the single word programming algorithm
    656     // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
    657     // i.e. which ends in the range 0x......01 - 0x......7F.
    658     for(WordIndex=0; WordIndex<BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {
    659       Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
    660       if (EFI_ERROR(Status)) {
    661         goto EXIT;
    662       }
    663     }
    664   }
    665 
    666 EXIT:
    667   if (!EfiAtRuntime ()) {
    668     // Interruptions can resume.
    669     gBS->RestoreTPL (OriginalTPL);
    670   }
    671 
    672   if (EFI_ERROR(Status)) {
    673     DEBUG((EFI_D_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));
    674   }
    675   return Status;
    676 }
    677 
    678 
    679 EFI_STATUS
    680 NorFlashWriteBlocks (
    681   IN NOR_FLASH_INSTANCE     *Instance,
    682   IN EFI_LBA                Lba,
    683   IN UINTN                  BufferSizeInBytes,
    684   IN VOID                   *Buffer
    685   )
    686 {
    687   UINT32          *pWriteBuffer;
    688   EFI_STATUS      Status = EFI_SUCCESS;
    689   EFI_LBA         CurrentBlock;
    690   UINT32          BlockSizeInWords;
    691   UINT32          NumBlocks;
    692   UINT32          BlockCount;
    693 
    694   // The buffer must be valid
    695   if (Buffer == NULL) {
    696     return EFI_INVALID_PARAMETER;
    697   }
    698 
    699   if(Instance->Media.ReadOnly == TRUE) {
    700     return EFI_WRITE_PROTECTED;
    701   }
    702 
    703   // We must have some bytes to read
    704   DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes));
    705   if(BufferSizeInBytes == 0) {
    706     return EFI_BAD_BUFFER_SIZE;
    707   }
    708 
    709   // The size of the buffer must be a multiple of the block size
    710   DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance->Media.BlockSize));
    711   if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
    712     return EFI_BAD_BUFFER_SIZE;
    713   }
    714 
    715   // All blocks must be within the device
    716   NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
    717 
    718   DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->Media.LastBlock, Lba));
    719 
    720   if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
    721     DEBUG((EFI_D_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
    722     return EFI_INVALID_PARAMETER;
    723   }
    724 
    725   BlockSizeInWords = Instance->Media.BlockSize / 4;
    726 
    727   // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
    728   // to a proper data type, so use *ReadBuffer
    729   pWriteBuffer = (UINT32 *)Buffer;
    730 
    731   CurrentBlock = Lba;
    732   for (BlockCount=0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) {
    733 
    734     DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock));
    735 
    736     Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, BlockSizeInWords);
    737 
    738     if (EFI_ERROR(Status)) {
    739       break;
    740     }
    741   }
    742 
    743   DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
    744   return Status;
    745 }
    746 
    747 EFI_STATUS
    748 NorFlashReadBlocks (
    749   IN NOR_FLASH_INSTANCE   *Instance,
    750   IN EFI_LBA              Lba,
    751   IN UINTN                BufferSizeInBytes,
    752   OUT VOID                *Buffer
    753   )
    754 {
    755   UINT32              NumBlocks;
    756   UINTN               StartAddress;
    757 
    758   DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
    759       BufferSizeInBytes, Instance->Media.BlockSize, Instance->Media.LastBlock, Lba));
    760 
    761   // The buffer must be valid
    762   if (Buffer == NULL) {
    763     return EFI_INVALID_PARAMETER;
    764   }
    765 
    766   // Return if we have not any byte to read
    767   if (BufferSizeInBytes == 0) {
    768     return EFI_SUCCESS;
    769   }
    770 
    771   // The size of the buffer must be a multiple of the block size
    772   if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
    773     return EFI_BAD_BUFFER_SIZE;
    774   }
    775 
    776   // All blocks must be within the device
    777   NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
    778 
    779   if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
    780     DEBUG((EFI_D_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
    781     return EFI_INVALID_PARAMETER;
    782   }
    783 
    784   // Get the address to start reading from
    785   StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress,
    786                                         Lba,
    787                                         Instance->Media.BlockSize
    788                                        );
    789 
    790   // Put the device into Read Array mode
    791   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
    792 
    793   // Readout the data
    794   CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes);
    795 
    796   return EFI_SUCCESS;
    797 }
    798 
    799 EFI_STATUS
    800 NorFlashRead (
    801   IN NOR_FLASH_INSTANCE   *Instance,
    802   IN EFI_LBA              Lba,
    803   IN UINTN                Offset,
    804   IN UINTN                BufferSizeInBytes,
    805   OUT VOID                *Buffer
    806   )
    807 {
    808   UINTN  StartAddress;
    809 
    810   // The buffer must be valid
    811   if (Buffer == NULL) {
    812     return EFI_INVALID_PARAMETER;
    813   }
    814 
    815   // Return if we have not any byte to read
    816   if (BufferSizeInBytes == 0) {
    817     return EFI_SUCCESS;
    818   }
    819 
    820   if (((Lba * Instance->Media.BlockSize) + Offset + BufferSizeInBytes) > Instance->Size) {
    821     DEBUG ((EFI_D_ERROR, "NorFlashRead: ERROR - Read will exceed device size.\n"));
    822     return EFI_INVALID_PARAMETER;
    823   }
    824 
    825   // Get the address to start reading from
    826   StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress,
    827                                         Lba,
    828                                         Instance->Media.BlockSize
    829                                        );
    830 
    831   // Put the device into Read Array mode
    832   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
    833 
    834   // Readout the data
    835   CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes);
    836 
    837   return EFI_SUCCESS;
    838 }
    839 
    840 /*
    841   Write a full or portion of a block. It must not span block boundaries; that is,
    842   Offset + *NumBytes <= Instance->Media.BlockSize.
    843 */
    844 EFI_STATUS
    845 NorFlashWriteSingleBlock (
    846   IN        NOR_FLASH_INSTANCE   *Instance,
    847   IN        EFI_LBA               Lba,
    848   IN        UINTN                 Offset,
    849   IN OUT    UINTN                *NumBytes,
    850   IN        UINT8                *Buffer
    851   )
    852 {
    853   EFI_STATUS  TempStatus;
    854   UINT32      Tmp;
    855   UINT32      TmpBuf;
    856   UINT32      WordToWrite;
    857   UINT32      Mask;
    858   BOOLEAN     DoErase;
    859   UINTN       BytesToWrite;
    860   UINTN       CurOffset;
    861   UINTN       WordAddr;
    862   UINTN       BlockSize;
    863   UINTN       BlockAddress;
    864   UINTN       PrevBlockAddress;
    865 
    866   PrevBlockAddress = 0;
    867 
    868   if (!Instance->Initialized && Instance->Initialize) {
    869     Instance->Initialize(Instance);
    870   }
    871 
    872   DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));
    873 
    874   // Detect WriteDisabled state
    875   if (Instance->Media.ReadOnly == TRUE) {
    876     DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n"));
    877     // It is in WriteDisabled state, return an error right away
    878     return EFI_ACCESS_DENIED;
    879   }
    880 
    881   // Cache the block size to avoid de-referencing pointers all the time
    882   BlockSize = Instance->Media.BlockSize;
    883 
    884   // The write must not span block boundaries.
    885   // We need to check each variable individually because adding two large values together overflows.
    886   if ( ( Offset               >= BlockSize ) ||
    887        ( *NumBytes            >  BlockSize ) ||
    888        ( (Offset + *NumBytes) >  BlockSize )    ) {
    889     DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
    890     return EFI_BAD_BUFFER_SIZE;
    891   }
    892 
    893   // We must have some bytes to write
    894   if (*NumBytes == 0) {
    895     DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
    896     return EFI_BAD_BUFFER_SIZE;
    897   }
    898 
    899   // Pick 128bytes as a good start for word operations as opposed to erasing the
    900   // block and writing the data regardless if an erase is really needed.
    901   // It looks like most individual NV variable writes are smaller than 128bytes.
    902   if (*NumBytes <= 128) {
    903     // Check to see if we need to erase before programming the data into NOR.
    904     // If the destination bits are only changing from 1s to 0s we can just write.
    905     // After a block is erased all bits in the block is set to 1.
    906     // If any byte requires us to erase we just give up and rewrite all of it.
    907     DoErase      = FALSE;
    908     BytesToWrite = *NumBytes;
    909     CurOffset    = Offset;
    910 
    911     while (BytesToWrite > 0) {
    912       // Read full word from NOR, splice as required. A word is the smallest
    913       // unit we can write.
    914       TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof(Tmp), &Tmp);
    915       if (EFI_ERROR (TempStatus)) {
    916         return EFI_DEVICE_ERROR;
    917       }
    918 
    919       // Physical address of word in NOR to write.
    920       WordAddr = (CurOffset & ~(0x3)) + GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress,
    921                                                                Lba, BlockSize);
    922       // The word of data that is to be written.
    923       TmpBuf = *((UINT32*)(Buffer + (*NumBytes - BytesToWrite)));
    924 
    925       // First do word aligned chunks.
    926       if ((CurOffset & 0x3) == 0) {
    927         if (BytesToWrite >= 4) {
    928           // Is the destination still in 'erased' state?
    929           if (~Tmp != 0) {
    930             // Check to see if we are only changing bits to zero.
    931             if ((Tmp ^ TmpBuf) & TmpBuf) {
    932               DoErase = TRUE;
    933               break;
    934             }
    935           }
    936           // Write this word to NOR
    937           WordToWrite = TmpBuf;
    938           CurOffset += sizeof(TmpBuf);
    939           BytesToWrite -= sizeof(TmpBuf);
    940         } else {
    941           // BytesToWrite < 4. Do small writes and left-overs
    942           Mask = ~((~0) << (BytesToWrite * 8));
    943           // Mask out the bytes we want.
    944           TmpBuf &= Mask;
    945           // Is the destination still in 'erased' state?
    946           if ((Tmp & Mask) != Mask) {
    947             // Check to see if we are only changing bits to zero.
    948             if ((Tmp ^ TmpBuf) & TmpBuf) {
    949               DoErase = TRUE;
    950               break;
    951             }
    952           }
    953           // Merge old and new data. Write merged word to NOR
    954           WordToWrite = (Tmp & ~Mask) | TmpBuf;
    955           CurOffset += BytesToWrite;
    956           BytesToWrite = 0;
    957         }
    958       } else {
    959         // Do multiple words, but starting unaligned.
    960         if (BytesToWrite > (4 - (CurOffset & 0x3))) {
    961           Mask = ((~0) << ((CurOffset & 0x3) * 8));
    962           // Mask out the bytes we want.
    963           TmpBuf &= Mask;
    964           // Is the destination still in 'erased' state?
    965           if ((Tmp & Mask) != Mask) {
    966             // Check to see if we are only changing bits to zero.
    967             if ((Tmp ^ TmpBuf) & TmpBuf) {
    968               DoErase = TRUE;
    969               break;
    970             }
    971           }
    972           // Merge old and new data. Write merged word to NOR
    973           WordToWrite = (Tmp & ~Mask) | TmpBuf;
    974           BytesToWrite -= (4 - (CurOffset & 0x3));
    975           CurOffset += (4 - (CurOffset & 0x3));
    976         } else {
    977           // Unaligned and fits in one word.
    978           Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8);
    979           // Mask out the bytes we want.
    980           TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;
    981           // Is the destination still in 'erased' state?
    982           if ((Tmp & Mask) != Mask) {
    983             // Check to see if we are only changing bits to zero.
    984             if ((Tmp ^ TmpBuf) & TmpBuf) {
    985               DoErase = TRUE;
    986               break;
    987             }
    988           }
    989           // Merge old and new data. Write merged word to NOR
    990           WordToWrite = (Tmp & ~Mask) | TmpBuf;
    991           CurOffset += BytesToWrite;
    992           BytesToWrite = 0;
    993         }
    994       }
    995 
    996       //
    997       // Write the word to NOR.
    998       //
    999 
   1000       BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize);
   1001       if (BlockAddress != PrevBlockAddress) {
   1002         TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
   1003         if (EFI_ERROR (TempStatus)) {
   1004           return EFI_DEVICE_ERROR;
   1005         }
   1006         PrevBlockAddress = BlockAddress;
   1007       }
   1008       TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite);
   1009       if (EFI_ERROR (TempStatus)) {
   1010         return EFI_DEVICE_ERROR;
   1011       }
   1012     }
   1013     // Exit if we got here and could write all the data. Otherwise do the
   1014     // Erase-Write cycle.
   1015     if (!DoErase) {
   1016       return EFI_SUCCESS;
   1017     }
   1018   }
   1019 
   1020   // Check we did get some memory. Buffer is BlockSize.
   1021   if (Instance->ShadowBuffer == NULL) {
   1022     DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
   1023     return EFI_DEVICE_ERROR;
   1024   }
   1025 
   1026   // Read NOR Flash data into shadow buffer
   1027   TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);
   1028   if (EFI_ERROR (TempStatus)) {
   1029     // Return one of the pre-approved error statuses
   1030     return EFI_DEVICE_ERROR;
   1031   }
   1032 
   1033   // Put the data at the appropriate location inside the buffer area
   1034   CopyMem ((VOID*)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
   1035 
   1036   // Write the modified buffer back to the NorFlash
   1037   TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);
   1038   if (EFI_ERROR (TempStatus)) {
   1039     // Return one of the pre-approved error statuses
   1040     return EFI_DEVICE_ERROR;
   1041   }
   1042 
   1043   return EFI_SUCCESS;
   1044 }
   1045 
   1046 /*
   1047   Although DiskIoDxe will automatically install the DiskIO protocol whenever
   1048   we install the BlockIO protocol, its implementation is sub-optimal as it reads
   1049   and writes entire blocks using the BlockIO protocol. In fact we can access
   1050   NOR flash with a finer granularity than that, so we can improve performance
   1051   by directly producing the DiskIO protocol.
   1052 */
   1053 
   1054 /**
   1055   Read BufferSize bytes from Offset into Buffer.
   1056 
   1057   @param  This                  Protocol instance pointer.
   1058   @param  MediaId               Id of the media, changes every time the media is replaced.
   1059   @param  Offset                The starting byte offset to read from
   1060   @param  BufferSize            Size of Buffer
   1061   @param  Buffer                Buffer containing read data
   1062 
   1063   @retval EFI_SUCCESS           The data was read correctly from the device.
   1064   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
   1065   @retval EFI_NO_MEDIA          There is no media in the device.
   1066   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
   1067   @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
   1068                                 valid for the device.
   1069 
   1070 **/
   1071 EFI_STATUS
   1072 EFIAPI
   1073 NorFlashDiskIoReadDisk (
   1074   IN EFI_DISK_IO_PROTOCOL         *This,
   1075   IN UINT32                       MediaId,
   1076   IN UINT64                       DiskOffset,
   1077   IN UINTN                        BufferSize,
   1078   OUT VOID                        *Buffer
   1079   )
   1080 {
   1081   NOR_FLASH_INSTANCE *Instance;
   1082   UINT32              BlockSize;
   1083   UINT32              BlockOffset;
   1084   EFI_LBA             Lba;
   1085 
   1086   Instance = INSTANCE_FROM_DISKIO_THIS(This);
   1087 
   1088   if (MediaId != Instance->Media.MediaId) {
   1089     return EFI_MEDIA_CHANGED;
   1090   }
   1091 
   1092   BlockSize = Instance->Media.BlockSize;
   1093   Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
   1094 
   1095   return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer);
   1096 }
   1097 
   1098 /**
   1099   Writes a specified number of bytes to a device.
   1100 
   1101   @param  This       Indicates a pointer to the calling context.
   1102   @param  MediaId    ID of the medium to be written.
   1103   @param  Offset     The starting byte offset on the logical block I/O device to write.
   1104   @param  BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
   1105   @param  Buffer     A pointer to the buffer containing the data to be written.
   1106 
   1107   @retval EFI_SUCCESS           The data was written correctly to the device.
   1108   @retval EFI_WRITE_PROTECTED   The device can not be written to.
   1109   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
   1110   @retval EFI_NO_MEDIA          There is no media in the device.
   1111   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
   1112   @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
   1113                                  valid for the device.
   1114 
   1115 **/
   1116 EFI_STATUS
   1117 EFIAPI
   1118 NorFlashDiskIoWriteDisk (
   1119   IN EFI_DISK_IO_PROTOCOL         *This,
   1120   IN UINT32                       MediaId,
   1121   IN UINT64                       DiskOffset,
   1122   IN UINTN                        BufferSize,
   1123   IN VOID                         *Buffer
   1124   )
   1125 {
   1126   NOR_FLASH_INSTANCE *Instance;
   1127   UINT32              BlockSize;
   1128   UINT32              BlockOffset;
   1129   EFI_LBA             Lba;
   1130   UINTN               RemainingBytes;
   1131   UINTN               WriteSize;
   1132   EFI_STATUS          Status;
   1133 
   1134   Instance = INSTANCE_FROM_DISKIO_THIS(This);
   1135 
   1136   if (MediaId != Instance->Media.MediaId) {
   1137     return EFI_MEDIA_CHANGED;
   1138   }
   1139 
   1140   BlockSize = Instance->Media.BlockSize;
   1141   Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
   1142 
   1143   RemainingBytes = BufferSize;
   1144 
   1145   // Write either all the remaining bytes, or the number of bytes that bring
   1146   // us up to a block boundary, whichever is less.
   1147   // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next
   1148   // block boundary (even if it is already on one).
   1149   WriteSize = MIN (RemainingBytes, ((DiskOffset | (BlockSize - 1)) + 1) - DiskOffset);
   1150 
   1151   do {
   1152     if (WriteSize == BlockSize) {
   1153       // Write a full block
   1154       Status = NorFlashWriteFullBlock (Instance, Lba, Buffer, BlockSize / sizeof (UINT32));
   1155     } else {
   1156       // Write a partial block
   1157       Status = NorFlashWriteSingleBlock (Instance, Lba, BlockOffset, &WriteSize, Buffer);
   1158     }
   1159     if (EFI_ERROR (Status)) {
   1160       return Status;
   1161     }
   1162     // Now continue writing either all the remaining bytes or single blocks.
   1163     RemainingBytes -= WriteSize;
   1164     Buffer = (UINT8 *) Buffer + WriteSize;
   1165     Lba++;
   1166     BlockOffset = 0;
   1167     WriteSize = MIN (RemainingBytes, BlockSize);
   1168   } while (RemainingBytes);
   1169 
   1170   return Status;
   1171 }
   1172 
   1173 EFI_STATUS
   1174 NorFlashReset (
   1175   IN  NOR_FLASH_INSTANCE *Instance
   1176   )
   1177 {
   1178   // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
   1179   SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
   1180   return EFI_SUCCESS;
   1181 }
   1182 
   1183 /**
   1184   Fixup internal data so that EFI can be call in virtual mode.
   1185   Call the passed in Child Notify event and convert any pointers in
   1186   lib to virtual mode.
   1187 
   1188   @param[in]    Event   The Event that is being processed
   1189   @param[in]    Context Event Context
   1190 **/
   1191 VOID
   1192 EFIAPI
   1193 NorFlashVirtualNotifyEvent (
   1194   IN EFI_EVENT        Event,
   1195   IN VOID             *Context
   1196   )
   1197 {
   1198   UINTN Index;
   1199 
   1200   for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
   1201     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->DeviceBaseAddress);
   1202     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->RegionBaseAddress);
   1203 
   1204     // Convert BlockIo protocol
   1205     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks);
   1206     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks);
   1207     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.Reset);
   1208     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks);
   1209 
   1210     // Convert Fvb
   1211     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
   1212     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
   1213     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
   1214     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
   1215     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Read);
   1216     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
   1217     EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Write);
   1218 
   1219     if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
   1220       EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->ShadowBuffer);
   1221     }
   1222   }
   1223 
   1224   return;
   1225 }
   1226 
   1227 EFI_STATUS
   1228 EFIAPI
   1229 NorFlashInitialise (
   1230   IN EFI_HANDLE         ImageHandle,
   1231   IN EFI_SYSTEM_TABLE   *SystemTable
   1232   )
   1233 {
   1234   EFI_STATUS              Status;
   1235   UINT32                  Index;
   1236   NOR_FLASH_DESCRIPTION*  NorFlashDevices;
   1237   BOOLEAN                 ContainVariableStorage;
   1238 
   1239   Status = NorFlashPlatformInitialization ();
   1240   if (EFI_ERROR(Status)) {
   1241     DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to initialize Nor Flash devices\n"));
   1242     return Status;
   1243   }
   1244 
   1245   Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);
   1246   if (EFI_ERROR(Status)) {
   1247     DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to get Nor Flash devices\n"));
   1248     return Status;
   1249   }
   1250 
   1251   mNorFlashInstances = AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE*) * mNorFlashDeviceCount);
   1252 
   1253   for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
   1254     // Check if this NOR Flash device contain the variable storage region
   1255     ContainVariableStorage =
   1256         (NorFlashDevices[Index].RegionBaseAddress <= PcdGet32 (PcdFlashNvStorageVariableBase)) &&
   1257         (PcdGet32 (PcdFlashNvStorageVariableBase) + PcdGet32 (PcdFlashNvStorageVariableSize) <= NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
   1258 
   1259     Status = NorFlashCreateInstance (
   1260       NorFlashDevices[Index].DeviceBaseAddress,
   1261       NorFlashDevices[Index].RegionBaseAddress,
   1262       NorFlashDevices[Index].Size,
   1263       Index,
   1264       NorFlashDevices[Index].BlockSize,
   1265       ContainVariableStorage,
   1266       &NorFlashDevices[Index].Guid,
   1267       &mNorFlashInstances[Index]
   1268     );
   1269     if (EFI_ERROR(Status)) {
   1270       DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index));
   1271     }
   1272   }
   1273 
   1274   //
   1275   // Register for the virtual address change event
   1276   //
   1277   Status = gBS->CreateEventEx (
   1278                   EVT_NOTIFY_SIGNAL,
   1279                   TPL_NOTIFY,
   1280                   NorFlashVirtualNotifyEvent,
   1281                   NULL,
   1282                   &gEfiEventVirtualAddressChangeGuid,
   1283                   &mNorFlashVirtualAddrChangeEvent
   1284                   );
   1285   ASSERT_EFI_ERROR (Status);
   1286 
   1287   return Status;
   1288 }
   1289