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>
12 #include "VirtNorFlash.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 // Request a lock setup
69 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_LOCK_BLOCK_SETUP
);
72 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_UNLOCK_BLOCK
);
74 // Wait until the status register gives us the all clear
76 LockStatus
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
77 } while ((LockStatus
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
79 // Put device back into Read Array mode
80 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_READ_ARRAY
);
82 DEBUG ((DEBUG_BLKIO
, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress
));
88 NorFlashUnlockSingleBlockIfNecessary (
89 IN NOR_FLASH_INSTANCE
*Instance
,
97 if (NorFlashBlockIsLocked (Instance
, BlockAddress
)) {
98 Status
= NorFlashUnlockSingleBlock (Instance
, BlockAddress
);
105 * The following function presumes that the block has already been unlocked.
108 NorFlashEraseSingleBlock (
109 IN NOR_FLASH_INSTANCE
*Instance
,
110 IN UINTN BlockAddress
114 UINT32 StatusRegister
;
116 Status
= EFI_SUCCESS
;
118 // Request a block erase and then confirm it
119 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_BLOCK_ERASE_SETUP
);
120 SEND_NOR_COMMAND (BlockAddress
, 0, P30_CMD_BLOCK_ERASE_CONFIRM
);
122 // Wait until the status register gives us the all clear
124 StatusRegister
= NorFlashReadStatusRegister (Instance
, BlockAddress
);
125 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
127 if (StatusRegister
& P30_SR_BIT_VPP
) {
128 DEBUG ((DEBUG_ERROR
, "EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress
));
129 Status
= EFI_DEVICE_ERROR
;
132 if ((StatusRegister
& (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) == (P30_SR_BIT_ERASE
| P30_SR_BIT_PROGRAM
)) {
133 DEBUG ((DEBUG_ERROR
, "EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress
));
134 Status
= EFI_DEVICE_ERROR
;
137 if (StatusRegister
& P30_SR_BIT_ERASE
) {
138 DEBUG ((DEBUG_ERROR
, "EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress
, StatusRegister
));
139 Status
= EFI_DEVICE_ERROR
;
142 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
143 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
144 DEBUG ((DEBUG_INFO
, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress
));
145 Status
= EFI_WRITE_PROTECTED
;
148 if (EFI_ERROR (Status
)) {
149 // Clear the Status Register
150 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
153 // Put device back into Read Array mode
154 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
160 NorFlashWriteSingleWord (
161 IN NOR_FLASH_INSTANCE
*Instance
,
162 IN UINTN WordAddress
,
167 UINT32 StatusRegister
;
169 Status
= EFI_SUCCESS
;
171 // Request a write single word command
172 SEND_NOR_COMMAND (WordAddress
, 0, P30_CMD_WORD_PROGRAM_SETUP
);
174 // Store the word into NOR Flash;
175 MmioWrite32 (WordAddress
, WriteData
);
177 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
179 // Prepare to read the status register
180 StatusRegister
= NorFlashReadStatusRegister (Instance
, WordAddress
);
181 // The chip is busy while the WRITE bit is not asserted
182 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
184 // Perform a full status check:
185 // Mask the relevant bits of Status Register.
186 // Everything should be zero, if not, we have a problem
188 if (StatusRegister
& P30_SR_BIT_VPP
) {
189 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n", WordAddress
));
190 Status
= EFI_DEVICE_ERROR
;
193 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
194 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n", WordAddress
));
195 Status
= EFI_DEVICE_ERROR
;
198 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
199 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n", WordAddress
));
200 Status
= EFI_DEVICE_ERROR
;
203 if (!EFI_ERROR (Status
)) {
204 // Clear the Status Register
205 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
212 * Writes data to the NOR Flash using the Buffered Programming method.
214 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
215 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
216 * To deal with larger buffers, call this function again.
218 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
219 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
221 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
222 * then programming time is doubled and power consumption is increased.
223 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
224 * i.e. the last 4 bits of the target start address must be zero: 0x......00
227 NorFlashWriteBuffer (
228 IN NOR_FLASH_INSTANCE
*Instance
,
229 IN UINTN TargetAddress
,
230 IN UINTN BufferSizeInBytes
,
235 UINTN BufferSizeInWords
;
237 volatile UINT32
*Data
;
239 BOOLEAN BufferAvailable
;
240 UINT32 StatusRegister
;
242 WaitForBuffer
= MAX_BUFFERED_PROG_ITERATIONS
;
243 BufferAvailable
= FALSE
;
245 // Check that the target address does not cross a 32-word boundary.
246 if ((TargetAddress
& BOUNDARY_OF_32_WORDS
) != 0) {
247 return EFI_INVALID_PARAMETER
;
250 // Check there are some data to program
251 if (BufferSizeInBytes
== 0) {
252 return EFI_BUFFER_TOO_SMALL
;
255 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
256 if (BufferSizeInBytes
> P30_MAX_BUFFER_SIZE_IN_BYTES
) {
257 return EFI_BAD_BUFFER_SIZE
;
260 // Check that the buffer size is a multiple of 32-bit words
261 if ((BufferSizeInBytes
% 4) != 0) {
262 return EFI_BAD_BUFFER_SIZE
;
265 // Pre-programming conditions checked, now start the algorithm.
267 // Prepare the data destination address
268 Data
= (UINT32
*)TargetAddress
;
270 // Check the availability of the buffer
272 // Issue the Buffered Program Setup command
273 SEND_NOR_COMMAND (TargetAddress
, 0, P30_CMD_BUFFERED_PROGRAM_SETUP
);
275 // Read back the status register bit#7 from the same address
276 if (((*Data
) & P30_SR_BIT_WRITE
) == P30_SR_BIT_WRITE
) {
277 BufferAvailable
= TRUE
;
280 // Update the loop counter
282 } while ((WaitForBuffer
> 0) && (BufferAvailable
== FALSE
));
284 // The buffer was not available for writing
285 if (WaitForBuffer
== 0) {
286 return EFI_DEVICE_ERROR
;
289 // From now on we work in 32-bit words
290 BufferSizeInWords
= BufferSizeInBytes
/ (UINTN
)4;
292 // Write the word count, which is (buffer_size_in_words - 1),
293 // because word count 0 means one word.
294 SEND_NOR_COMMAND (TargetAddress
, 0, (BufferSizeInWords
- 1));
296 // Write the data to the NOR Flash, advancing each address by 4 bytes
297 for (Count
= 0; Count
< BufferSizeInWords
; Count
++, Data
++, Buffer
++) {
298 MmioWrite32 ((UINTN
)Data
, *Buffer
);
301 // Issue the Buffered Program Confirm command, to start the programming operation
302 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM
);
304 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
306 StatusRegister
= NorFlashReadStatusRegister (Instance
, TargetAddress
);
307 // The chip is busy while the WRITE bit is not asserted
308 } while ((StatusRegister
& P30_SR_BIT_WRITE
) != P30_SR_BIT_WRITE
);
310 // Perform a full status check:
311 // Mask the relevant bits of Status Register.
312 // Everything should be zero, if not, we have a problem
314 Status
= EFI_SUCCESS
;
316 if (StatusRegister
& P30_SR_BIT_VPP
) {
317 DEBUG ((DEBUG_ERROR
, "NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress
));
318 Status
= EFI_DEVICE_ERROR
;
321 if (StatusRegister
& P30_SR_BIT_PROGRAM
) {
322 DEBUG ((DEBUG_ERROR
, "NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress
));
323 Status
= EFI_DEVICE_ERROR
;
326 if (StatusRegister
& P30_SR_BIT_BLOCK_LOCKED
) {
327 DEBUG ((DEBUG_ERROR
, "NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n", TargetAddress
));
328 Status
= EFI_DEVICE_ERROR
;
331 if (!EFI_ERROR (Status
)) {
332 // Clear the Status Register
333 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_CLEAR_STATUS_REGISTER
);
340 NorFlashWriteBlocks (
341 IN NOR_FLASH_INSTANCE
*Instance
,
343 IN UINTN BufferSizeInBytes
,
347 UINT32
*pWriteBuffer
;
349 EFI_LBA CurrentBlock
;
350 UINT32 BlockSizeInWords
;
354 Status
= EFI_SUCCESS
;
356 // The buffer must be valid
357 if (Buffer
== NULL
) {
358 return EFI_INVALID_PARAMETER
;
361 // We must have some bytes to read
362 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes
));
363 if (BufferSizeInBytes
== 0) {
364 return EFI_BAD_BUFFER_SIZE
;
367 // The size of the buffer must be a multiple of the block size
368 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance
->BlockSize
));
369 if ((BufferSizeInBytes
% Instance
->BlockSize
) != 0) {
370 return EFI_BAD_BUFFER_SIZE
;
373 // All blocks must be within the device
374 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->BlockSize
;
376 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks
, Instance
->LastBlock
, Lba
));
378 if ((Lba
+ NumBlocks
) > (Instance
->LastBlock
+ 1)) {
379 DEBUG ((DEBUG_ERROR
, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
380 return EFI_INVALID_PARAMETER
;
383 BlockSizeInWords
= Instance
->BlockSize
/ 4;
385 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
386 // to a proper data type, so use *ReadBuffer
387 pWriteBuffer
= (UINT32
*)Buffer
;
390 for (BlockCount
= 0; BlockCount
< NumBlocks
; BlockCount
++, CurrentBlock
++, pWriteBuffer
= pWriteBuffer
+ BlockSizeInWords
) {
391 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN
)CurrentBlock
));
393 Status
= NorFlashWriteFullBlock (Instance
, CurrentBlock
, pWriteBuffer
, BlockSizeInWords
);
395 if (EFI_ERROR (Status
)) {
400 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status
));
404 #define BOTH_ALIGNED(a, b, align) ((((UINTN)(a) | (UINTN)(b)) & ((align) - 1)) == 0)
407 Copy Length bytes from Source to Destination, using aligned accesses only.
408 Note that this implementation uses memcpy() semantics rather then memmove()
409 semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.
411 @param DestinationBuffer The target of the copy request.
412 @param SourceBuffer The place to copy from.
413 @param Length The number of bytes to copy.
421 OUT VOID
*DestinationBuffer
,
422 IN CONST VOID
*SourceBuffer
,
427 CONST UINT8
*Source8
;
428 UINT32
*Destination32
;
429 CONST UINT32
*Source32
;
430 UINT64
*Destination64
;
431 CONST UINT64
*Source64
;
433 if (BOTH_ALIGNED (DestinationBuffer
, SourceBuffer
, 8) && (Length
>= 8)) {
434 Destination64
= DestinationBuffer
;
435 Source64
= SourceBuffer
;
436 while (Length
>= 8) {
437 *Destination64
++ = *Source64
++;
441 Destination8
= (UINT8
*)Destination64
;
442 Source8
= (CONST UINT8
*)Source64
;
443 } else if (BOTH_ALIGNED (DestinationBuffer
, SourceBuffer
, 4) && (Length
>= 4)) {
444 Destination32
= DestinationBuffer
;
445 Source32
= SourceBuffer
;
446 while (Length
>= 4) {
447 *Destination32
++ = *Source32
++;
451 Destination8
= (UINT8
*)Destination32
;
452 Source8
= (CONST UINT8
*)Source32
;
454 Destination8
= DestinationBuffer
;
455 Source8
= SourceBuffer
;
458 while (Length
-- != 0) {
459 *Destination8
++ = *Source8
++;
462 return DestinationBuffer
;
467 IN NOR_FLASH_INSTANCE
*Instance
,
469 IN UINTN BufferSizeInBytes
,
478 "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
485 // The buffer must be valid
486 if (Buffer
== NULL
) {
487 return EFI_INVALID_PARAMETER
;
490 // Return if we have not any byte to read
491 if (BufferSizeInBytes
== 0) {
495 // The size of the buffer must be a multiple of the block size
496 if ((BufferSizeInBytes
% Instance
->BlockSize
) != 0) {
497 return EFI_BAD_BUFFER_SIZE
;
500 // All blocks must be within the device
501 NumBlocks
= ((UINT32
)BufferSizeInBytes
) / Instance
->BlockSize
;
503 if ((Lba
+ NumBlocks
) > (Instance
->LastBlock
+ 1)) {
504 DEBUG ((DEBUG_ERROR
, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
505 return EFI_INVALID_PARAMETER
;
508 // Get the address to start reading from
509 StartAddress
= GET_NOR_BLOCK_ADDRESS (
510 Instance
->RegionBaseAddress
,
515 // Put the device into Read Array mode
516 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
519 AlignedCopyMem (Buffer
, (VOID
*)StartAddress
, BufferSizeInBytes
);
526 IN NOR_FLASH_INSTANCE
*Instance
,
529 IN UINTN BufferSizeInBytes
,
535 // The buffer must be valid
536 if (Buffer
== NULL
) {
537 return EFI_INVALID_PARAMETER
;
540 // Return if we have not any byte to read
541 if (BufferSizeInBytes
== 0) {
545 if (((Lba
* Instance
->BlockSize
) + Offset
+ BufferSizeInBytes
) > Instance
->Size
) {
546 DEBUG ((DEBUG_ERROR
, "NorFlashRead: ERROR - Read will exceed device size.\n"));
547 return EFI_INVALID_PARAMETER
;
550 // Get the address to start reading from
551 StartAddress
= GET_NOR_BLOCK_ADDRESS (
552 Instance
->RegionBaseAddress
,
557 // Put the device into Read Array mode
558 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
561 AlignedCopyMem (Buffer
, (VOID
*)(StartAddress
+ Offset
), BufferSizeInBytes
);
567 Write a full or portion of a block. It must not span block boundaries; that is,
568 Offset + *NumBytes <= Instance->BlockSize.
571 NorFlashWriteSingleBlock (
572 IN NOR_FLASH_INSTANCE
*Instance
,
575 IN OUT UINTN
*NumBytes
,
585 DEBUG ((DEBUG_BLKIO
, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba
, Offset
, *NumBytes
, Buffer
));
587 // Check we did get some memory. Buffer is BlockSize.
588 if (Instance
->ShadowBuffer
== NULL
) {
589 DEBUG ((DEBUG_ERROR
, "FvbWrite: ERROR - Buffer not ready\n"));
590 return EFI_DEVICE_ERROR
;
593 // Cache the block size to avoid de-referencing pointers all the time
594 BlockSize
= Instance
->BlockSize
;
596 // The write must not span block boundaries.
597 // We need to check each variable individually because adding two large values together overflows.
598 if ((Offset
>= BlockSize
) ||
599 (*NumBytes
> BlockSize
) ||
600 ((Offset
+ *NumBytes
) > BlockSize
))
602 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset
, *NumBytes
, BlockSize
));
603 return EFI_BAD_BUFFER_SIZE
;
606 // We must have some bytes to write
607 if (*NumBytes
== 0) {
608 DEBUG ((DEBUG_ERROR
, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset
, *NumBytes
, BlockSize
));
609 return EFI_BAD_BUFFER_SIZE
;
612 // Pick P30_MAX_BUFFER_SIZE_IN_BYTES (== 128 bytes) as a good start for word
613 // operations as opposed to erasing the block and writing the data regardless
614 // if an erase is really needed. It looks like most individual NV variable
615 // writes are smaller than 128 bytes.
616 // To avoid pathological cases were a 2 byte write is disregarded because it
617 // occurs right at a 128 byte buffered write alignment boundary, permit up to
618 // twice the max buffer size, and perform two writes if needed.
619 if ((*NumBytes
+ (Offset
& BOUNDARY_OF_32_WORDS
)) <= (2 * P30_MAX_BUFFER_SIZE_IN_BYTES
)) {
620 // Check to see if we need to erase before programming the data into NOR.
621 // If the destination bits are only changing from 1s to 0s we can just write.
622 // After a block is erased all bits in the block is set to 1.
623 // If any byte requires us to erase we just give up and rewrite all of it.
625 // Read the old version of the data into the shadow buffer
626 Status
= NorFlashRead (
629 Offset
& ~BOUNDARY_OF_32_WORDS
,
630 (*NumBytes
| BOUNDARY_OF_32_WORDS
) + 1,
631 Instance
->ShadowBuffer
633 if (EFI_ERROR (Status
)) {
634 return EFI_DEVICE_ERROR
;
637 // Make OrigData point to the start of the old version of the data inside
638 // the word aligned buffer
639 OrigData
= Instance
->ShadowBuffer
+ (Offset
& BOUNDARY_OF_32_WORDS
);
641 // Update the buffer containing the old version of the data with the new
642 // contents, while checking whether the old version had any bits cleared
643 // that we want to set. In that case, we will need to erase the block first.
644 for (CurOffset
= 0; CurOffset
< *NumBytes
; CurOffset
++) {
645 if (~OrigData
[CurOffset
] & Buffer
[CurOffset
]) {
649 OrigData
[CurOffset
] = Buffer
[CurOffset
];
653 // Write the updated buffer to NOR.
655 BlockAddress
= GET_NOR_BLOCK_ADDRESS (Instance
->RegionBaseAddress
, Lba
, BlockSize
);
657 // Unlock the block if we have to
658 Status
= NorFlashUnlockSingleBlockIfNecessary (Instance
, BlockAddress
);
659 if (EFI_ERROR (Status
)) {
663 Status
= NorFlashWriteBuffer (
665 BlockAddress
+ (Offset
& ~BOUNDARY_OF_32_WORDS
),
666 P30_MAX_BUFFER_SIZE_IN_BYTES
,
667 Instance
->ShadowBuffer
669 if (EFI_ERROR (Status
)) {
673 if ((*NumBytes
+ (Offset
& BOUNDARY_OF_32_WORDS
)) > P30_MAX_BUFFER_SIZE_IN_BYTES
) {
674 BlockAddress
+= P30_MAX_BUFFER_SIZE_IN_BYTES
;
676 Status
= NorFlashWriteBuffer (
678 BlockAddress
+ (Offset
& ~BOUNDARY_OF_32_WORDS
),
679 P30_MAX_BUFFER_SIZE_IN_BYTES
,
680 Instance
->ShadowBuffer
+ P30_MAX_BUFFER_SIZE_IN_BYTES
685 // Put device back into Read Array mode
686 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
692 // Read NOR Flash data into shadow buffer
693 Status
= NorFlashReadBlocks (Instance
, Lba
, BlockSize
, Instance
->ShadowBuffer
);
694 if (EFI_ERROR (Status
)) {
695 // Return one of the pre-approved error statuses
696 return EFI_DEVICE_ERROR
;
699 // Put the data at the appropriate location inside the buffer area
700 CopyMem ((VOID
*)((UINTN
)Instance
->ShadowBuffer
+ Offset
), Buffer
, *NumBytes
);
702 // Write the modified buffer back to the NorFlash
703 Status
= NorFlashWriteBlocks (Instance
, Lba
, BlockSize
, Instance
->ShadowBuffer
);
704 if (EFI_ERROR (Status
)) {
705 // Return one of the pre-approved error statuses
706 return EFI_DEVICE_ERROR
;
714 IN NOR_FLASH_INSTANCE
*Instance
717 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
718 SEND_NOR_COMMAND (Instance
->DeviceBaseAddress
, 0, P30_CMD_READ_ARRAY
);
723 Fixup internal data so that EFI can be call in virtual mode.
724 Call the passed in Child Notify event and convert any pointers in
727 @param[in] Event The Event that is being processed
728 @param[in] Context Event Context
732 NorFlashVirtualNotifyEvent (
739 for (Index
= 0; Index
< mNorFlashDeviceCount
; Index
++) {
740 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->DeviceBaseAddress
);
741 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->RegionBaseAddress
);
744 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.EraseBlocks
);
745 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetAttributes
);
746 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetBlockSize
);
747 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.GetPhysicalAddress
);
748 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Read
);
749 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.SetAttributes
);
750 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->FvbProtocol
.Write
);
752 if (mNorFlashInstances
[Index
]->ShadowBuffer
!= NULL
) {
753 EfiConvertPointer (0x0, (VOID
**)&mNorFlashInstances
[Index
]->ShadowBuffer
);