3 Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>
4 Copyright (c) 2020, Linaro, Ltd. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseMemoryLib.h>
15 // Global variable declarations
17 extern NOR_FLASH_INSTANCE
**mNorFlashInstances
;
18 extern UINT32 mNorFlashDeviceCount
;
21 NorFlashReadStatusRegister (
22 IN NOR_FLASH_INSTANCE
*Instance
,
26 // Prepare to read the status register
27 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_STATUS_REGISTER
);
28 return MmioRead32 (Instance
->DeviceBaseAddress
);
33 NorFlashBlockIsLocked (
34 IN NOR_FLASH_INSTANCE
*Instance
,
40 // Send command for reading device id
41 SEND_NOR_COMMAND (BlockAddress
, 2, P30_CMD_READ_DEVICE_ID
);
43 // Read block lock status
44 LockStatus
= MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress
, 2));
46 // Decode block lock status
47 LockStatus
= FOLD_32BIT_INTO_16BIT(LockStatus
);
49 if ((LockStatus
& 0x2) != 0) {
50 DEBUG((DEBUG_ERROR
, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
53 return ((LockStatus
& 0x1) != 0);
58 NorFlashUnlockSingleBlock (
59 IN NOR_FLASH_INSTANCE
*Instance
,
65 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
66 // and to protect shared data structures.
68 if (FeaturePcdGet (PcdNorFlashCheckBlockLocked
) == TRUE
) {
70 // Request a lock setup
71 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
74 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
76 // Send command for reading device id
77 SEND_NOR_COMMAND (BlockAddress
, 2, P30_CMD_READ_DEVICE_ID
);
79 // Read block lock status
80 LockStatus
= MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress
, 2));
82 // Decode block lock status
83 LockStatus
= FOLD_32BIT_INTO_16BIT(LockStatus
);
84 } while ((LockStatus
& 0x1) == 1);
86 // Request a lock setup
87 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
90 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
92 // Wait until the status register gives us the all clear
94 LockStatus
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
95 } while ((LockStatus
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
98 // Put device back into Read Array mode
99 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_READ_ARRAY
);
101 DEBUG((DEBUG_BLKIO
, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress
));
107 NorFlashUnlockSingleBlockIfNecessary (
108 IN NOR_FLASH_INSTANCE
*Instance
,
109 IN UINTN BlockAddress
114 Status
= EFI_SUCCESS
;
116 if (NorFlashBlockIsLocked (Instance
, BlockAddress
)) {
117 Status
= NorFlashUnlockSingleBlock (Instance
, BlockAddress
);
125 * The following function presumes that the block has already been unlocked.
128 NorFlashEraseSingleBlock (
129 IN NOR_FLASH_INSTANCE
*Instance
,
130 IN UINTN BlockAddress
134 UINT32 StatusRegister
;
136 Status
= EFI_SUCCESS
;
138 // Request a block erase and then confirm it
139 SEND_NOR_COMMAND(BlockAddress
, 0, P30_CMD_BLOCK_ERASE_SETUP
);
140 SEND_NOR_COMMAND(BlockAddress
, 0, P30_CMD_BLOCK_ERASE_CONFIRM
);
142 // Wait until the status register gives us the all clear
144 StatusRegister
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
145 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
147 if (StatusRegister
& P30_SR_BIT_VPP
) {
148 DEBUG((DEBUG_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress
));
149 Status
= EFI_DEVICE_ERROR
;
152 if ((StatusRegister
& (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) == (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) {
153 DEBUG((DEBUG_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress
));
154 Status
= EFI_DEVICE_ERROR
;
157 if (StatusRegister
& P30_SR_BIT_ERASE
) {
158 DEBUG((DEBUG_ERROR
,"EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress
, StatusRegister
));
159 Status
= EFI_DEVICE_ERROR
;
162 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
163 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
164 DEBUG((DEBUG_INFO
,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress
));
165 Status
= EFI_WRITE_PROTECTED
;
168 if (EFI_ERROR(Status
)) {
169 // Clear the Status Register
170 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
173 // Put device back into Read Array mode
174 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
180 NorFlashWriteSingleWord (
181 IN NOR_FLASH_INSTANCE
*Instance
,
182 IN UINTN WordAddress
,
187 UINT32 StatusRegister
;
189 Status
= EFI_SUCCESS
;
191 // Request a write single word command
192 SEND_NOR_COMMAND(WordAddress
, 0, P30_CMD_WORD_PROGRAM_SETUP
);
194 // Store the word into NOR Flash;
195 MmioWrite32 (WordAddress
, WriteData
);
197 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
199 // Prepare to read the status register
200 StatusRegister
= NorFlashReadStatusRegister (Instance
, WordAddress
);
201 // The chip is busy while the WRITE bit is not asserted
202 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
205 // Perform a full status check:
206 // Mask the relevant bits of Status Register.
207 // Everything should be zero, if not, we have a problem
209 if (StatusRegister
& P30_SR_BIT_VPP
) {
210 DEBUG((DEBUG_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n",WordAddress
));
211 Status
= EFI_DEVICE_ERROR
;
214 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
215 DEBUG((DEBUG_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n",WordAddress
));
216 Status
= EFI_DEVICE_ERROR
;
219 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
220 DEBUG((DEBUG_ERROR
,"NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n",WordAddress
));
221 Status
= EFI_DEVICE_ERROR
;
224 if (!EFI_ERROR(Status
)) {
225 // Clear the Status Register
226 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
229 // Put device back into Read Array mode
230 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
236 * Writes data to the NOR Flash using the Buffered Programming method.
238 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
239 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
240 * To deal with larger buffers, call this function again.
242 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
243 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
245 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
246 * then programming time is doubled and power consumption is increased.
247 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
248 * i.e. the last 4 bits of the target start address must be zero: 0x......00
251 NorFlashWriteBuffer (
252 IN NOR_FLASH_INSTANCE
*Instance
,
253 IN UINTN TargetAddress
,
254 IN UINTN BufferSizeInBytes
,
259 UINTN BufferSizeInWords
;
261 volatile UINT32
*Data
;
263 BOOLEAN BufferAvailable
;
264 UINT32 StatusRegister
;
266 WaitForBuffer
= MAX_BUFFERED_PROG_ITERATIONS
;
267 BufferAvailable
= FALSE
;
269 // Check that the target address does not cross a 32-word boundary.
270 if ((TargetAddress
& BOUNDARY_OF_32_WORDS
) != 0) {
271 return EFI_INVALID_PARAMETER
;
274 // Check there are some data to program
275 if (BufferSizeInBytes
== 0) {
276 return EFI_BUFFER_TOO_SMALL
;
279 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
280 if (BufferSizeInBytes
> P30_MAX_BUFFER_SIZE_IN_BYTES
) {
281 return EFI_BAD_BUFFER_SIZE
;
284 // Check that the buffer size is a multiple of 32-bit words
285 if ((BufferSizeInBytes
% 4) != 0) {
286 return EFI_BAD_BUFFER_SIZE
;
289 // Pre-programming conditions checked, now start the algorithm.
291 // Prepare the data destination address
292 Data
= (UINT32
*)TargetAddress
;
294 // Check the availability of the buffer
296 // Issue the Buffered Program Setup command
297 SEND_NOR_COMMAND(TargetAddress
, 0, P30_CMD_BUFFERED_PROGRAM_SETUP
);
299 // Read back the status register bit#7 from the same address
300 if (((*Data
) & P30_SR_BIT_WRITE
) == P30_SR_BIT_WRITE
) {
301 BufferAvailable
= TRUE
;
304 // Update the loop counter
307 } while ((WaitForBuffer
> 0) && (BufferAvailable
== FALSE
));
309 // The buffer was not available for writing
310 if (WaitForBuffer
== 0) {
311 Status
= EFI_DEVICE_ERROR
;
315 // From now on we work in 32-bit words
316 BufferSizeInWords
= BufferSizeInBytes
/ (UINTN
)4;
318 // Write the word count, which is (buffer_size_in_words - 1),
319 // because word count 0 means one word.
320 SEND_NOR_COMMAND(TargetAddress
, 0, (BufferSizeInWords
- 1));
322 // Write the data to the NOR Flash, advancing each address by 4 bytes
323 for(Count
=0; Count
< BufferSizeInWords
; Count
++, Data
++, Buffer
++) {
324 MmioWrite32 ((UINTN
)Data
, *Buffer
);
327 // Issue the Buffered Program Confirm command, to start the programming operation
328 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM
);
330 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
332 StatusRegister
= NorFlashReadStatusRegister (Instance
, TargetAddress
);
333 // The chip is busy while the WRITE bit is not asserted
334 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
337 // Perform a full status check:
338 // Mask the relevant bits of Status Register.
339 // Everything should be zero, if not, we have a problem
341 Status
= EFI_SUCCESS
;
343 if (StatusRegister
& P30_SR_BIT_VPP
) {
344 DEBUG((DEBUG_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress
));
345 Status
= EFI_DEVICE_ERROR
;
348 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
349 DEBUG((DEBUG_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress
));
350 Status
= EFI_DEVICE_ERROR
;
353 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
354 DEBUG((DEBUG_ERROR
,"NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n",TargetAddress
));
355 Status
= EFI_DEVICE_ERROR
;
358 if (!EFI_ERROR(Status
)) {
359 // Clear the Status Register
360 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
364 // Put device back into Read Array mode
365 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
371 NorFlashWriteBlocks (
372 IN NOR_FLASH_INSTANCE
*Instance
,
374 IN UINTN BufferSizeInBytes
,
378 UINT32
*pWriteBuffer
;
380 EFI_LBA CurrentBlock
;
381 UINT32 BlockSizeInWords
;
385 Status
= EFI_SUCCESS
;
387 // The buffer must be valid
388 if (Buffer
== NULL
) {
389 return EFI_INVALID_PARAMETER
;
392 if(Instance
->Media
.ReadOnly
== TRUE
) {
393 return EFI_WRITE_PROTECTED
;
396 // We must have some bytes to read
397 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes
));
398 if(BufferSizeInBytes
== 0) {
399 return EFI_BAD_BUFFER_SIZE
;
402 // The size of the buffer must be a multiple of the block size
403 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance
->Media
.BlockSize
));
404 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
405 return EFI_BAD_BUFFER_SIZE
;
408 // All blocks must be within the device
409 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
411 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks
, Instance
->Media
.LastBlock
, Lba
));
413 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
414 DEBUG((DEBUG_ERROR
, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
415 return EFI_INVALID_PARAMETER
;
418 BlockSizeInWords
= Instance
->Media
.BlockSize
/ 4;
420 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
421 // to a proper data type, so use *ReadBuffer
422 pWriteBuffer
= (UINT32
*)Buffer
;
425 for (BlockCount
=0; BlockCount
< NumBlocks
; BlockCount
++, CurrentBlock
++, pWriteBuffer
= pWriteBuffer
+ BlockSizeInWords
) {
427 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN
)CurrentBlock
));
429 Status
= NorFlashWriteFullBlock (Instance
, CurrentBlock
, pWriteBuffer
, BlockSizeInWords
);
431 if (EFI_ERROR(Status
)) {
436 DEBUG((DEBUG_BLKIO
, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status
));
440 #define BOTH_ALIGNED(a, b, align) ((((UINTN)(a) | (UINTN)(b)) & ((align) - 1)) == 0)
443 Copy Length bytes from Source to Destination, using aligned accesses only.
444 Note that this implementation uses memcpy() semantics rather then memmove()
445 semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.
447 @param DestinationBuffer The target of the copy request.
448 @param SourceBuffer The place to copy from.
449 @param Length The number of bytes to copy.
457 OUT VOID
*DestinationBuffer
,
458 IN CONST VOID
*SourceBuffer
,
463 CONST UINT8
*Source8
;
464 UINT32
*Destination32
;
465 CONST UINT32
*Source32
;
466 UINT64
*Destination64
;
467 CONST UINT64
*Source64
;
469 if (BOTH_ALIGNED(DestinationBuffer
, SourceBuffer
, 8) && Length
>= 8) {
470 Destination64
= DestinationBuffer
;
471 Source64
= SourceBuffer
;
472 while (Length
>= 8) {
473 *Destination64
++ = *Source64
++;
477 Destination8
= (UINT8
*)Destination64
;
478 Source8
= (CONST UINT8
*)Source64
;
479 } else if (BOTH_ALIGNED(DestinationBuffer
, SourceBuffer
, 4) && Length
>= 4) {
480 Destination32
= DestinationBuffer
;
481 Source32
= SourceBuffer
;
482 while (Length
>= 4) {
483 *Destination32
++ = *Source32
++;
487 Destination8
= (UINT8
*)Destination32
;
488 Source8
= (CONST UINT8
*)Source32
;
490 Destination8
= DestinationBuffer
;
491 Source8
= SourceBuffer
;
493 while (Length
-- != 0) {
494 *Destination8
++ = *Source8
++;
496 return DestinationBuffer
;
501 IN NOR_FLASH_INSTANCE
*Instance
,
503 IN UINTN BufferSizeInBytes
,
510 DEBUG((DEBUG_BLKIO
, "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
511 BufferSizeInBytes
, Instance
->Media
.BlockSize
, Instance
->Media
.LastBlock
, Lba
));
513 // The buffer must be valid
514 if (Buffer
== NULL
) {
515 return EFI_INVALID_PARAMETER
;
518 // Return if we have not any byte to read
519 if (BufferSizeInBytes
== 0) {
523 // The size of the buffer must be a multiple of the block size
524 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
525 return EFI_BAD_BUFFER_SIZE
;
528 // All blocks must be within the device
529 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
531 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
532 DEBUG((DEBUG_ERROR
, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
533 return EFI_INVALID_PARAMETER
;
536 // Get the address to start reading from
537 StartAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
,
539 Instance
->Media
.BlockSize
542 // Put the device into Read Array mode
543 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
546 AlignedCopyMem (Buffer
, (VOID
*)StartAddress
, BufferSizeInBytes
);
553 IN NOR_FLASH_INSTANCE
*Instance
,
556 IN UINTN BufferSizeInBytes
,
562 // The buffer must be valid
563 if (Buffer
== NULL
) {
564 return EFI_INVALID_PARAMETER
;
567 // Return if we have not any byte to read
568 if (BufferSizeInBytes
== 0) {
572 if (((Lba
* Instance
->Media
.BlockSize
) + Offset
+ BufferSizeInBytes
) > Instance
->Size
) {
573 DEBUG ((DEBUG_ERROR
, "NorFlashRead: ERROR - Read will exceed device size.\n"));
574 return EFI_INVALID_PARAMETER
;
577 // Get the address to start reading from
578 StartAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
,
580 Instance
->Media
.BlockSize
583 // Put the device into Read Array mode
584 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
587 AlignedCopyMem (Buffer
, (VOID
*)(StartAddress
+ Offset
), BufferSizeInBytes
);
593 Write a full or portion of a block. It must not span block boundaries; that is,
594 Offset + *NumBytes <= Instance->Media.BlockSize.
597 NorFlashWriteSingleBlock (
598 IN NOR_FLASH_INSTANCE
*Instance
,
601 IN OUT UINTN
*NumBytes
,
605 EFI_STATUS TempStatus
;
616 UINTN PrevBlockAddress
;
618 PrevBlockAddress
= 0;
620 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba
, Offset
, *NumBytes
, Buffer
));
622 // Detect WriteDisabled state
623 if (Instance
->Media
.ReadOnly
== TRUE
) {
624 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n"));
625 // It is in WriteDisabled state, return an error right away
626 return EFI_ACCESS_DENIED
;
629 // Cache the block size to avoid de-referencing pointers all the time
630 BlockSize
= Instance
->Media
.BlockSize
;
632 // The write must not span block boundaries.
633 // We need to check each variable individually because adding two large values together overflows.
634 if ( ( Offset
>= BlockSize
) ||
635 ( *NumBytes
> BlockSize
) ||
636 ( (Offset
+ *NumBytes
) > BlockSize
) ) {
637 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset
, *NumBytes
, BlockSize
));
638 return EFI_BAD_BUFFER_SIZE
;
641 // We must have some bytes to write
642 if (*NumBytes
== 0) {
643 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset
, *NumBytes
, BlockSize
));
644 return EFI_BAD_BUFFER_SIZE
;
647 // Pick 128bytes as a good start for word operations as opposed to erasing the
648 // block and writing the data regardless if an erase is really needed.
649 // It looks like most individual NV variable writes are smaller than 128bytes.
650 if (*NumBytes
<= 128) {
651 // Check to see if we need to erase before programming the data into NOR.
652 // If the destination bits are only changing from 1s to 0s we can just write.
653 // After a block is erased all bits in the block is set to 1.
654 // If any byte requires us to erase we just give up and rewrite all of it.
656 BytesToWrite
= *NumBytes
;
659 while (BytesToWrite
> 0) {
660 // Read full word from NOR, splice as required. A word is the smallest
661 // unit we can write.
662 TempStatus
= NorFlashRead (Instance
, Lba
, CurOffset
& ~(0x3), sizeof(Tmp
), &Tmp
);
663 if (EFI_ERROR (TempStatus
)) {
664 return EFI_DEVICE_ERROR
;
667 // Physical address of word in NOR to write.
668 WordAddr
= (CurOffset
& ~(0x3)) + GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
,
670 // The word of data that is to be written.
671 TmpBuf
= *((UINT32
*)(Buffer
+ (*NumBytes
- BytesToWrite
)));
673 // First do word aligned chunks.
674 if ((CurOffset
& 0x3) == 0) {
675 if (BytesToWrite
>= 4) {
676 // Is the destination still in 'erased' state?
678 // Check to see if we are only changing bits to zero.
679 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
684 // Write this word to NOR
685 WordToWrite
= TmpBuf
;
686 CurOffset
+= sizeof(TmpBuf
);
687 BytesToWrite
-= sizeof(TmpBuf
);
689 // BytesToWrite < 4. Do small writes and left-overs
690 Mask
= ~((~0) << (BytesToWrite
* 8));
691 // Mask out the bytes we want.
693 // Is the destination still in 'erased' state?
694 if ((Tmp
& Mask
) != Mask
) {
695 // Check to see if we are only changing bits to zero.
696 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
701 // Merge old and new data. Write merged word to NOR
702 WordToWrite
= (Tmp
& ~Mask
) | TmpBuf
;
703 CurOffset
+= BytesToWrite
;
707 // Do multiple words, but starting unaligned.
708 if (BytesToWrite
> (4 - (CurOffset
& 0x3))) {
709 Mask
= ((~0) << ((CurOffset
& 0x3) * 8));
710 // Mask out the bytes we want.
712 // Is the destination still in 'erased' state?
713 if ((Tmp
& Mask
) != Mask
) {
714 // Check to see if we are only changing bits to zero.
715 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
720 // Merge old and new data. Write merged word to NOR
721 WordToWrite
= (Tmp
& ~Mask
) | TmpBuf
;
722 BytesToWrite
-= (4 - (CurOffset
& 0x3));
723 CurOffset
+= (4 - (CurOffset
& 0x3));
725 // Unaligned and fits in one word.
726 Mask
= (~((~0) << (BytesToWrite
* 8))) << ((CurOffset
& 0x3) * 8);
727 // Mask out the bytes we want.
728 TmpBuf
= (TmpBuf
<< ((CurOffset
& 0x3) * 8)) & Mask
;
729 // Is the destination still in 'erased' state?
730 if ((Tmp
& Mask
) != Mask
) {
731 // Check to see if we are only changing bits to zero.
732 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
737 // Merge old and new data. Write merged word to NOR
738 WordToWrite
= (Tmp
& ~Mask
) | TmpBuf
;
739 CurOffset
+= BytesToWrite
;
745 // Write the word to NOR.
748 BlockAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
, Lba
, BlockSize
);
749 if (BlockAddress
!= PrevBlockAddress
) {
750 TempStatus
= NorFlashUnlockSingleBlockIfNecessary (Instance
, BlockAddress
);
751 if (EFI_ERROR (TempStatus
)) {
752 return EFI_DEVICE_ERROR
;
754 PrevBlockAddress
= BlockAddress
;
756 TempStatus
= NorFlashWriteSingleWord (Instance
, WordAddr
, WordToWrite
);
757 if (EFI_ERROR (TempStatus
)) {
758 return EFI_DEVICE_ERROR
;
761 // Exit if we got here and could write all the data. Otherwise do the
762 // Erase-Write cycle.
768 // Check we did get some memory. Buffer is BlockSize.
769 if (Instance
->ShadowBuffer
== NULL
) {
770 DEBUG ((DEBUG_ERROR
, "FvbWrite: ERROR - Buffer not ready\n"));
771 return EFI_DEVICE_ERROR
;
774 // Read NOR Flash data into shadow buffer
775 TempStatus
= NorFlashReadBlocks (Instance
, Lba
, BlockSize
, Instance
->ShadowBuffer
);
776 if (EFI_ERROR (TempStatus
)) {
777 // Return one of the pre-approved error statuses
778 return EFI_DEVICE_ERROR
;
781 // Put the data at the appropriate location inside the buffer area
782 CopyMem ((VOID
*)((UINTN
)Instance
->ShadowBuffer
+ Offset
), Buffer
, *NumBytes
);
784 // Write the modified buffer back to the NorFlash
785 TempStatus
= NorFlashWriteBlocks (Instance
, Lba
, BlockSize
, Instance
->ShadowBuffer
);
786 if (EFI_ERROR (TempStatus
)) {
787 // Return one of the pre-approved error statuses
788 return EFI_DEVICE_ERROR
;
795 Although DiskIoDxe will automatically install the DiskIO protocol whenever
796 we install the BlockIO protocol, its implementation is sub-optimal as it reads
797 and writes entire blocks using the BlockIO protocol. In fact we can access
798 NOR flash with a finer granularity than that, so we can improve performance
799 by directly producing the DiskIO protocol.
803 Read BufferSize bytes from Offset into Buffer.
805 @param This Protocol instance pointer.
806 @param MediaId Id of the media, changes every time the media is replaced.
807 @param Offset The starting byte offset to read from
808 @param BufferSize Size of Buffer
809 @param Buffer Buffer containing read data
811 @retval EFI_SUCCESS The data was read correctly from the device.
812 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
813 @retval EFI_NO_MEDIA There is no media in the device.
814 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
815 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
816 valid for the device.
821 NorFlashDiskIoReadDisk (
822 IN EFI_DISK_IO_PROTOCOL
*This
,
824 IN UINT64 DiskOffset
,
829 NOR_FLASH_INSTANCE
*Instance
;
834 Instance
= INSTANCE_FROM_DISKIO_THIS(This
);
836 if (MediaId
!= Instance
->Media
.MediaId
) {
837 return EFI_MEDIA_CHANGED
;
840 BlockSize
= Instance
->Media
.BlockSize
;
841 Lba
= (EFI_LBA
) DivU64x32Remainder (DiskOffset
, BlockSize
, &BlockOffset
);
843 return NorFlashRead (Instance
, Lba
, BlockOffset
, BufferSize
, Buffer
);
847 Writes a specified number of bytes to a device.
849 @param This Indicates a pointer to the calling context.
850 @param MediaId ID of the medium to be written.
851 @param Offset The starting byte offset on the logical block I/O device to write.
852 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
853 @param Buffer A pointer to the buffer containing the data to be written.
855 @retval EFI_SUCCESS The data was written correctly to the device.
856 @retval EFI_WRITE_PROTECTED The device can not be written to.
857 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
858 @retval EFI_NO_MEDIA There is no media in the device.
859 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
860 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
861 valid for the device.
866 NorFlashDiskIoWriteDisk (
867 IN EFI_DISK_IO_PROTOCOL
*This
,
869 IN UINT64 DiskOffset
,
874 NOR_FLASH_INSTANCE
*Instance
;
878 UINTN RemainingBytes
;
882 Instance
= INSTANCE_FROM_DISKIO_THIS(This
);
884 if (MediaId
!= Instance
->Media
.MediaId
) {
885 return EFI_MEDIA_CHANGED
;
888 BlockSize
= Instance
->Media
.BlockSize
;
889 Lba
= (EFI_LBA
) DivU64x32Remainder (DiskOffset
, BlockSize
, &BlockOffset
);
891 RemainingBytes
= BufferSize
;
893 // Write either all the remaining bytes, or the number of bytes that bring
894 // us up to a block boundary, whichever is less.
895 // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next
896 // block boundary (even if it is already on one).
897 WriteSize
= MIN (RemainingBytes
, ((DiskOffset
| (BlockSize
- 1)) + 1) - DiskOffset
);
900 if (WriteSize
== BlockSize
) {
901 // Write a full block
902 Status
= NorFlashWriteFullBlock (Instance
, Lba
, Buffer
, BlockSize
/ sizeof (UINT32
));
904 // Write a partial block
905 Status
= NorFlashWriteSingleBlock (Instance
, Lba
, BlockOffset
, &WriteSize
, Buffer
);
907 if (EFI_ERROR (Status
)) {
910 // Now continue writing either all the remaining bytes or single blocks.
911 RemainingBytes
-= WriteSize
;
912 Buffer
= (UINT8
*) Buffer
+ WriteSize
;
915 WriteSize
= MIN (RemainingBytes
, BlockSize
);
916 } while (RemainingBytes
);
923 IN NOR_FLASH_INSTANCE
*Instance
926 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
927 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
932 Fixup internal data so that EFI can be call in virtual mode.
933 Call the passed in Child Notify event and convert any pointers in
936 @param[in] Event The Event that is being processed
937 @param[in] Context Event Context
941 NorFlashVirtualNotifyEvent (
948 for (Index
= 0; Index
< mNorFlashDeviceCount
; Index
++) {
949 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->DeviceBaseAddress
);
950 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->RegionBaseAddress
);
952 // Convert BlockIo protocol
953 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.FlushBlocks
);
954 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.ReadBlocks
);
955 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.Reset
);
956 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.WriteBlocks
);
959 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.EraseBlocks
);
960 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetAttributes
);
961 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetBlockSize
);
962 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetPhysicalAddress
);
963 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Read
);
964 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.SetAttributes
);
965 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Write
);
967 if (mNorFlashInstances
[Index
]->ShadowBuffer
!= NULL
) {
968 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->ShadowBuffer
);