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
);
124 * The following function presumes that the block has already been unlocked.
127 NorFlashEraseSingleBlock (
128 IN NOR_FLASH_INSTANCE
*Instance
,
129 IN UINTN BlockAddress
133 UINT32 StatusRegister
;
135 Status
= EFI_SUCCESS
;
137 // Request a block erase and then confirm it
138 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_BLOCK_ERASE_SETUP
);
139 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_BLOCK_ERASE_CONFIRM
);
141 // Wait until the status register gives us the all clear
143 StatusRegister
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
144 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
146 if (StatusRegister
& P30_SR_BIT_VPP
) {
147 DEBUG ((DEBUG_ERROR
, "EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress
));
148 Status
= EFI_DEVICE_ERROR
;
151 if ((StatusRegister
& (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) == (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) {
152 DEBUG ((DEBUG_ERROR
, "EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress
));
153 Status
= EFI_DEVICE_ERROR
;
156 if (StatusRegister
& P30_SR_BIT_ERASE
) {
157 DEBUG ((DEBUG_ERROR
, "EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress
, StatusRegister
));
158 Status
= EFI_DEVICE_ERROR
;
161 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
162 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
163 DEBUG ((DEBUG_INFO
, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress
));
164 Status
= EFI_WRITE_PROTECTED
;
167 if (EFI_ERROR (Status
)) {
168 // Clear the Status Register
169 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
172 // Put device back into Read Array mode
173 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
179 NorFlashWriteSingleWord (
180 IN NOR_FLASH_INSTANCE
*Instance
,
181 IN UINTN WordAddress
,
186 UINT32 StatusRegister
;
188 Status
= EFI_SUCCESS
;
190 // Request a write single word command
191 SEND_NOR_COMMAND (WordAddress
, 0, P30_CMD_WORD_PROGRAM_SETUP
);
193 // Store the word into NOR Flash;
194 MmioWrite32 (WordAddress
, WriteData
);
196 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
198 // Prepare to read the status register
199 StatusRegister
= NorFlashReadStatusRegister (Instance
, WordAddress
);
200 // The chip is busy while the WRITE bit is not asserted
201 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
203 // Perform a full status check:
204 // Mask the relevant bits of Status Register.
205 // Everything should be zero, if not, we have a problem
207 if (StatusRegister
& P30_SR_BIT_VPP
) {
208 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n", WordAddress
));
209 Status
= EFI_DEVICE_ERROR
;
212 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
213 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n", WordAddress
));
214 Status
= EFI_DEVICE_ERROR
;
217 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
218 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n", WordAddress
));
219 Status
= EFI_DEVICE_ERROR
;
222 if (!EFI_ERROR (Status
)) {
223 // Clear the Status Register
224 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
227 // Put device back into Read Array mode
228 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
234 * Writes data to the NOR Flash using the Buffered Programming method.
236 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
237 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
238 * To deal with larger buffers, call this function again.
240 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
241 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
243 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
244 * then programming time is doubled and power consumption is increased.
245 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
246 * i.e. the last 4 bits of the target start address must be zero: 0x......00
249 NorFlashWriteBuffer (
250 IN NOR_FLASH_INSTANCE
*Instance
,
251 IN UINTN TargetAddress
,
252 IN UINTN BufferSizeInBytes
,
257 UINTN BufferSizeInWords
;
259 volatile UINT32
*Data
;
261 BOOLEAN BufferAvailable
;
262 UINT32 StatusRegister
;
264 WaitForBuffer
= MAX_BUFFERED_PROG_ITERATIONS
;
265 BufferAvailable
= FALSE
;
267 // Check that the target address does not cross a 32-word boundary.
268 if ((TargetAddress
& BOUNDARY_OF_32_WORDS
) != 0) {
269 return EFI_INVALID_PARAMETER
;
272 // Check there are some data to program
273 if (BufferSizeInBytes
== 0) {
274 return EFI_BUFFER_TOO_SMALL
;
277 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
278 if (BufferSizeInBytes
> P30_MAX_BUFFER_SIZE_IN_BYTES
) {
279 return EFI_BAD_BUFFER_SIZE
;
282 // Check that the buffer size is a multiple of 32-bit words
283 if ((BufferSizeInBytes
% 4) != 0) {
284 return EFI_BAD_BUFFER_SIZE
;
287 // Pre-programming conditions checked, now start the algorithm.
289 // Prepare the data destination address
290 Data
= (UINT32
*)TargetAddress
;
292 // Check the availability of the buffer
294 // Issue the Buffered Program Setup command
295 SEND_NOR_COMMAND (TargetAddress
, 0, P30_CMD_BUFFERED_PROGRAM_SETUP
);
297 // Read back the status register bit#7 from the same address
298 if (((*Data
) & P30_SR_BIT_WRITE
) == P30_SR_BIT_WRITE
) {
299 BufferAvailable
= TRUE
;
302 // Update the loop counter
304 } while ((WaitForBuffer
> 0) && (BufferAvailable
== FALSE
));
306 // The buffer was not available for writing
307 if (WaitForBuffer
== 0) {
308 Status
= EFI_DEVICE_ERROR
;
312 // From now on we work in 32-bit words
313 BufferSizeInWords
= BufferSizeInBytes
/ (UINTN
)4;
315 // Write the word count, which is (buffer_size_in_words - 1),
316 // because word count 0 means one word.
317 SEND_NOR_COMMAND (TargetAddress
, 0, (BufferSizeInWords
- 1));
319 // Write the data to the NOR Flash, advancing each address by 4 bytes
320 for (Count
= 0; Count
< BufferSizeInWords
; Count
++, Data
++, Buffer
++) {
321 MmioWrite32 ((UINTN
)Data
, *Buffer
);
324 // Issue the Buffered Program Confirm command, to start the programming operation
325 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM
);
327 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
329 StatusRegister
= NorFlashReadStatusRegister (Instance
, TargetAddress
);
330 // The chip is busy while the WRITE bit is not asserted
331 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
333 // Perform a full status check:
334 // Mask the relevant bits of Status Register.
335 // Everything should be zero, if not, we have a problem
337 Status
= EFI_SUCCESS
;
339 if (StatusRegister
& P30_SR_BIT_VPP
) {
340 DEBUG ((DEBUG_ERROR
, "NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress
));
341 Status
= EFI_DEVICE_ERROR
;
344 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
345 DEBUG ((DEBUG_ERROR
, "NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress
));
346 Status
= EFI_DEVICE_ERROR
;
349 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
350 DEBUG ((DEBUG_ERROR
, "NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n", TargetAddress
));
351 Status
= EFI_DEVICE_ERROR
;
354 if (!EFI_ERROR (Status
)) {
355 // Clear the Status Register
356 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
360 // Put device back into Read Array mode
361 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
367 NorFlashWriteBlocks (
368 IN NOR_FLASH_INSTANCE
*Instance
,
370 IN UINTN BufferSizeInBytes
,
374 UINT32
*pWriteBuffer
;
376 EFI_LBA CurrentBlock
;
377 UINT32 BlockSizeInWords
;
381 Status
= EFI_SUCCESS
;
383 // The buffer must be valid
384 if (Buffer
== NULL
) {
385 return EFI_INVALID_PARAMETER
;
388 if (Instance
->Media
.ReadOnly
== TRUE
) {
389 return EFI_WRITE_PROTECTED
;
392 // We must have some bytes to read
393 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes
));
394 if (BufferSizeInBytes
== 0) {
395 return EFI_BAD_BUFFER_SIZE
;
398 // The size of the buffer must be a multiple of the block size
399 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance
->Media
.BlockSize
));
400 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
401 return EFI_BAD_BUFFER_SIZE
;
404 // All blocks must be within the device
405 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
407 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks
, Instance
->Media
.LastBlock
, Lba
));
409 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
410 DEBUG ((DEBUG_ERROR
, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
411 return EFI_INVALID_PARAMETER
;
414 BlockSizeInWords
= Instance
->Media
.BlockSize
/ 4;
416 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
417 // to a proper data type, so use *ReadBuffer
418 pWriteBuffer
= (UINT32
*)Buffer
;
421 for (BlockCount
= 0; BlockCount
< NumBlocks
; BlockCount
++, CurrentBlock
++, pWriteBuffer
= pWriteBuffer
+ BlockSizeInWords
) {
422 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN
)CurrentBlock
));
424 Status
= NorFlashWriteFullBlock (Instance
, CurrentBlock
, pWriteBuffer
, BlockSizeInWords
);
426 if (EFI_ERROR (Status
)) {
431 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status
));
435 #define BOTH_ALIGNED(a, b, align) ((((UINTN)(a) | (UINTN)(b)) & ((align) - 1)) == 0)
438 Copy Length bytes from Source to Destination, using aligned accesses only.
439 Note that this implementation uses memcpy() semantics rather then memmove()
440 semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.
442 @param DestinationBuffer The target of the copy request.
443 @param SourceBuffer The place to copy from.
444 @param Length The number of bytes to copy.
452 OUT VOID
*DestinationBuffer
,
453 IN CONST VOID
*SourceBuffer
,
458 CONST UINT8
*Source8
;
459 UINT32
*Destination32
;
460 CONST UINT32
*Source32
;
461 UINT64
*Destination64
;
462 CONST UINT64
*Source64
;
464 if (BOTH_ALIGNED (DestinationBuffer
, SourceBuffer
, 8) && (Length
>= 8)) {
465 Destination64
= DestinationBuffer
;
466 Source64
= SourceBuffer
;
467 while (Length
>= 8) {
468 *Destination64
++ = *Source64
++;
472 Destination8
= (UINT8
*)Destination64
;
473 Source8
= (CONST UINT8
*)Source64
;
474 } else if (BOTH_ALIGNED (DestinationBuffer
, SourceBuffer
, 4) && (Length
>= 4)) {
475 Destination32
= DestinationBuffer
;
476 Source32
= SourceBuffer
;
477 while (Length
>= 4) {
478 *Destination32
++ = *Source32
++;
482 Destination8
= (UINT8
*)Destination32
;
483 Source8
= (CONST UINT8
*)Source32
;
485 Destination8
= DestinationBuffer
;
486 Source8
= SourceBuffer
;
489 while (Length
-- != 0) {
490 *Destination8
++ = *Source8
++;
493 return DestinationBuffer
;
498 IN NOR_FLASH_INSTANCE
*Instance
,
500 IN UINTN BufferSizeInBytes
,
509 "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
511 Instance
->Media
.BlockSize
,
512 Instance
->Media
.LastBlock
,
516 // The buffer must be valid
517 if (Buffer
== NULL
) {
518 return EFI_INVALID_PARAMETER
;
521 // Return if we have not any byte to read
522 if (BufferSizeInBytes
== 0) {
526 // The size of the buffer must be a multiple of the block size
527 if ((BufferSizeInBytes
% Instance
->Media
.BlockSize
) != 0) {
528 return EFI_BAD_BUFFER_SIZE
;
531 // All blocks must be within the device
532 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->Media
.BlockSize
;
534 if ((Lba
+ NumBlocks
) > (Instance
->Media
.LastBlock
+ 1)) {
535 DEBUG ((DEBUG_ERROR
, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
536 return EFI_INVALID_PARAMETER
;
539 // Get the address to start reading from
540 StartAddress
= GET_NOR_BLOCK_ADDRESS (
541 Instance
->RegionBaseAddress
,
543 Instance
->Media
.BlockSize
546 // Put the device into Read Array mode
547 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
550 AlignedCopyMem (Buffer
, (VOID
*)StartAddress
, BufferSizeInBytes
);
557 IN NOR_FLASH_INSTANCE
*Instance
,
560 IN UINTN BufferSizeInBytes
,
566 // The buffer must be valid
567 if (Buffer
== NULL
) {
568 return EFI_INVALID_PARAMETER
;
571 // Return if we have not any byte to read
572 if (BufferSizeInBytes
== 0) {
576 if (((Lba
* Instance
->Media
.BlockSize
) + Offset
+ BufferSizeInBytes
) > Instance
->Size
) {
577 DEBUG ((DEBUG_ERROR
, "NorFlashRead: ERROR - Read will exceed device size.\n"));
578 return EFI_INVALID_PARAMETER
;
581 // Get the address to start reading from
582 StartAddress
= GET_NOR_BLOCK_ADDRESS (
583 Instance
->RegionBaseAddress
,
585 Instance
->Media
.BlockSize
588 // Put the device into Read Array mode
589 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
592 AlignedCopyMem (Buffer
, (VOID
*)(StartAddress
+ Offset
), BufferSizeInBytes
);
598 Write a full or portion of a block. It must not span block boundaries; that is,
599 Offset + *NumBytes <= Instance->Media.BlockSize.
602 NorFlashWriteSingleBlock (
603 IN NOR_FLASH_INSTANCE
*Instance
,
606 IN OUT UINTN
*NumBytes
,
610 EFI_STATUS TempStatus
;
621 UINTN PrevBlockAddress
;
623 PrevBlockAddress
= 0;
625 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba
, Offset
, *NumBytes
, Buffer
));
627 // Detect WriteDisabled state
628 if (Instance
->Media
.ReadOnly
== TRUE
) {
629 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n"));
630 // It is in WriteDisabled state, return an error right away
631 return EFI_ACCESS_DENIED
;
634 // Cache the block size to avoid de-referencing pointers all the time
635 BlockSize
= Instance
->Media
.BlockSize
;
637 // The write must not span block boundaries.
638 // We need to check each variable individually because adding two large values together overflows.
639 if ((Offset
>= BlockSize
) ||
640 (*NumBytes
> BlockSize
) ||
641 ((Offset
+ *NumBytes
) > BlockSize
))
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 // We must have some bytes to write
648 if (*NumBytes
== 0) {
649 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset
, *NumBytes
, BlockSize
));
650 return EFI_BAD_BUFFER_SIZE
;
653 // Pick 128bytes as a good start for word operations as opposed to erasing the
654 // block and writing the data regardless if an erase is really needed.
655 // It looks like most individual NV variable writes are smaller than 128bytes.
656 if (*NumBytes
<= 128) {
657 // Check to see if we need to erase before programming the data into NOR.
658 // If the destination bits are only changing from 1s to 0s we can just write.
659 // After a block is erased all bits in the block is set to 1.
660 // If any byte requires us to erase we just give up and rewrite all of it.
662 BytesToWrite
= *NumBytes
;
665 while (BytesToWrite
> 0) {
666 // Read full word from NOR, splice as required. A word is the smallest
667 // unit we can write.
668 TempStatus
= NorFlashRead (Instance
, Lba
, CurOffset
& ~(0x3), sizeof (Tmp
), &Tmp
);
669 if (EFI_ERROR (TempStatus
)) {
670 return EFI_DEVICE_ERROR
;
673 // Physical address of word in NOR to write.
674 WordAddr
= (CurOffset
& ~(0x3)) + GET_NOR_BLOCK_ADDRESS (
675 Instance
->RegionBaseAddress
,
679 // The word of data that is to be written.
680 TmpBuf
= *((UINT32
*)(Buffer
+ (*NumBytes
- BytesToWrite
)));
682 // First do word aligned chunks.
683 if ((CurOffset
& 0x3) == 0) {
684 if (BytesToWrite
>= 4) {
685 // Is the destination still in 'erased' state?
687 // Check to see if we are only changing bits to zero.
688 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
694 // Write this word to NOR
695 WordToWrite
= TmpBuf
;
696 CurOffset
+= sizeof (TmpBuf
);
697 BytesToWrite
-= sizeof (TmpBuf
);
699 // BytesToWrite < 4. Do small writes and left-overs
700 Mask
= ~((~0) << (BytesToWrite
* 8));
701 // Mask out the bytes we want.
703 // Is the destination still in 'erased' state?
704 if ((Tmp
& Mask
) != Mask
) {
705 // Check to see if we are only changing bits to zero.
706 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
712 // Merge old and new data. Write merged word to NOR
713 WordToWrite
= (Tmp
& ~Mask
) | TmpBuf
;
714 CurOffset
+= BytesToWrite
;
718 // Do multiple words, but starting unaligned.
719 if (BytesToWrite
> (4 - (CurOffset
& 0x3))) {
720 Mask
= ((~0) << ((CurOffset
& 0x3) * 8));
721 // Mask out the bytes we want.
723 // Is the destination still in 'erased' state?
724 if ((Tmp
& Mask
) != Mask
) {
725 // Check to see if we are only changing bits to zero.
726 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
732 // Merge old and new data. Write merged word to NOR
733 WordToWrite
= (Tmp
& ~Mask
) | TmpBuf
;
734 BytesToWrite
-= (4 - (CurOffset
& 0x3));
735 CurOffset
+= (4 - (CurOffset
& 0x3));
737 // Unaligned and fits in one word.
738 Mask
= (~((~0) << (BytesToWrite
* 8))) << ((CurOffset
& 0x3) * 8);
739 // Mask out the bytes we want.
740 TmpBuf
= (TmpBuf
<< ((CurOffset
& 0x3) * 8)) & Mask
;
741 // Is the destination still in 'erased' state?
742 if ((Tmp
& Mask
) != Mask
) {
743 // Check to see if we are only changing bits to zero.
744 if ((Tmp
^ TmpBuf
) & TmpBuf
) {
750 // Merge old and new data. Write merged word to NOR
751 WordToWrite
= (Tmp
& ~Mask
) | TmpBuf
;
752 CurOffset
+= BytesToWrite
;
758 // Write the word to NOR.
761 BlockAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
, Lba
, BlockSize
);
762 if (BlockAddress
!= PrevBlockAddress
) {
763 TempStatus
= NorFlashUnlockSingleBlockIfNecessary (Instance
, BlockAddress
);
764 if (EFI_ERROR (TempStatus
)) {
765 return EFI_DEVICE_ERROR
;
768 PrevBlockAddress
= BlockAddress
;
771 TempStatus
= NorFlashWriteSingleWord (Instance
, WordAddr
, WordToWrite
);
772 if (EFI_ERROR (TempStatus
)) {
773 return EFI_DEVICE_ERROR
;
777 // Exit if we got here and could write all the data. Otherwise do the
778 // Erase-Write cycle.
784 // Check we did get some memory. Buffer is BlockSize.
785 if (Instance
->ShadowBuffer
== NULL
) {
786 DEBUG ((DEBUG_ERROR
, "FvbWrite: ERROR - Buffer not ready\n"));
787 return EFI_DEVICE_ERROR
;
790 // Read NOR Flash data into shadow buffer
791 TempStatus
= NorFlashReadBlocks (Instance
, Lba
, BlockSize
, Instance
->ShadowBuffer
);
792 if (EFI_ERROR (TempStatus
)) {
793 // Return one of the pre-approved error statuses
794 return EFI_DEVICE_ERROR
;
797 // Put the data at the appropriate location inside the buffer area
798 CopyMem ((VOID
*)((UINTN
)Instance
->ShadowBuffer
+ Offset
), Buffer
, *NumBytes
);
800 // Write the modified buffer back to the NorFlash
801 TempStatus
= NorFlashWriteBlocks (Instance
, Lba
, BlockSize
, Instance
->ShadowBuffer
);
802 if (EFI_ERROR (TempStatus
)) {
803 // Return one of the pre-approved error statuses
804 return EFI_DEVICE_ERROR
;
811 Although DiskIoDxe will automatically install the DiskIO protocol whenever
812 we install the BlockIO protocol, its implementation is sub-optimal as it reads
813 and writes entire blocks using the BlockIO protocol. In fact we can access
814 NOR flash with a finer granularity than that, so we can improve performance
815 by directly producing the DiskIO protocol.
819 Read BufferSize bytes from Offset into Buffer.
821 @param This Protocol instance pointer.
822 @param MediaId Id of the media, changes every time the media is replaced.
823 @param Offset The starting byte offset to read from
824 @param BufferSize Size of Buffer
825 @param Buffer Buffer containing read data
827 @retval EFI_SUCCESS The data was read correctly from the device.
828 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
829 @retval EFI_NO_MEDIA There is no media in the device.
830 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
831 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
832 valid for the device.
837 NorFlashDiskIoReadDisk (
838 IN EFI_DISK_IO_PROTOCOL
*This
,
840 IN UINT64 DiskOffset
,
845 NOR_FLASH_INSTANCE
*Instance
;
850 Instance
= INSTANCE_FROM_DISKIO_THIS (This
);
852 if (MediaId
!= Instance
->Media
.MediaId
) {
853 return EFI_MEDIA_CHANGED
;
856 BlockSize
= Instance
->Media
.BlockSize
;
857 Lba
= (EFI_LBA
)DivU64x32Remainder (DiskOffset
, BlockSize
, &BlockOffset
);
859 return NorFlashRead (Instance
, Lba
, BlockOffset
, BufferSize
, Buffer
);
863 Writes a specified number of bytes to a device.
865 @param This Indicates a pointer to the calling context.
866 @param MediaId ID of the medium to be written.
867 @param Offset The starting byte offset on the logical block I/O device to write.
868 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
869 @param Buffer A pointer to the buffer containing the data to be written.
871 @retval EFI_SUCCESS The data was written correctly to the device.
872 @retval EFI_WRITE_PROTECTED The device can not be written to.
873 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
874 @retval EFI_NO_MEDIA There is no media in the device.
875 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
876 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
877 valid for the device.
882 NorFlashDiskIoWriteDisk (
883 IN EFI_DISK_IO_PROTOCOL
*This
,
885 IN UINT64 DiskOffset
,
890 NOR_FLASH_INSTANCE
*Instance
;
894 UINTN RemainingBytes
;
898 Instance
= INSTANCE_FROM_DISKIO_THIS (This
);
900 if (MediaId
!= Instance
->Media
.MediaId
) {
901 return EFI_MEDIA_CHANGED
;
904 BlockSize
= Instance
->Media
.BlockSize
;
905 Lba
= (EFI_LBA
)DivU64x32Remainder (DiskOffset
, BlockSize
, &BlockOffset
);
907 RemainingBytes
= BufferSize
;
909 // Write either all the remaining bytes, or the number of bytes that bring
910 // us up to a block boundary, whichever is less.
911 // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next
912 // block boundary (even if it is already on one).
913 WriteSize
= MIN (RemainingBytes
, ((DiskOffset
| (BlockSize
- 1)) + 1) - DiskOffset
);
916 if (WriteSize
== BlockSize
) {
917 // Write a full block
918 Status
= NorFlashWriteFullBlock (Instance
, Lba
, Buffer
, BlockSize
/ sizeof (UINT32
));
920 // Write a partial block
921 Status
= NorFlashWriteSingleBlock (Instance
, Lba
, BlockOffset
, &WriteSize
, Buffer
);
924 if (EFI_ERROR (Status
)) {
928 // Now continue writing either all the remaining bytes or single blocks.
929 RemainingBytes
-= WriteSize
;
930 Buffer
= (UINT8
*)Buffer
+ WriteSize
;
933 WriteSize
= MIN (RemainingBytes
, BlockSize
);
934 } while (RemainingBytes
);
941 IN NOR_FLASH_INSTANCE
*Instance
944 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
945 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
950 Fixup internal data so that EFI can be call in virtual mode.
951 Call the passed in Child Notify event and convert any pointers in
954 @param[in] Event The Event that is being processed
955 @param[in] Context Event Context
959 NorFlashVirtualNotifyEvent (
966 for (Index
= 0; Index
< mNorFlashDeviceCount
; Index
++) {
967 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->DeviceBaseAddress
);
968 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->RegionBaseAddress
);
970 // Convert BlockIo protocol
971 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.FlushBlocks
);
972 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.ReadBlocks
);
973 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.Reset
);
974 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->BlockIoProtocol
.WriteBlocks
);
977 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.EraseBlocks
);
978 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetAttributes
);
979 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetBlockSize
);
980 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetPhysicalAddress
);
981 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Read
);
982 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.SetAttributes
);
983 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Write
);
985 if (mNorFlashInstances
[Index
]->ShadowBuffer
!= NULL
) {
986 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->ShadowBuffer
);