1 /** @file NorFlashDxe.c
3 Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 #include <Library/UefiLib.h>
15 #include <Library/DebugLib.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
28 #define NOR_FLASH_LAST_DEVICE 4
30 NOR_FLASH_DESCRIPTION mNorFlashDescription
[NOR_FLASH_LAST_DEVICE
] = {
35 {0xE7223039, 0x5836, 0x41E1, 0xB5, 0x42, 0xD7, 0xEC, 0x73, 0x6C, 0x5E, 0x59}
37 { // BootMon non-volatile storage
38 ARM_VE_SMB_NOR0_BASE
+ SIZE_256KB
* 255,
41 {0x02118005, 0x9DA7, 0x443A, 0x92, 0xD5, 0x78, 0x1F, 0x02, 0x2A, 0xED, 0xBB}
47 {0x1F15DA3C, 0x37FF, 0x4070, 0xB4, 0x71, 0xBB, 0x4A, 0xF1, 0x2A, 0x72, 0x4A}
49 { // UEFI Variable Services non-volatile storage
50 ARM_VE_SMB_NOR1_BASE
+ SIZE_256KB
* 255,
51 SIZE_64KB
* 3, //FIXME: Set 3 blocks because I did not succeed to copy 4 blocks into the ARM Versastile Express NOR Falsh in the last NOR Flash. It should be 4 blocks
53 {0xCC2CBF29, 0x1498, 0x4CDD, 0x81, 0x71, 0xF8, 0xB6, 0xB4, 0x1D, 0x09, 0x09}
57 NOR_FLASH_INSTANCE
*mNorFlashInstances
[ NOR_FLASH_LAST_DEVICE
];
59 NOR_FLASH_INSTANCE mNorFlashInstanceTemplate
= {
60 NOR_FLASH_SIGNATURE
, // Signature
61 NULL
, // Handle ... NEED TO BE FILLED
66 0, // BaseAddress ... NEED TO BE FILLED
67 0, // Size ... NEED TO BE FILLED
70 EFI_BLOCK_IO_PROTOCOL_REVISION2
, // Revision
71 NULL
, // Media ... NEED TO BE FILLED
72 NorFlashBlockIoReset
, // Reset;
73 NorFlashBlockIoReadBlocks
, // ReadBlocks
74 NorFlashBlockIoWriteBlocks
, // WriteBlocks
75 NorFlashBlockIoFlushBlocks
// FlushBlocks
79 0, // MediaId ... NEED TO BE FILLED
80 FALSE
, // RemovableMedia
82 FALSE
, // LogicalPartition
84 FALSE
, // WriteCaching;
85 0, // BlockSize ... NEED TO BE FILLED
87 0, // LastBlock ... NEED TO BE FILLED
88 0, // LowestAlignedLba
89 1, // LogicalBlocksPerPhysicalBlock
92 FALSE
, // SupportFvb ... NEED TO BE FILLED
94 FvbGetAttributes
, // GetAttributes
95 FvbSetAttributes
, // SetAttributes
96 FvbGetPhysicalAddress
, // GetPhysicalAddress
97 FvbGetBlockSize
, // GetBlockSize
100 FvbEraseBlocks
, // EraseBlocks
107 HARDWARE_DEVICE_PATH
,
109 (UINT8
)( sizeof(VENDOR_DEVICE_PATH
) ),
110 (UINT8
)((sizeof(VENDOR_DEVICE_PATH
)) >> 8),
112 { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, // GUID ... NEED TO BE FILLED
115 END_DEVICE_PATH_TYPE
,
116 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
117 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
123 EFI_STATUS
NorFlashCreateInstance(
124 IN UINTN NorFlashBase
,
125 IN UINTN NorFlashSize
,
128 IN BOOLEAN SupportFvb
,
129 IN CONST GUID
*NorFlashGuid
,
130 OUT NOR_FLASH_INSTANCE
** NorFlashInstance
133 NOR_FLASH_INSTANCE
* Instance
;
135 ASSERT(NorFlashInstance
!= NULL
);
137 Instance
= AllocateCopyPool (sizeof(NOR_FLASH_INSTANCE
),&mNorFlashInstanceTemplate
);
138 if (Instance
== NULL
) {
139 return EFI_OUT_OF_RESOURCES
;
142 Instance
->BaseAddress
= NorFlashBase
;
143 Instance
->Size
= NorFlashSize
;
145 Instance
->BlockIoProtocol
.Media
= &Instance
->Media
;
146 Instance
->Media
.MediaId
= MediaId
;
147 Instance
->Media
.BlockSize
= BlockSize
;
148 Instance
->Media
.LastBlock
= (NorFlashSize
/ BlockSize
)-1;
150 CopyGuid (&Instance
->DevicePath
.Vendor
.Guid
,NorFlashGuid
);
153 Instance
->SupportFvb
= TRUE
;
154 Instance
->Initialize
= NorFlashFvbInitialize
;
156 Status
= gBS
->InstallMultipleProtocolInterfaces (
158 &gEfiDevicePathProtocolGuid
, &Instance
->DevicePath
,
159 //&gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
160 &gEfiFirmwareVolumeBlockProtocolGuid
, &Instance
->FvbProtocol
,
163 if (EFI_ERROR(Status
)) {
168 Instance
->Initialize
= NorFlashBlkIoInitialize
;
170 Status
= gBS
->InstallMultipleProtocolInterfaces (
172 &gEfiDevicePathProtocolGuid
, &Instance
->DevicePath
,
173 &gEfiBlockIoProtocolGuid
, &Instance
->BlockIoProtocol
,
176 if (EFI_ERROR(Status
)) {
182 *NorFlashInstance
= Instance
;
187 NorFlashReadCfiData (
188 IN UINTN BaseAddress
,
190 IN UINT32 NumberOfBytes
,
195 volatile UINTN
*ReadAddress
;
199 UINT32 CombinedData
= 0;
200 EFI_STATUS Status
= EFI_SUCCESS
;
203 if( NumberOfBytes
> 4 ) {
204 // Using 32 bit variable so can only read 4 bytes
205 return EFI_INVALID_PARAMETER
;
208 // First combine the base address with the offset address
209 // to create an absolute read address.
210 // However, because we are in little endian, read from the last address down to the first
211 ReadAddress
= CREATE_NOR_ADDRESS( BaseAddress
, CFI_Offset
) + NumberOfBytes
- 1;
213 // Although each read returns 32 bits, because of the NOR Flash structure,
214 // each 16 bits (16 MSB and 16 LSB) come from two different chips.
215 // When in CFI mode, each chip read returns valid data in only the 8 LSBits;
216 // the 8 MSBits are invalid and can be ignored.
217 // Therefore, each read address returns one byte from each chip.
219 // Also note: As we are in little endian notation and we are reading
220 // bytes from incremental addresses, we should assemble them in little endian order.
221 for( CurrentByte
=0; CurrentByte
<NumberOfBytes
; CurrentByte
++ ) {
223 // Read the bytes from the two chips
224 ReadData
= *ReadAddress
;
226 // Check the data validity:
227 // The 'Dual Data' function means that
228 // each chip should return identical data.
229 // If that is not the case then we have a problem.
230 Byte1
= GET_LOW_BYTE ( ReadData
);
231 Byte2
= GET_HIGH_BYTE( ReadData
);
233 if( Byte1
!= Byte2
) {
234 // The two bytes should have been identical
235 return EFI_DEVICE_ERROR
;
238 // Each successive iteration of the 'for' loop reads a lower address.
239 // As we read lower addresses and as we use little endian,
240 // we read lower significance bytes. So combine them in the correct order.
241 CombinedData
= (CombinedData
<< 8) | Byte1
;
243 // Decrement down to the next address
248 *Data
= CombinedData
;
254 NorFlashReadStatusRegister(
258 volatile UINT32
*pStatusRegister
;
259 UINT32 StatusRegister
;
261 EFI_STATUS Status
= EFI_SUCCESS
;
263 // Prepare the read address
264 pStatusRegister
= (UINT32
*) SR_Address
;
267 // Prepare to read the status register
268 SEND_NOR_COMMAND( SR_Address
, 0, P30_CMD_READ_STATUS_REGISTER
);
269 // Snapshot the status register
270 StatusRegister
= *pStatusRegister
;
272 // The chip is busy while the WRITE bit is not asserted
273 while ( (StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
276 // Perform a full status check:
277 // Mask the relevant bits of Status Register.
278 // Everything should be zero, if not, we have a problem
280 // Prepare the Error Mask by setting bits 5, 4, 3, 1
281 ErrorMask
= P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
| P30_SR_BIT_VPP
| P30_SR_BIT_BLOCK_LOCKED
;
283 if ( (StatusRegister
& ErrorMask
) != 0 ) {
284 if ( (StatusRegister
& P30_SR_BIT_VPP
) != 0 ) {
285 DEBUG((EFI_D_ERROR
,"NorFlashReadStatusRegister: VPP Range Error\n"));
286 } else if ( (StatusRegister
& (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
) ) != 0 ) {
287 DEBUG((EFI_D_ERROR
,"NorFlashReadStatusRegister: Command Sequence Error\n"));
288 } else if ( (StatusRegister
& P30_SR_BIT_PROGRAM
) != 0 ) {
289 DEBUG((EFI_D_ERROR
,"NorFlashReadStatusRegister: Program Error\n"));
290 } else if ( (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) != 0 ) {
291 DEBUG((EFI_D_ERROR
,"NorFlashReadStatusRegister: Device Protect Error\n"));
293 DEBUG((EFI_D_ERROR
,"NorFlashReadStatusRegister: Error (0x%X)\n",Status
));
296 // If an error is detected we must clear the Status Register
297 SEND_NOR_COMMAND( SR_Address
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
298 Status
= EFI_DEVICE_ERROR
;
301 SEND_NOR_COMMAND( SR_Address
, 0, P30_CMD_READ_ARRAY
);
308 NorFlashBlockIsLocked(
309 IN UINTN BlockAddress
312 volatile UINT32
*pReadData
;
314 BOOLEAN BlockIsLocked
= TRUE
;
316 // Prepare the read address
317 pReadData
= (UINT32
*) CREATE_NOR_ADDRESS( BlockAddress
, 2 );
319 // Send command for reading device id
320 SEND_NOR_COMMAND( BlockAddress
, 2, P30_CMD_READ_DEVICE_ID
);
322 // Read block lock status
323 LockStatus
= *pReadData
;
325 // Decode block lock status
326 LockStatus
= FOLD_32BIT_INTO_16BIT(LockStatus
);
328 if( (LockStatus
& 0x2) != 0 ) {
329 DEBUG((EFI_D_ERROR
, "UnlockSingleBlock: WARNING: Block LOCKED DOWN\n"));
332 if( (LockStatus
& 0x1) == 0 ) {
333 // This means the block is unlocked
334 DEBUG((DEBUG_BLKIO
, "UnlockSingleBlock: Block 0x%08x unlocked\n", BlockAddress
));
335 BlockIsLocked
= FALSE
;
338 return BlockIsLocked
;
343 NorFlashUnlockSingleBlock(
344 IN UINTN BlockAddress
347 EFI_STATUS Status
= EFI_SUCCESS
;
349 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
350 // and to protect shared data structures.
352 //while( NorFlashBlockIsLocked( BlockAddress ) )
354 // Request a lock setup
355 SEND_NOR_COMMAND( BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
358 SEND_NOR_COMMAND( BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
361 // Put device back into Read Array mode
362 SEND_NOR_COMMAND( BlockAddress
, 0, P30_CMD_READ_ARRAY
);
364 DEBUG((DEBUG_BLKIO
, "UnlockSingleBlock: BlockAddress=0x%08x, Exit Status = \"%r\".\n", BlockAddress
, Status
));
371 NorFlashUnlockSingleBlockIfNecessary(
372 IN UINTN BlockAddress
375 EFI_STATUS Status
= EFI_SUCCESS
;
377 if ( NorFlashBlockIsLocked( BlockAddress
) == TRUE
) {
378 Status
= NorFlashUnlockSingleBlock( BlockAddress
);
386 * The following function presumes that the block has already been unlocked.
389 NorFlashEraseSingleBlock(
390 IN UINTN BlockAddress
393 EFI_STATUS Status
= EFI_SUCCESS
;
395 // Request a block erase and then confirm it
396 SEND_NOR_COMMAND( BlockAddress
, 0, P30_CMD_BLOCK_ERASE_SETUP
);
397 SEND_NOR_COMMAND( BlockAddress
, 0, P30_CMD_BLOCK_ERASE_CONFIRM
);
398 // Wait until the status register gives us the all clear
399 Status
= NorFlashReadStatusRegister( BlockAddress
);
401 if (EFI_ERROR(Status
)) {
402 DEBUG((DEBUG_BLKIO
, "EraseSingleBlock(BlockAddress=0x%08x) = '%r'\n", BlockAddress
, Status
));
408 * The following function presumes that the block has already been unlocked.
411 NorFlashUnlockAndEraseSingleBlock(
412 IN UINTN BlockAddress
417 // Unlock the block if we have to
418 Status
= NorFlashUnlockSingleBlockIfNecessary( BlockAddress
);
419 if (!EFI_ERROR(Status
)) {
420 Status
= NorFlashEraseSingleBlock( BlockAddress
);
428 NorFlashWriteSingleWord (
429 IN UINTN WordAddress
,
434 volatile UINT32
*Data
;
436 // Prepare the read address
437 Data
= (UINT32
*)WordAddress
;
439 // Request a write single word command
440 SEND_NOR_COMMAND( WordAddress
, 0, P30_CMD_WORD_PROGRAM_SETUP
);
442 // Store the word into NOR Flash;
445 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
446 Status
= NorFlashReadStatusRegister( WordAddress
);
452 * Writes data to the NOR Flash using the Buffered Programming method.
454 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
455 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
456 * To deal with larger buffers, call this function again.
458 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
459 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
461 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
462 * then programming time is doubled and power consumption is increased.
463 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
464 * i.e. the last 4 bits of the target start address must be zero: 0x......00
467 NorFlashWriteBuffer (
468 IN UINTN TargetAddress
,
469 IN UINTN BufferSizeInBytes
,
474 UINTN BufferSizeInWords
;
476 volatile UINT32
*Data
;
477 UINTN WaitForBuffer
= MAX_BUFFERED_PROG_ITERATIONS
;
478 BOOLEAN BufferAvailable
= FALSE
;
481 // Check that the target address does not cross a 32-word boundary.
482 if ( (TargetAddress
& BOUNDARY_OF_32_WORDS
) != 0 ) {
483 return EFI_INVALID_PARAMETER
;
486 // Check there are some data to program
487 if ( BufferSizeInBytes
== 0 ) {
488 return EFI_BUFFER_TOO_SMALL
;
491 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
492 if ( BufferSizeInBytes
> P30_MAX_BUFFER_SIZE_IN_BYTES
) {
493 return EFI_BAD_BUFFER_SIZE
;
496 // Check that the buffer size is a multiple of 32-bit words
497 if ( (BufferSizeInBytes
% 4) != 0 ) {
498 return EFI_BAD_BUFFER_SIZE
;
501 // Pre-programming conditions checked, now start the algorithm.
503 // Prepare the data destination address
504 Data
= (UINT32
*)TargetAddress
;
506 // Check the availability of the buffer
508 // Issue the Buffered Program Setup command
509 SEND_NOR_COMMAND( TargetAddress
, 0, P30_CMD_BUFFERED_PROGRAM_SETUP
);
511 // Read back the status register bit#7 from the same address
512 if ( ((*Data
) & P30_SR_BIT_WRITE
) == P30_SR_BIT_WRITE
) {
513 BufferAvailable
= TRUE
;
516 // Update the loop counter
519 } while (( WaitForBuffer
> 0 ) && ( BufferAvailable
== FALSE
));
521 // The buffer was not available for writing
522 if ( WaitForBuffer
== 0 ) {
523 return EFI_DEVICE_ERROR
;
526 // From now on we work in 32-bit words
527 BufferSizeInWords
= BufferSizeInBytes
/ (UINTN
)4;
529 // Write the word count, which is (buffer_size_in_words - 1),
530 // because word count 0 means one word.
531 SEND_NOR_COMMAND( TargetAddress
, 0, (BufferSizeInWords
- 1) );
533 // Write the data to the NOR Flash, advancing each address by 4 bytes
534 for( Count
=0; Count
<BufferSizeInWords
; Count
++, Data
++, Buffer
++ ) {
538 // Issue the Buffered Program Confirm command, to start the programming operation
539 SEND_NOR_COMMAND( TargetAddress
, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM
);
541 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
542 Status
= NorFlashReadStatusRegister( TargetAddress
);
548 NorFlashWriteSingleBlock (
549 IN UINTN DeviceBaseAddress
,
551 IN UINT32
*DataBuffer
,
552 IN UINT32 BlockSizeInWords
555 EFI_STATUS Status
= EFI_SUCCESS
;
560 UINTN BuffersInBlock
;
561 UINTN RemainingWords
;
563 // Get the physical address of the block
564 BlockAddress
= GET_NOR_BLOCK_ADDRESS(DeviceBaseAddress
, Lba
, BlockSizeInWords
* 4);
566 Status
= NorFlashUnlockAndEraseSingleBlock( BlockAddress
);
567 if (EFI_ERROR(Status
)) {
568 DEBUG((EFI_D_ERROR
, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress
));
572 // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
574 // Start writing from the first address at the start of the block
575 WordAddress
= BlockAddress
;
577 // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
578 if ( (WordAddress
& BOUNDARY_OF_32_WORDS
) == 0x00 ) {
580 // First, break the entire block into buffer-sized chunks.
581 BuffersInBlock
= (UINTN
)BlockSizeInWords
/ P30_MAX_BUFFER_SIZE_IN_BYTES
;
583 // Then feed each buffer chunk to the NOR Flash
585 BufferIndex
< BuffersInBlock
;
586 BufferIndex
++, WordAddress
+= P30_MAX_BUFFER_SIZE_IN_BYTES
, DataBuffer
+= P30_MAX_BUFFER_SIZE_IN_WORDS
588 Status
= NorFlashWriteBuffer ( WordAddress
, P30_MAX_BUFFER_SIZE_IN_BYTES
, DataBuffer
);
589 if (EFI_ERROR(Status
)) {
594 // Finally, finish off any remaining words that are less than the maximum size of the buffer
595 RemainingWords
= BlockSizeInWords
% P30_MAX_BUFFER_SIZE_IN_WORDS
;
597 if( RemainingWords
!= 0) {
598 Status
= NorFlashWriteBuffer ( WordAddress
, (RemainingWords
* 4), DataBuffer
);
599 if (EFI_ERROR(Status
)) {
605 // For now, use the single word programming algorithm
606 // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
607 // i.e. which ends in the range 0x......01 - 0x......7F.
608 for( WordIndex
=0; WordIndex
<BlockSizeInWords
; WordIndex
++, DataBuffer
++, WordAddress
= WordAddress
+ 4 ) {
609 Status
= NorFlashWriteSingleWord( WordAddress
, *DataBuffer
);
610 if (EFI_ERROR(Status
)) {
617 if (EFI_ERROR(Status
)) {
618 DEBUG((EFI_D_ERROR
, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress
, Status
));
625 NorFlashWriteBlocks (
626 IN NOR_FLASH_INSTANCE
*Instance
,
628 IN UINTN BufferSizeInBytes
,
632 UINT32
*pWriteBuffer
;
633 EFI_STATUS Status
= EFI_SUCCESS
;
634 EFI_LBA CurrentBlock
;
635 UINT32 BlockSizeInWords
;
638 volatile UINT32
*VersatileExpress_SYS_FLASH
;
640 // The buffer must be valid
641 if (Buffer
== NULL
) {
642 return EFI_INVALID_PARAMETER
;
645 if( Instance
->Media
.ReadOnly
== TRUE
) {
646 return EFI_WRITE_PROTECTED
;
649 // We must have some bytes to read
650 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes
));
651 if( BufferSizeInBytes
== 0 ) {
652 return EFI_BAD_BUFFER_SIZE
;
655 // The size of the buffer must be a multiple of the block size
656 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance
->Media
.BlockSize
));
657 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
658 return EFI_BAD_BUFFER_SIZE
;
661 // All blocks must be within the device
662 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
664 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks
, Instance
->Media
.LastBlock
, Lba
));
666 if ( ( Lba
+ NumBlocks
) > ( Instance
->Media
.LastBlock
+ 1 ) ) {
667 DEBUG((EFI_D_ERROR
, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
668 return EFI_INVALID_PARAMETER
;
671 // Everything seems ok so far, so now we need to disable the platform-specific
672 // flash write protection for Versatile Express
673 VersatileExpress_SYS_FLASH
= (UINT32
*)VE_REGISTER_SYS_FLASH_ADDR
;
674 if( (*VersatileExpress_SYS_FLASH
& 0x1) == 0 ) {
675 // Writing to NOR FLASH is disabled, so enable it
676 *VersatileExpress_SYS_FLASH
= 0x1;
677 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: informational - Had to enable HSYS_FLASH flag.\n" ));
680 BlockSizeInWords
= Instance
->Media
.BlockSize
/ 4;
682 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
683 // to a proper data type, so use *ReadBuffer
684 pWriteBuffer
= (UINT32
*)Buffer
;
687 for( BlockCount
=0; BlockCount
<NumBlocks
; BlockCount
++, CurrentBlock
++, pWriteBuffer
= pWriteBuffer
+ BlockSizeInWords
) {
689 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN
)CurrentBlock
));
691 Status
= NorFlashWriteSingleBlock( Instance
->BaseAddress
, CurrentBlock
, pWriteBuffer
, BlockSizeInWords
);
693 if (EFI_ERROR(Status
)) {
699 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status
));
706 IN NOR_FLASH_INSTANCE
*Instance
,
708 IN UINTN BufferSizeInBytes
,
715 // The buffer must be valid
716 if (Buffer
== NULL
) {
717 return EFI_INVALID_PARAMETER
;
720 // We must have some bytes to read
721 DEBUG((DEBUG_BLKIO
, "NorFlashReadBlocks: BufferSize=0x%x bytes.\n", BufferSizeInBytes
));
722 if( BufferSizeInBytes
== 0 ) {
723 return EFI_BAD_BUFFER_SIZE
;
726 // The size of the buffer must be a multiple of the block size
727 DEBUG((DEBUG_BLKIO
, "NorFlashReadBlocks: BlockSize=0x%x bytes.\n", Instance
->Media
.BlockSize
));
728 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
729 return EFI_BAD_BUFFER_SIZE
;
732 // All blocks must be within the device
733 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
735 DEBUG((DEBUG_BLKIO
, "NorFlashReadBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld\n", NumBlocks
, Instance
->Media
.LastBlock
, Lba
));
737 if ( ( Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1) ) {
738 DEBUG((EFI_D_ERROR
, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
739 return EFI_INVALID_PARAMETER
;
742 // Get the address to start reading from
743 StartAddress
= GET_NOR_BLOCK_ADDRESS( Instance
->BaseAddress
,
745 Instance
->Media
.BlockSize
748 // Put the device into Read Array mode
749 SEND_NOR_COMMAND( Instance
->BaseAddress
, 0, P30_CMD_READ_ARRAY
);
752 CopyMem(Buffer
, (UINTN
*)StartAddress
, BufferSizeInBytes
);
760 IN NOR_FLASH_INSTANCE
*Instance
763 DEBUG((DEBUG_BLKIO
, "NorFlashReset(BaseAddress=0x%08x)\n", Instance
->BaseAddress
));
765 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
766 SEND_NOR_COMMAND( Instance
->BaseAddress
, 0, P30_CMD_READ_ARRAY
);
776 IN EFI_HANDLE ImageHandle
,
777 IN EFI_SYSTEM_TABLE
*SystemTable
780 EFI_STATUS Status
= EFI_SUCCESS
;
782 UINTN NvStorageVariableBase
= (UINTN
) PcdGet32 (PcdFlashNvStorageVariableBase
);
784 for (Index
= 0; Index
< NOR_FLASH_LAST_DEVICE
; Index
++) {
785 Status
= NorFlashCreateInstance(
786 mNorFlashDescription
[Index
].BaseAddress
,
787 mNorFlashDescription
[Index
].Size
,
789 mNorFlashDescription
[Index
].BlockSize
,
790 (mNorFlashDescription
[Index
].BaseAddress
== NvStorageVariableBase
),
791 &mNorFlashDescription
[Index
].Guid
,
792 &mNorFlashInstances
[Index
]
794 if (EFI_ERROR(Status
)) {
795 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index
));