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"
23 STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent
;
26 // Global variable declarations
28 NOR_FLASH_INSTANCE
**mNorFlashInstances
;
29 UINT32 mNorFlashDeviceCount
;
31 NOR_FLASH_INSTANCE mNorFlashInstanceTemplate
= {
32 NOR_FLASH_SIGNATURE
, // Signature
33 NULL
, // Handle ... NEED TO BE FILLED
38 0, // DeviceBaseAddress ... NEED TO BE FILLED
39 0, // RegionBaseAddress ... NEED TO BE FILLED
40 0, // Size ... NEED TO BE FILLED
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
53 0, // MediaId ... NEED TO BE FILLED
54 FALSE
, // RemovableMedia
56 FALSE
, // LogicalPartition
58 FALSE
, // WriteCaching;
59 0, // BlockSize ... NEED TO BE FILLED
61 0, // LastBlock ... NEED TO BE FILLED
62 0, // LowestAlignedLba
63 1, // LogicalBlocksPerPhysicalBlock
66 FALSE
, // SupportFvb ... NEED TO BE FILLED
68 FvbGetAttributes
, // GetAttributes
69 FvbSetAttributes
, // SetAttributes
70 FvbGetPhysicalAddress
, // GetPhysicalAddress
71 FvbGetBlockSize
, // GetBlockSize
74 FvbEraseBlocks
, // EraseBlocks
83 (UINT8
)( sizeof(VENDOR_DEVICE_PATH
) ),
84 (UINT8
)((sizeof(VENDOR_DEVICE_PATH
)) >> 8),
86 { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, // GUID ... NEED TO BE FILLED
90 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
91 sizeof (EFI_DEVICE_PATH_PROTOCOL
),
98 NorFlashCreateInstance (
99 IN UINTN NorFlashDeviceBase
,
100 IN UINTN NorFlashRegionBase
,
101 IN UINTN NorFlashSize
,
104 IN BOOLEAN SupportFvb
,
105 IN CONST GUID
*NorFlashGuid
,
106 OUT NOR_FLASH_INSTANCE
** NorFlashInstance
110 NOR_FLASH_INSTANCE
* Instance
;
112 ASSERT(NorFlashInstance
!= NULL
);
114 Instance
= AllocateRuntimeCopyPool (sizeof(NOR_FLASH_INSTANCE
),&mNorFlashInstanceTemplate
);
115 if (Instance
== NULL
) {
116 return EFI_OUT_OF_RESOURCES
;
119 Instance
->DeviceBaseAddress
= NorFlashDeviceBase
;
120 Instance
->RegionBaseAddress
= NorFlashRegionBase
;
121 Instance
->Size
= NorFlashSize
;
123 Instance
->BlockIoProtocol
.Media
= &Instance
->Media
;
124 Instance
->Media
.MediaId
= MediaId
;
125 Instance
->Media
.BlockSize
= BlockSize
;
126 Instance
->Media
.LastBlock
= (NorFlashSize
/ BlockSize
)-1;
128 CopyGuid (&Instance
->DevicePath
.Vendor
.Guid
, NorFlashGuid
);
131 Instance
->SupportFvb
= TRUE
;
132 Instance
->Initialize
= NorFlashFvbInitialize
;
133 Instance
->FvbBuffer
= AllocateRuntimePool (BlockSize
);;
134 if (Instance
->FvbBuffer
== NULL
) {
135 return EFI_OUT_OF_RESOURCES
;
138 Status
= gBS
->InstallMultipleProtocolInterfaces (
140 &gEfiDevicePathProtocolGuid
, &Instance
->DevicePath
,
141 &gEfiBlockIoProtocolGuid
, &Instance
->BlockIoProtocol
,
142 &gEfiFirmwareVolumeBlockProtocolGuid
, &Instance
->FvbProtocol
,
145 if (EFI_ERROR(Status
)) {
150 Instance
->Initialized
= TRUE
;
152 Status
= gBS
->InstallMultipleProtocolInterfaces (
154 &gEfiDevicePathProtocolGuid
, &Instance
->DevicePath
,
155 &gEfiBlockIoProtocolGuid
, &Instance
->BlockIoProtocol
,
158 if (EFI_ERROR(Status
)) {
164 *NorFlashInstance
= Instance
;
169 NorFlashReadStatusRegister (
170 IN NOR_FLASH_INSTANCE
*Instance
,
174 // Prepare to read the status register
175 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_STATUS_REGISTER
);
176 return MmioRead32 (Instance
->DeviceBaseAddress
);
181 NorFlashBlockIsLocked (
182 IN NOR_FLASH_INSTANCE
*Instance
,
183 IN UINTN BlockAddress
187 BOOLEAN BlockIsLocked
;
189 BlockIsLocked
= TRUE
;
191 // Send command for reading device id
192 SEND_NOR_COMMAND (BlockAddress
, 2, P30_CMD_READ_DEVICE_ID
);
194 // Read block lock status
195 LockStatus
= MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress
, 2));
197 // Decode block lock status
198 LockStatus
= FOLD_32BIT_INTO_16BIT(LockStatus
);
200 if ((LockStatus
& 0x2) != 0) {
201 DEBUG((EFI_D_ERROR
, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
204 if ((LockStatus
& 0x1) == 0) {
205 // This means the block is unlocked
206 DEBUG((DEBUG_BLKIO
, "UnlockSingleBlock: Block 0x%08x unlocked\n", BlockAddress
));
207 BlockIsLocked
= FALSE
;
210 return BlockIsLocked
;
215 NorFlashUnlockSingleBlock (
216 IN NOR_FLASH_INSTANCE
*Instance
,
217 IN UINTN BlockAddress
220 EFI_STATUS Status
= EFI_SUCCESS
;
223 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
224 // and to protect shared data structures.
226 if (FeaturePcdGet (PcdNorFlashCheckBlockLocked
) == TRUE
) {
228 // Request a lock setup
229 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
232 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
234 // Send command for reading device id
235 SEND_NOR_COMMAND (BlockAddress
, 2, P30_CMD_READ_DEVICE_ID
);
237 // Read block lock status
238 LockStatus
= MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress
, 2));
240 // Decode block lock status
241 LockStatus
= FOLD_32BIT_INTO_16BIT(LockStatus
);
242 } while ((LockStatus
& 0x1) == 1);
244 // Request a lock setup
245 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
248 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
250 // Wait until the status register gives us the all clear
252 LockStatus
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
253 } while ((LockStatus
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
256 // Put device back into Read Array mode
257 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_READ_ARRAY
);
259 DEBUG((DEBUG_BLKIO
, "UnlockSingleBlock: BlockAddress=0x%08x, Exit Status = \"%r\".\n", BlockAddress
, Status
));
266 NorFlashUnlockSingleBlockIfNecessary (
267 IN NOR_FLASH_INSTANCE
*Instance
,
268 IN UINTN BlockAddress
271 EFI_STATUS Status
= EFI_SUCCESS
;
273 if (NorFlashBlockIsLocked (Instance
, BlockAddress
) == TRUE
) {
274 Status
= NorFlashUnlockSingleBlock (Instance
, BlockAddress
);
282 * The following function presumes that the block has already been unlocked.
285 NorFlashEraseSingleBlock (
286 IN NOR_FLASH_INSTANCE
*Instance
,
287 IN UINTN BlockAddress
291 UINT32 StatusRegister
;
293 Status
= EFI_SUCCESS
;
295 // Request a block erase and then confirm it
296 SEND_NOR_COMMAND(BlockAddress
, 0, P30_CMD_BLOCK_ERASE_SETUP
);
297 SEND_NOR_COMMAND(BlockAddress
, 0, P30_CMD_BLOCK_ERASE_CONFIRM
);
299 // Wait until the status register gives us the all clear
301 StatusRegister
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
302 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
304 if (StatusRegister
& P30_SR_BIT_VPP
) {
305 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress
));
306 Status
= EFI_DEVICE_ERROR
;
309 if ((StatusRegister
& (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) == (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) {
310 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress
));
311 Status
= EFI_DEVICE_ERROR
;
314 if (StatusRegister
& P30_SR_BIT_ERASE
) {
315 DEBUG((EFI_D_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress
, StatusRegister
));
316 Status
= EFI_DEVICE_ERROR
;
319 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
320 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
321 DEBUG((EFI_D_INFO
,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress
));
322 Status
= EFI_WRITE_PROTECTED
;
325 if (EFI_ERROR(Status
)) {
326 // Clear the Status Register
327 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
330 // Put device back into Read Array mode
331 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
337 * The following function presumes that the block has already been unlocked.
340 NorFlashUnlockAndEraseSingleBlock (
341 IN NOR_FLASH_INSTANCE
*Instance
,
342 IN UINTN BlockAddress
349 if (!EfiAtRuntime ()) {
350 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
351 OriginalTPL
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
353 // This initialization is only to prevent the compiler to complain about the
354 // use of uninitialized variables
355 OriginalTPL
= TPL_HIGH_LEVEL
;
359 // The block erase might fail a first time (SW bug ?). Retry it ...
361 // Unlock the block if we have to
362 Status
= NorFlashUnlockSingleBlockIfNecessary (Instance
, BlockAddress
);
363 if (!EFI_ERROR(Status
)) {
364 Status
= NorFlashEraseSingleBlock (Instance
, BlockAddress
);
367 } while ((Index
< NOR_FLASH_ERASE_RETRY
) && (Status
== EFI_WRITE_PROTECTED
));
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
));
373 if (!EfiAtRuntime ()) {
374 // Interruptions can resume.
375 gBS
->RestoreTPL (OriginalTPL
);
383 NorFlashWriteSingleWord (
384 IN NOR_FLASH_INSTANCE
*Instance
,
385 IN UINTN WordAddress
,
390 UINT32 StatusRegister
;
392 Status
= EFI_SUCCESS
;
394 // Request a write single word command
395 SEND_NOR_COMMAND(WordAddress
, 0, P30_CMD_WORD_PROGRAM_SETUP
);
397 // Store the word into NOR Flash;
398 MmioWrite32 (WordAddress
, WriteData
);
400 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
402 // Prepare to read the status register
403 StatusRegister
= NorFlashReadStatusRegister (Instance
, WordAddress
);
404 // The chip is busy while the WRITE bit is not asserted
405 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
408 // Perform a full status check:
409 // Mask the relevant bits of Status Register.
410 // Everything should be zero, if not, we have a problem
412 if (StatusRegister
& P30_SR_BIT_VPP
) {
413 DEBUG((EFI_D_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n",WordAddress
));
414 Status
= EFI_DEVICE_ERROR
;
417 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
418 DEBUG((EFI_D_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n",WordAddress
));
419 Status
= EFI_DEVICE_ERROR
;
422 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
423 DEBUG((EFI_D_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n",WordAddress
));
424 Status
= EFI_DEVICE_ERROR
;
427 if (!EFI_ERROR(Status
)) {
428 // Clear the Status Register
429 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
432 // Put device back into Read Array mode
433 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
439 * Writes data to the NOR Flash using the Buffered Programming method.
441 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
442 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
443 * To deal with larger buffers, call this function again.
445 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
446 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
448 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
449 * then programming time is doubled and power consumption is increased.
450 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
451 * i.e. the last 4 bits of the target start address must be zero: 0x......00
454 NorFlashWriteBuffer (
455 IN NOR_FLASH_INSTANCE
*Instance
,
456 IN UINTN TargetAddress
,
457 IN UINTN BufferSizeInBytes
,
462 UINTN BufferSizeInWords
;
464 volatile UINT32
*Data
;
466 BOOLEAN BufferAvailable
;
467 UINT32 StatusRegister
;
469 WaitForBuffer
= MAX_BUFFERED_PROG_ITERATIONS
;
470 BufferAvailable
= FALSE
;
472 // Check that the target address does not cross a 32-word boundary.
473 if ((TargetAddress
& BOUNDARY_OF_32_WORDS
) != 0) {
474 return EFI_INVALID_PARAMETER
;
477 // Check there are some data to program
478 if (BufferSizeInBytes
== 0) {
479 return EFI_BUFFER_TOO_SMALL
;
482 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
483 if (BufferSizeInBytes
> P30_MAX_BUFFER_SIZE_IN_BYTES
) {
484 return EFI_BAD_BUFFER_SIZE
;
487 // Check that the buffer size is a multiple of 32-bit words
488 if ((BufferSizeInBytes
% 4) != 0) {
489 return EFI_BAD_BUFFER_SIZE
;
492 // Pre-programming conditions checked, now start the algorithm.
494 // Prepare the data destination address
495 Data
= (UINT32
*)TargetAddress
;
497 // Check the availability of the buffer
499 // Issue the Buffered Program Setup command
500 SEND_NOR_COMMAND(TargetAddress
, 0, P30_CMD_BUFFERED_PROGRAM_SETUP
);
502 // Read back the status register bit#7 from the same address
503 if (((*Data
) & P30_SR_BIT_WRITE
) == P30_SR_BIT_WRITE
) {
504 BufferAvailable
= TRUE
;
507 // Update the loop counter
510 } while ((WaitForBuffer
> 0) && (BufferAvailable
== FALSE
));
512 // The buffer was not available for writing
513 if (WaitForBuffer
== 0) {
514 Status
= EFI_DEVICE_ERROR
;
518 // From now on we work in 32-bit words
519 BufferSizeInWords
= BufferSizeInBytes
/ (UINTN
)4;
521 // Write the word count, which is (buffer_size_in_words - 1),
522 // because word count 0 means one word.
523 SEND_NOR_COMMAND(TargetAddress
, 0, (BufferSizeInWords
- 1));
525 // Write the data to the NOR Flash, advancing each address by 4 bytes
526 for(Count
=0; Count
< BufferSizeInWords
; Count
++, Data
++, Buffer
++) {
530 // Issue the Buffered Program Confirm command, to start the programming operation
531 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM
);
533 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
535 StatusRegister
= NorFlashReadStatusRegister (Instance
, TargetAddress
);
536 // The chip is busy while the WRITE bit is not asserted
537 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
540 // Perform a full status check:
541 // Mask the relevant bits of Status Register.
542 // Everything should be zero, if not, we have a problem
544 Status
= EFI_SUCCESS
;
546 if (StatusRegister
& P30_SR_BIT_VPP
) {
547 DEBUG((EFI_D_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress
));
548 Status
= EFI_DEVICE_ERROR
;
551 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
552 DEBUG((EFI_D_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress
));
553 Status
= EFI_DEVICE_ERROR
;
556 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
557 DEBUG((EFI_D_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n",TargetAddress
));
558 Status
= EFI_DEVICE_ERROR
;
561 if (!EFI_ERROR(Status
)) {
562 // Clear the Status Register
563 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
567 // Put device back into Read Array mode
568 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
574 NorFlashWriteSingleBlock (
575 IN NOR_FLASH_INSTANCE
*Instance
,
577 IN UINT32
*DataBuffer
,
578 IN UINT32 BlockSizeInWords
586 UINTN BuffersInBlock
;
587 UINTN RemainingWords
;
591 Status
= EFI_SUCCESS
;
593 // Get the physical address of the block
594 BlockAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
, Lba
, BlockSizeInWords
* 4);
596 // Start writing from the first address at the start of the block
597 WordAddress
= BlockAddress
;
599 if (!EfiAtRuntime ()) {
600 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
601 OriginalTPL
= gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
603 // This initialization is only to prevent the compiler to complain about the
604 // use of uninitialized variables
605 OriginalTPL
= TPL_HIGH_LEVEL
;
608 Status
= NorFlashUnlockAndEraseSingleBlock (Instance
, BlockAddress
);
609 if (EFI_ERROR(Status
)) {
610 DEBUG((EFI_D_ERROR
, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress
));
614 // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
616 // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
617 if ((WordAddress
& BOUNDARY_OF_32_WORDS
) == 0x00) {
619 // First, break the entire block into buffer-sized chunks.
620 BuffersInBlock
= (UINTN
)(BlockSizeInWords
* 4) / P30_MAX_BUFFER_SIZE_IN_BYTES
;
622 // Then feed each buffer chunk to the NOR Flash
623 // If a buffer does not contain any data, don't write it.
625 BufferIndex
< BuffersInBlock
;
626 BufferIndex
++, WordAddress
+= P30_MAX_BUFFER_SIZE_IN_BYTES
, DataBuffer
+= P30_MAX_BUFFER_SIZE_IN_WORDS
628 // Check the buffer to see if it contains any data (not set all 1s).
629 for (Cnt
= 0; Cnt
< P30_MAX_BUFFER_SIZE_IN_WORDS
; Cnt
++) {
630 if (~DataBuffer
[Cnt
] != 0 ) {
631 // Some data found, write the buffer.
632 Status
= NorFlashWriteBuffer (Instance
, WordAddress
, P30_MAX_BUFFER_SIZE_IN_BYTES
,
634 if (EFI_ERROR(Status
)) {
642 // Finally, finish off any remaining words that are less than the maximum size of the buffer
643 RemainingWords
= BlockSizeInWords
% P30_MAX_BUFFER_SIZE_IN_WORDS
;
645 if(RemainingWords
!= 0) {
646 Status
= NorFlashWriteBuffer (Instance
, WordAddress
, (RemainingWords
* 4), DataBuffer
);
647 if (EFI_ERROR(Status
)) {
653 // For now, use the single word programming algorithm
654 // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
655 // i.e. which ends in the range 0x......01 - 0x......7F.
656 for(WordIndex
=0; WordIndex
<BlockSizeInWords
; WordIndex
++, DataBuffer
++, WordAddress
= WordAddress
+ 4) {
657 Status
= NorFlashWriteSingleWord (Instance
, WordAddress
, *DataBuffer
);
658 if (EFI_ERROR(Status
)) {
665 if (!EfiAtRuntime ()) {
666 // Interruptions can resume.
667 gBS
->RestoreTPL (OriginalTPL
);
670 if (EFI_ERROR(Status
)) {
671 DEBUG((EFI_D_ERROR
, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress
, Status
));
678 NorFlashWriteBlocks (
679 IN NOR_FLASH_INSTANCE
*Instance
,
681 IN UINTN BufferSizeInBytes
,
685 UINT32
*pWriteBuffer
;
686 EFI_STATUS Status
= EFI_SUCCESS
;
687 EFI_LBA CurrentBlock
;
688 UINT32 BlockSizeInWords
;
692 // The buffer must be valid
693 if (Buffer
== NULL
) {
694 return EFI_INVALID_PARAMETER
;
697 if(Instance
->Media
.ReadOnly
== TRUE
) {
698 return EFI_WRITE_PROTECTED
;
701 // We must have some bytes to read
702 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes
));
703 if(BufferSizeInBytes
== 0) {
704 return EFI_BAD_BUFFER_SIZE
;
707 // The size of the buffer must be a multiple of the block size
708 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance
->Media
.BlockSize
));
709 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
710 return EFI_BAD_BUFFER_SIZE
;
713 // All blocks must be within the device
714 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
716 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks
, Instance
->Media
.LastBlock
, Lba
));
718 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
719 DEBUG((EFI_D_ERROR
, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
720 return EFI_INVALID_PARAMETER
;
723 BlockSizeInWords
= Instance
->Media
.BlockSize
/ 4;
725 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
726 // to a proper data type, so use *ReadBuffer
727 pWriteBuffer
= (UINT32
*)Buffer
;
730 for (BlockCount
=0; BlockCount
< NumBlocks
; BlockCount
++, CurrentBlock
++, pWriteBuffer
= pWriteBuffer
+ BlockSizeInWords
) {
732 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN
)CurrentBlock
));
734 Status
= NorFlashWriteSingleBlock (Instance
, CurrentBlock
, pWriteBuffer
, BlockSizeInWords
);
736 if (EFI_ERROR(Status
)) {
741 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status
));
747 IN NOR_FLASH_INSTANCE
*Instance
,
749 IN UINTN BufferSizeInBytes
,
756 DEBUG((DEBUG_BLKIO
, "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
757 BufferSizeInBytes
, Instance
->Media
.BlockSize
, Instance
->Media
.LastBlock
, Lba
));
759 // The buffer must be valid
760 if (Buffer
== NULL
) {
761 return EFI_INVALID_PARAMETER
;
764 // Return if we have not any byte to read
765 if (BufferSizeInBytes
== 0) {
769 // The size of the buffer must be a multiple of the block size
770 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
771 return EFI_BAD_BUFFER_SIZE
;
774 // All blocks must be within the device
775 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
777 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
778 DEBUG((EFI_D_ERROR
, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
779 return EFI_INVALID_PARAMETER
;
782 // Get the address to start reading from
783 StartAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
,
785 Instance
->Media
.BlockSize
788 // Put the device into Read Array mode
789 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
792 CopyMem(Buffer
, (UINTN
*)StartAddress
, BufferSizeInBytes
);
799 IN NOR_FLASH_INSTANCE
*Instance
,
802 IN UINTN BufferSizeInBytes
,
809 // The buffer must be valid
810 if (Buffer
== NULL
) {
811 return EFI_INVALID_PARAMETER
;
814 // Return if we have not any byte to read
815 if (BufferSizeInBytes
== 0) {
819 // All blocks must be within the device
820 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
822 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
823 DEBUG ((EFI_D_ERROR
, "NorFlashRead: ERROR - Read will exceed last block\n"));
824 return EFI_INVALID_PARAMETER
;
827 if (Offset
+ BufferSizeInBytes
>= Instance
->Size
) {
828 DEBUG ((EFI_D_ERROR
, "NorFlashRead: ERROR - Read will exceed device size.\n"));
829 return EFI_INVALID_PARAMETER
;
832 // Get the address to start reading from
833 StartAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
,
835 Instance
->Media
.BlockSize
838 // Put the device into Read Array mode
839 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
842 CopyMem (Buffer
, (UINTN
*)(StartAddress
+ Offset
), BufferSizeInBytes
);
850 IN NOR_FLASH_INSTANCE
*Instance
853 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
854 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
859 Fixup internal data so that EFI can be call in virtual mode.
860 Call the passed in Child Notify event and convert any pointers in
863 @param[in] Event The Event that is being processed
864 @param[in] Context Event Context
868 NorFlashVirtualNotifyEvent (
875 for (Index
= 0; Index
< mNorFlashDeviceCount
; Index
++) {
876 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->DeviceBaseAddress
);
877 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->RegionBaseAddress
);
879 // Convert BlockIo protocol
880 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.FlushBlocks
);
881 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.ReadBlocks
);
882 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.Reset
);
883 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.WriteBlocks
);
886 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.EraseBlocks
);
887 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetAttributes
);
888 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetBlockSize
);
889 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetPhysicalAddress
);
890 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Read
);
891 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.SetAttributes
);
892 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Write
);
894 if (mNorFlashInstances
[Index
]->FvbBuffer
!= NULL
) {
895 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbBuffer
);
905 IN EFI_HANDLE ImageHandle
,
906 IN EFI_SYSTEM_TABLE
*SystemTable
911 NOR_FLASH_DESCRIPTION
* NorFlashDevices
;
912 BOOLEAN ContainVariableStorage
;
914 Status
= NorFlashPlatformInitialization ();
915 if (EFI_ERROR(Status
)) {
916 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to initialize Nor Flash devices\n"));
920 Status
= NorFlashPlatformGetDevices (&NorFlashDevices
, &mNorFlashDeviceCount
);
921 if (EFI_ERROR(Status
)) {
922 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to get Nor Flash devices\n"));
926 mNorFlashInstances
= AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE
*) * mNorFlashDeviceCount
);
928 for (Index
= 0; Index
< mNorFlashDeviceCount
; Index
++) {
929 // Check if this NOR Flash device contain the variable storage region
930 ContainVariableStorage
=
931 (NorFlashDevices
[Index
].RegionBaseAddress
<= PcdGet32 (PcdFlashNvStorageVariableBase
)) &&
932 (PcdGet32 (PcdFlashNvStorageVariableBase
) + PcdGet32 (PcdFlashNvStorageVariableSize
) <= NorFlashDevices
[Index
].RegionBaseAddress
+ NorFlashDevices
[Index
].Size
);
934 Status
= NorFlashCreateInstance (
935 NorFlashDevices
[Index
].DeviceBaseAddress
,
936 NorFlashDevices
[Index
].RegionBaseAddress
,
937 NorFlashDevices
[Index
].Size
,
939 NorFlashDevices
[Index
].BlockSize
,
940 ContainVariableStorage
,
941 &NorFlashDevices
[Index
].Guid
,
942 &mNorFlashInstances
[Index
]
944 if (EFI_ERROR(Status
)) {
945 DEBUG((EFI_D_ERROR
,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index
));
950 // Register for the virtual address change event
952 Status
= gBS
->CreateEventEx (
955 NorFlashVirtualNotifyEvent
,
957 &gEfiEventVirtualAddressChangeGuid
,
958 &mNorFlashVirtualAddrChangeEvent
960 ASSERT_EFI_ERROR (Status
);