1 /** @file NorFlashDxe.c
3 Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
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
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.
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>
21 #include "NorFlashDxe.h"
25 // Global variable declarations
27 NOR_FLASH_INSTANCE
**mNorFlashInstances
;
29 NOR_FLASH_INSTANCE mNorFlashInstanceTemplate
= {
30 NOR_FLASH_SIGNATURE
, // Signature
31 NULL
, // Handle ... NEED TO BE FILLED
36 0, // DeviceBaseAddress ... NEED TO BE FILLED
37 0, // RegionBaseAddress ... NEED TO BE FILLED
38 0, // Size ... NEED TO BE FILLED
42 EFI_BLOCK_IO_PROTOCOL_REVISION2
, // Revision
43 NULL
, // Media ... NEED TO BE FILLED
44 NorFlashBlockIoReset
, // Reset;
45 NorFlashBlockIoReadBlocks
, // ReadBlocks
46 NorFlashBlockIoWriteBlocks
, // WriteBlocks
47 NorFlashBlockIoFlushBlocks
// FlushBlocks
51 0, // MediaId ... NEED TO BE FILLED
52 FALSE
, // RemovableMedia
54 FALSE
, // LogicalPartition
56 FALSE
, // WriteCaching;
57 0, // BlockSize ... NEED TO BE FILLED
59 0, // LastBlock ... NEED TO BE FILLED
60 0, // LowestAlignedLba
61 1, // LogicalBlocksPerPhysicalBlock
64 FALSE
, // SupportFvb ... NEED TO BE FILLED
66 FvbGetAttributes
, // GetAttributes
67 FvbSetAttributes
, // SetAttributes
68 FvbGetPhysicalAddress
, // GetPhysicalAddress
69 FvbGetBlockSize
, // GetBlockSize
72 FvbEraseBlocks
, // EraseBlocks
81 (UINT8
)( sizeof(VENDOR_DEVICE_PATH
) ),
82 (UINT8
)((sizeof(VENDOR_DEVICE_PATH
)) >> 8),
84 { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, // GUID ... NEED TO BE FILLED
88 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
89 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
96 NorFlashCreateInstance (
97 IN UINTN NorFlashDeviceBase
,
98 IN UINTN NorFlashRegionBase
,
99 IN UINTN NorFlashSize
,
102 IN BOOLEAN SupportFvb
,
103 IN CONST GUID
*NorFlashGuid
,
104 OUT NOR_FLASH_INSTANCE
** NorFlashInstance
108 NOR_FLASH_INSTANCE
* Instance
;
110 ASSERT(NorFlashInstance
!= NULL
);
112 Instance
= AllocateRuntimeCopyPool (sizeof(NOR_FLASH_INSTANCE
),&mNorFlashInstanceTemplate
);
113 if (Instance
== NULL
) {
114 return EFI_OUT_OF_RESOURCES
;
117 Instance
->DeviceBaseAddress
= NorFlashDeviceBase
;
118 Instance
->RegionBaseAddress
= NorFlashRegionBase
;
119 Instance
->Size
= NorFlashSize
;
121 Instance
->BlockIoProtocol
.Media
= &Instance
->Media
;
122 Instance
->Media
.MediaId
= MediaId
;
123 Instance
->Media
.BlockSize
= BlockSize
;
124 Instance
->Media
.LastBlock
= (NorFlashSize
/ BlockSize
)-1;
126 CopyGuid (&Instance
->DevicePath
.Vendor
.Guid
, NorFlashGuid
);
129 Instance
->SupportFvb
= TRUE
;
130 Instance
->Initialize
= NorFlashFvbInitialize
;
131 Instance
->FvbBuffer
= AllocateRuntimePool (BlockSize
);;
132 if (Instance
->FvbBuffer
== NULL
) {
133 return EFI_OUT_OF_RESOURCES
;
136 Status
= gBS
->InstallMultipleProtocolInterfaces (
138 &gEfiDevicePathProtocolGuid
, &Instance
->DevicePath
,
139 &gEfiBlockIoProtocolGuid
, &Instance
->BlockIoProtocol
,
140 &gEfiFirmwareVolumeBlockProtocolGuid
, &Instance
->FvbProtocol
,
143 if (EFI_ERROR(Status
)) {
148 Instance
->Initialized
= TRUE
;
150 Status
= gBS
->InstallMultipleProtocolInterfaces (
152 &gEfiDevicePathProtocolGuid
, &Instance
->DevicePath
,
153 &gEfiBlockIoProtocolGuid
, &Instance
->BlockIoProtocol
,
156 if (EFI_ERROR(Status
)) {
162 *NorFlashInstance
= Instance
;
167 NorFlashReadStatusRegister (
168 IN NOR_FLASH_INSTANCE
*Instance
,
172 // Prepare to read the status register
173 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_STATUS_REGISTER
);
174 return MmioRead32 (Instance
->DeviceBaseAddress
);
179 NorFlashBlockIsLocked (
180 IN NOR_FLASH_INSTANCE
*Instance
,
181 IN UINTN BlockAddress
185 BOOLEAN BlockIsLocked
;
187 BlockIsLocked
= TRUE
;
189 // Send command for reading device id
190 SEND_NOR_COMMAND (BlockAddress
, 2, P30_CMD_READ_DEVICE_ID
);
192 // Read block lock status
193 LockStatus
= MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress
, 2));
195 // Decode block lock status
196 LockStatus
= FOLD_32BIT_INTO_16BIT(LockStatus
);
198 if ((LockStatus
& 0x2) != 0) {
199 DEBUG((EFI_D_ERROR
, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
202 if ((LockStatus
& 0x1) == 0) {
203 // This means the block is unlocked
204 DEBUG((DEBUG_BLKIO
, "UnlockSingleBlock: Block 0x%08x unlocked\n", BlockAddress
));
205 BlockIsLocked
= FALSE
;
208 return BlockIsLocked
;
213 NorFlashUnlockSingleBlock (
214 IN NOR_FLASH_INSTANCE
*Instance
,
215 IN UINTN BlockAddress
218 EFI_STATUS Status
= EFI_SUCCESS
;
221 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
222 // and to protect shared data structures.
224 if (FeaturePcdGet (PcdNorFlashCheckBlockLocked
) == TRUE
) {
226 // Request a lock setup
227 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
230 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
232 // Send command for reading device id
233 SEND_NOR_COMMAND (BlockAddress
, 2, P30_CMD_READ_DEVICE_ID
);
235 // Read block lock status
236 LockStatus
= MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress
, 2));
238 // Decode block lock status
239 LockStatus
= FOLD_32BIT_INTO_16BIT(LockStatus
);
240 } while ((LockStatus
& 0x1) == 1);
242 // Request a lock setup
243 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
246 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
248 // Wait until the status register gives us the all clear
250 LockStatus
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
251 } while ((LockStatus
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
254 // Put device back into Read Array mode
255 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_READ_ARRAY
);
257 DEBUG((DEBUG_BLKIO
, "UnlockSingleBlock: BlockAddress=0x%08x, Exit Status = \"%r\".\n", BlockAddress
, Status
));
264 NorFlashUnlockSingleBlockIfNecessary (
265 IN NOR_FLASH_INSTANCE
*Instance
,
266 IN UINTN BlockAddress
269 EFI_STATUS Status
= EFI_SUCCESS
;
271 if (NorFlashBlockIsLocked (Instance
, BlockAddress
) == TRUE
) {
272 Status
= NorFlashUnlockSingleBlock (Instance
, BlockAddress
);
280 * The following function presumes that the block has already been unlocked.
283 NorFlashEraseSingleBlock (
284 IN NOR_FLASH_INSTANCE
*Instance
,
285 IN UINTN BlockAddress
289 UINT32 StatusRegister
;
291 Status
= EFI_SUCCESS
;
293 // Request a block erase and then confirm it
294 SEND_NOR_COMMAND(BlockAddress
, 0, P30_CMD_BLOCK_ERASE_SETUP
);
295 SEND_NOR_COMMAND(BlockAddress
, 0, P30_CMD_BLOCK_ERASE_CONFIRM
);
297 // Wait until the status register gives us the all clear
299 StatusRegister
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
300 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
302 if (StatusRegister
& P30_SR_BIT_VPP
) {
303 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress
));
304 Status
= EFI_DEVICE_ERROR
;
307 if ((StatusRegister
& (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) == (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) {
308 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress
));
309 Status
= EFI_DEVICE_ERROR
;
312 if (StatusRegister
& P30_SR_BIT_ERASE
) {
313 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress
, StatusRegister
));
314 Status
= EFI_DEVICE_ERROR
;
317 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
318 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
319 DEBUG((EFI_D_INFO
,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress
));
320 Status
= EFI_WRITE_PROTECTED
;
323 if (EFI_ERROR(Status
)) {
324 // Clear the Status Register
325 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
328 // Put device back into Read Array mode
329 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
335 * The following function presumes that the block has already been unlocked.
338 NorFlashUnlockAndEraseSingleBlock (
339 IN NOR_FLASH_INSTANCE
*Instance
,
340 IN UINTN BlockAddress
347 if (!EfiAtRuntime ()) {
348 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
349 OriginalTPL
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
351 // This initialization is only to prevent the compiler to complain about the
352 // use of uninitialized variables
353 OriginalTPL
= TPL_HIGH_LEVEL
;
357 // The block erase might fail a first time (SW bug ?). Retry it ...
359 // Unlock the block if we have to
360 Status
= NorFlashUnlockSingleBlockIfNecessary (Instance
, BlockAddress
);
361 if (!EFI_ERROR(Status
)) {
362 Status
= NorFlashEraseSingleBlock (Instance
, BlockAddress
);
365 } while ((Index
< NOR_FLASH_ERASE_RETRY
) && (Status
== EFI_WRITE_PROTECTED
));
367 if (Index
== NOR_FLASH_ERASE_RETRY
) {
368 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress
,Index
));
371 if (!EfiAtRuntime ()) {
372 // Interruptions can resume.
373 gBS
->RestoreTPL (OriginalTPL
);
381 NorFlashWriteSingleWord (
382 IN NOR_FLASH_INSTANCE
*Instance
,
383 IN UINTN WordAddress
,
388 UINT32 StatusRegister
;
390 Status
= EFI_SUCCESS
;
392 // Request a write single word command
393 SEND_NOR_COMMAND(WordAddress
, 0, P30_CMD_WORD_PROGRAM_SETUP
);
395 // Store the word into NOR Flash;
396 MmioWrite32 (WordAddress
, WriteData
);
398 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
400 // Prepare to read the status register
401 StatusRegister
= NorFlashReadStatusRegister (Instance
, WordAddress
);
402 // The chip is busy while the WRITE bit is not asserted
403 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
406 // Perform a full status check:
407 // Mask the relevant bits of Status Register.
408 // Everything should be zero, if not, we have a problem
410 if (StatusRegister
& P30_SR_BIT_VPP
) {
411 DEBUG((EFI_D_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n",WordAddress
));
412 Status
= EFI_DEVICE_ERROR
;
415 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
416 DEBUG((EFI_D_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n",WordAddress
));
417 Status
= EFI_DEVICE_ERROR
;
420 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
421 DEBUG((EFI_D_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n",WordAddress
));
422 Status
= EFI_DEVICE_ERROR
;
425 if (!EFI_ERROR(Status
)) {
426 // Clear the Status Register
427 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
430 // Put device back into Read Array mode
431 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
437 * Writes data to the NOR Flash using the Buffered Programming method.
439 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
440 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
441 * To deal with larger buffers, call this function again.
443 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
444 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
446 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
447 * then programming time is doubled and power consumption is increased.
448 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
449 * i.e. the last 4 bits of the target start address must be zero: 0x......00
452 NorFlashWriteBuffer (
453 IN NOR_FLASH_INSTANCE
*Instance
,
454 IN UINTN TargetAddress
,
455 IN UINTN BufferSizeInBytes
,
460 UINTN BufferSizeInWords
;
462 volatile UINT32
*Data
;
464 BOOLEAN BufferAvailable
;
465 UINT32 StatusRegister
;
467 WaitForBuffer
= MAX_BUFFERED_PROG_ITERATIONS
;
468 BufferAvailable
= FALSE
;
470 // Check that the target address does not cross a 32-word boundary.
471 if ((TargetAddress
& BOUNDARY_OF_32_WORDS
) != 0) {
472 return EFI_INVALID_PARAMETER
;
475 // Check there are some data to program
476 if (BufferSizeInBytes
== 0) {
477 return EFI_BUFFER_TOO_SMALL
;
480 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
481 if (BufferSizeInBytes
> P30_MAX_BUFFER_SIZE_IN_BYTES
) {
482 return EFI_BAD_BUFFER_SIZE
;
485 // Check that the buffer size is a multiple of 32-bit words
486 if ((BufferSizeInBytes
% 4) != 0) {
487 return EFI_BAD_BUFFER_SIZE
;
490 // Pre-programming conditions checked, now start the algorithm.
492 // Prepare the data destination address
493 Data
= (UINT32
*)TargetAddress
;
495 // Check the availability of the buffer
497 // Issue the Buffered Program Setup command
498 SEND_NOR_COMMAND(TargetAddress
, 0, P30_CMD_BUFFERED_PROGRAM_SETUP
);
500 // Read back the status register bit#7 from the same address
501 if (((*Data
) & P30_SR_BIT_WRITE
) == P30_SR_BIT_WRITE
) {
502 BufferAvailable
= TRUE
;
505 // Update the loop counter
508 } while ((WaitForBuffer
> 0) && (BufferAvailable
== FALSE
));
510 // The buffer was not available for writing
511 if (WaitForBuffer
== 0) {
512 Status
= EFI_DEVICE_ERROR
;
516 // From now on we work in 32-bit words
517 BufferSizeInWords
= BufferSizeInBytes
/ (UINTN
)4;
519 // Write the word count, which is (buffer_size_in_words - 1),
520 // because word count 0 means one word.
521 SEND_NOR_COMMAND(TargetAddress
, 0, (BufferSizeInWords
- 1));
523 // Write the data to the NOR Flash, advancing each address by 4 bytes
524 for(Count
=0; Count
< BufferSizeInWords
; Count
++, Data
++, Buffer
++) {
528 // Issue the Buffered Program Confirm command, to start the programming operation
529 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM
);
531 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
533 StatusRegister
= NorFlashReadStatusRegister (Instance
, TargetAddress
);
534 // The chip is busy while the WRITE bit is not asserted
535 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
538 // Perform a full status check:
539 // Mask the relevant bits of Status Register.
540 // Everything should be zero, if not, we have a problem
542 Status
= EFI_SUCCESS
;
544 if (StatusRegister
& P30_SR_BIT_VPP
) {
545 DEBUG((EFI_D_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress
));
546 Status
= EFI_DEVICE_ERROR
;
549 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
550 DEBUG((EFI_D_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress
));
551 Status
= EFI_DEVICE_ERROR
;
554 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
555 DEBUG((EFI_D_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n",TargetAddress
));
556 Status
= EFI_DEVICE_ERROR
;
559 if (!EFI_ERROR(Status
)) {
560 // Clear the Status Register
561 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
565 // Put device back into Read Array mode
566 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
572 NorFlashWriteSingleBlock (
573 IN NOR_FLASH_INSTANCE
*Instance
,
575 IN UINT32
*DataBuffer
,
576 IN UINT32 BlockSizeInWords
584 UINTN BuffersInBlock
;
585 UINTN RemainingWords
;
588 Status
= EFI_SUCCESS
;
590 // Get the physical address of the block
591 BlockAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
, Lba
, BlockSizeInWords
* 4);
593 // Start writing from the first address at the start of the block
594 WordAddress
= BlockAddress
;
596 if (!EfiAtRuntime ()) {
597 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
598 OriginalTPL
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
600 // This initialization is only to prevent the compiler to complain about the
601 // use of uninitialized variables
602 OriginalTPL
= TPL_HIGH_LEVEL
;
605 Status
= NorFlashUnlockAndEraseSingleBlock (Instance
, BlockAddress
);
606 if (EFI_ERROR(Status
)) {
607 DEBUG((EFI_D_ERROR
, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress
));
611 // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
613 // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
614 if ((WordAddress
& BOUNDARY_OF_32_WORDS
) == 0x00) {
616 // First, break the entire block into buffer-sized chunks.
617 BuffersInBlock
= (UINTN
)(BlockSizeInWords
* 4) / P30_MAX_BUFFER_SIZE_IN_BYTES
;
619 // Then feed each buffer chunk to the NOR Flash
621 BufferIndex
< BuffersInBlock
;
622 BufferIndex
++, WordAddress
+= P30_MAX_BUFFER_SIZE_IN_BYTES
, DataBuffer
+= P30_MAX_BUFFER_SIZE_IN_WORDS
624 Status
= NorFlashWriteBuffer (Instance
, WordAddress
, P30_MAX_BUFFER_SIZE_IN_BYTES
, DataBuffer
);
625 if (EFI_ERROR(Status
)) {
630 // Finally, finish off any remaining words that are less than the maximum size of the buffer
631 RemainingWords
= BlockSizeInWords
% P30_MAX_BUFFER_SIZE_IN_WORDS
;
633 if(RemainingWords
!= 0) {
634 Status
= NorFlashWriteBuffer (Instance
, WordAddress
, (RemainingWords
* 4), DataBuffer
);
635 if (EFI_ERROR(Status
)) {
641 // For now, use the single word programming algorithm
642 // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
643 // i.e. which ends in the range 0x......01 - 0x......7F.
644 for(WordIndex
=0; WordIndex
<BlockSizeInWords
; WordIndex
++, DataBuffer
++, WordAddress
= WordAddress
+ 4) {
645 Status
= NorFlashWriteSingleWord (Instance
, WordAddress
, *DataBuffer
);
646 if (EFI_ERROR(Status
)) {
653 if (!EfiAtRuntime ()) {
654 // Interruptions can resume.
655 gBS
->RestoreTPL (OriginalTPL
);
658 if (EFI_ERROR(Status
)) {
659 DEBUG((EFI_D_ERROR
, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress
, Status
));
666 NorFlashWriteBlocks (
667 IN NOR_FLASH_INSTANCE
*Instance
,
669 IN UINTN BufferSizeInBytes
,
673 UINT32
*pWriteBuffer
;
674 EFI_STATUS Status
= EFI_SUCCESS
;
675 EFI_LBA CurrentBlock
;
676 UINT32 BlockSizeInWords
;
680 // The buffer must be valid
681 if (Buffer
== NULL
) {
682 return EFI_INVALID_PARAMETER
;
685 if(Instance
->Media
.ReadOnly
== TRUE
) {
686 return EFI_WRITE_PROTECTED
;
689 // We must have some bytes to read
690 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes
));
691 if(BufferSizeInBytes
== 0) {
692 return EFI_BAD_BUFFER_SIZE
;
695 // The size of the buffer must be a multiple of the block size
696 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance
->Media
.BlockSize
));
697 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
698 return EFI_BAD_BUFFER_SIZE
;
701 // All blocks must be within the device
702 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
704 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks
, Instance
->Media
.LastBlock
, Lba
));
706 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
707 DEBUG((EFI_D_ERROR
, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
708 return EFI_INVALID_PARAMETER
;
711 BlockSizeInWords
= Instance
->Media
.BlockSize
/ 4;
713 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
714 // to a proper data type, so use *ReadBuffer
715 pWriteBuffer
= (UINT32
*)Buffer
;
718 for (BlockCount
=0; BlockCount
< NumBlocks
; BlockCount
++, CurrentBlock
++, pWriteBuffer
= pWriteBuffer
+ BlockSizeInWords
) {
720 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN
)CurrentBlock
));
722 Status
= NorFlashWriteSingleBlock (Instance
, CurrentBlock
, pWriteBuffer
, BlockSizeInWords
);
724 if (EFI_ERROR(Status
)) {
729 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status
));
735 IN NOR_FLASH_INSTANCE
*Instance
,
737 IN UINTN BufferSizeInBytes
,
744 DEBUG((DEBUG_BLKIO
, "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
745 BufferSizeInBytes
, Instance
->Media
.BlockSize
, Instance
->Media
.LastBlock
, Lba
));
747 // The buffer must be valid
748 if (Buffer
== NULL
) {
749 return EFI_INVALID_PARAMETER
;
752 // Return if we have not any byte to read
753 if (BufferSizeInBytes
== 0) {
757 // The size of the buffer must be a multiple of the block size
758 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
759 return EFI_BAD_BUFFER_SIZE
;
762 // All blocks must be within the device
763 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
765 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
766 DEBUG((EFI_D_ERROR
, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
767 return EFI_INVALID_PARAMETER
;
770 // Get the address to start reading from
771 StartAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
,
773 Instance
->Media
.BlockSize
776 // Put the device into Read Array mode
777 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
780 CopyMem(Buffer
, (UINTN
*)StartAddress
, BufferSizeInBytes
);
787 IN NOR_FLASH_INSTANCE
*Instance
790 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
791 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
798 IN EFI_HANDLE ImageHandle
,
799 IN EFI_SYSTEM_TABLE
*SystemTable
804 NOR_FLASH_DESCRIPTION
* NorFlashDevices
;
805 UINT32 NorFlashDeviceCount
;
806 BOOLEAN ContainVariableStorage
;
808 Status
= NorFlashPlatformInitialization ();
809 if (EFI_ERROR(Status
)) {
810 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to initialize Nor Flash devices\n"));
814 Status
= NorFlashPlatformGetDevices (&NorFlashDevices
,&NorFlashDeviceCount
);
815 if (EFI_ERROR(Status
)) {
816 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to get Nor Flash devices\n"));
820 mNorFlashInstances
= AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE
*) * NorFlashDeviceCount
);
822 for (Index
= 0; Index
< NorFlashDeviceCount
; Index
++) {
823 // Check if this NOR Flash device contain the variable storage region
824 ContainVariableStorage
=
825 (NorFlashDevices
[Index
].RegionBaseAddress
<= PcdGet32 (PcdFlashNvStorageVariableBase
)) &&
826 (PcdGet32 (PcdFlashNvStorageVariableBase
) + PcdGet32 (PcdFlashNvStorageVariableSize
) <= NorFlashDevices
[Index
].RegionBaseAddress
+ NorFlashDevices
[Index
].Size
);
828 Status
= NorFlashCreateInstance (
829 NorFlashDevices
[Index
].DeviceBaseAddress
,
830 NorFlashDevices
[Index
].RegionBaseAddress
,
831 NorFlashDevices
[Index
].Size
,
833 NorFlashDevices
[Index
].BlockSize
,
834 ContainVariableStorage
,
835 &NorFlashDevices
[Index
].Guid
,
836 &mNorFlashInstances
[Index
]
838 if (EFI_ERROR(Status
)) {
839 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index
));