TianoCore EDK2 master
Loading...
Searching...
No Matches
VirtNorFlash.c
1
11
12#include "VirtNorFlash.h"
13
14//
15// Global variable declarations
16//
17extern NOR_FLASH_INSTANCE **mNorFlashInstances;
18extern UINT32 mNorFlashDeviceCount;
19
20UINT32
21NorFlashReadStatusRegister (
22 IN NOR_FLASH_INSTANCE *Instance,
23 IN UINTN SR_Address
24 )
25{
26 // Prepare to read the status register
27 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);
28 return MmioRead32 (Instance->DeviceBaseAddress);
29}
30
32BOOLEAN
33NorFlashBlockIsLocked (
34 IN NOR_FLASH_INSTANCE *Instance,
35 IN UINTN BlockAddress
36 )
37{
38 UINT32 LockStatus;
39
40 // Send command for reading device id
41 SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
42
43 // Read block lock status
44 LockStatus = MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));
45
46 // Decode block lock status
47 LockStatus = FOLD_32BIT_INTO_16BIT (LockStatus);
48
49 if ((LockStatus & 0x2) != 0) {
50 DEBUG ((DEBUG_ERROR, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
51 }
52
53 return ((LockStatus & 0x1) != 0);
54}
55
58NorFlashUnlockSingleBlock (
59 IN NOR_FLASH_INSTANCE *Instance,
60 IN UINTN BlockAddress
61 )
62{
63 UINT32 LockStatus;
64
65 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
66 // and to protect shared data structures.
67
68 // Request a lock setup
69 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
70
71 // Request an unlock
72 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
73
74 // Wait until the status register gives us the all clear
75 do {
76 LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress);
77 } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
78
79 // Put device back into Read Array mode
80 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);
81
82 DEBUG ((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress));
83
84 return EFI_SUCCESS;
85}
86
88NorFlashUnlockSingleBlockIfNecessary (
89 IN NOR_FLASH_INSTANCE *Instance,
90 IN UINTN BlockAddress
91 )
92{
93 EFI_STATUS Status;
94
95 Status = EFI_SUCCESS;
96
97 if (NorFlashBlockIsLocked (Instance, BlockAddress)) {
98 Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
99 }
100
101 return Status;
102}
103
108NorFlashEraseSingleBlock (
109 IN NOR_FLASH_INSTANCE *Instance,
110 IN UINTN BlockAddress
111 )
112{
113 EFI_STATUS Status;
114 UINT32 StatusRegister;
115
116 Status = EFI_SUCCESS;
117
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);
121
122 // Wait until the status register gives us the all clear
123 do {
124 StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress);
125 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
126
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;
130 }
131
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;
135 }
136
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;
140 }
141
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;
146 }
147
148 if (EFI_ERROR (Status)) {
149 // Clear the Status Register
150 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
151 }
152
153 // Put device back into Read Array mode
154 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
155
156 return Status;
157}
158
160NorFlashWriteSingleWord (
161 IN NOR_FLASH_INSTANCE *Instance,
162 IN UINTN WordAddress,
163 IN UINT32 WriteData
164 )
165{
166 EFI_STATUS Status;
167 UINT32 StatusRegister;
168
169 Status = EFI_SUCCESS;
170
171 // Request a write single word command
172 SEND_NOR_COMMAND (WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);
173
174 // Store the word into NOR Flash;
175 MmioWrite32 (WordAddress, WriteData);
176
177 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
178 do {
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);
183
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
187
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;
191 }
192
193 if (StatusRegister & P30_SR_BIT_PROGRAM) {
194 DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n", WordAddress));
195 Status = EFI_DEVICE_ERROR;
196 }
197
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;
201 }
202
203 if (!EFI_ERROR (Status)) {
204 // Clear the Status Register
205 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
206 }
207
208 return Status;
209}
210
211/*
212 * Writes data to the NOR Flash using the Buffered Programming method.
213 *
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.
217 *
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.
220 *
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
225 */
227NorFlashWriteBuffer (
228 IN NOR_FLASH_INSTANCE *Instance,
229 IN UINTN TargetAddress,
230 IN UINTN BufferSizeInBytes,
231 IN UINT32 *Buffer
232 )
233{
234 EFI_STATUS Status;
235 UINTN BufferSizeInWords;
236 UINTN Count;
237 volatile UINT32 *Data;
238 UINTN WaitForBuffer;
239 BOOLEAN BufferAvailable;
240 UINT32 StatusRegister;
241
242 WaitForBuffer = MAX_BUFFERED_PROG_ITERATIONS;
243 BufferAvailable = FALSE;
244
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;
248 }
249
250 // Check there are some data to program
251 if (BufferSizeInBytes == 0) {
252 return EFI_BUFFER_TOO_SMALL;
253 }
254
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;
258 }
259
260 // Check that the buffer size is a multiple of 32-bit words
261 if ((BufferSizeInBytes % 4) != 0) {
262 return EFI_BAD_BUFFER_SIZE;
263 }
264
265 // Pre-programming conditions checked, now start the algorithm.
266
267 // Prepare the data destination address
268 Data = (UINT32 *)TargetAddress;
269
270 // Check the availability of the buffer
271 do {
272 // Issue the Buffered Program Setup command
273 SEND_NOR_COMMAND (TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);
274
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;
278 }
279
280 // Update the loop counter
281 WaitForBuffer--;
282 } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE));
283
284 // The buffer was not available for writing
285 if (WaitForBuffer == 0) {
286 return EFI_DEVICE_ERROR;
287 }
288
289 // From now on we work in 32-bit words
290 BufferSizeInWords = BufferSizeInBytes / (UINTN)4;
291
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));
295
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);
299 }
300
301 // Issue the Buffered Program Confirm command, to start the programming operation
302 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
303
304 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
305 do {
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);
309
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
313
314 Status = EFI_SUCCESS;
315
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;
319 }
320
321 if (StatusRegister & P30_SR_BIT_PROGRAM) {
322 DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress));
323 Status = EFI_DEVICE_ERROR;
324 }
325
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;
329 }
330
331 if (!EFI_ERROR (Status)) {
332 // Clear the Status Register
333 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
334 }
335
336 return Status;
337}
338
340NorFlashWriteBlocks (
341 IN NOR_FLASH_INSTANCE *Instance,
342 IN EFI_LBA Lba,
343 IN UINTN BufferSizeInBytes,
344 IN VOID *Buffer
345 )
346{
347 UINT32 *pWriteBuffer;
348 EFI_STATUS Status;
349 EFI_LBA CurrentBlock;
350 UINT32 BlockSizeInWords;
351 UINT32 NumBlocks;
352 UINT32 BlockCount;
353
354 Status = EFI_SUCCESS;
355
356 // The buffer must be valid
357 if (Buffer == NULL) {
358 return EFI_INVALID_PARAMETER;
359 }
360
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;
365 }
366
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;
371 }
372
373 // All blocks must be within the device
374 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
375
376 DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->LastBlock, Lba));
377
378 if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
379 DEBUG ((DEBUG_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
380 return EFI_INVALID_PARAMETER;
381 }
382
383 BlockSizeInWords = Instance->BlockSize / 4;
384
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;
388
389 CurrentBlock = Lba;
390 for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) {
391 DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock));
392
393 Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, BlockSizeInWords);
394
395 if (EFI_ERROR (Status)) {
396 break;
397 }
398 }
399
400 DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
401 return Status;
402}
403
405NorFlashReadBlocks (
406 IN NOR_FLASH_INSTANCE *Instance,
407 IN EFI_LBA Lba,
408 IN UINTN BufferSizeInBytes,
409 OUT VOID *Buffer
410 )
411{
412 UINT32 NumBlocks;
413 UINTN StartAddress;
414
415 DEBUG ((
416 DEBUG_BLKIO,
417 "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
418 BufferSizeInBytes,
419 Instance->BlockSize,
420 Instance->LastBlock,
421 Lba
422 ));
423
424 // The buffer must be valid
425 if (Buffer == NULL) {
426 return EFI_INVALID_PARAMETER;
427 }
428
429 // Return if we have not any byte to read
430 if (BufferSizeInBytes == 0) {
431 return EFI_SUCCESS;
432 }
433
434 // The size of the buffer must be a multiple of the block size
435 if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
436 return EFI_BAD_BUFFER_SIZE;
437 }
438
439 // All blocks must be within the device
440 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
441
442 if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
443 DEBUG ((DEBUG_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
444 return EFI_INVALID_PARAMETER;
445 }
446
447 // Get the address to start reading from
448 StartAddress = GET_NOR_BLOCK_ADDRESS (
449 Instance->RegionBaseAddress,
450 Lba,
451 Instance->BlockSize
452 );
453
454 // Put the device into Read Array mode
455 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
456
457 // Readout the data
458 CopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);
459
460 return EFI_SUCCESS;
461}
462
464NorFlashRead (
465 IN NOR_FLASH_INSTANCE *Instance,
466 IN EFI_LBA Lba,
467 IN UINTN Offset,
468 IN UINTN BufferSizeInBytes,
469 OUT VOID *Buffer
470 )
471{
472 UINTN StartAddress;
473
474 // The buffer must be valid
475 if (Buffer == NULL) {
476 return EFI_INVALID_PARAMETER;
477 }
478
479 // Return if we have not any byte to read
480 if (BufferSizeInBytes == 0) {
481 return EFI_SUCCESS;
482 }
483
484 if (((Lba * Instance->BlockSize) + Offset + BufferSizeInBytes) > Instance->Size) {
485 DEBUG ((DEBUG_ERROR, "NorFlashRead: ERROR - Read will exceed device size.\n"));
486 return EFI_INVALID_PARAMETER;
487 }
488
489 // Get the address to start reading from
490 StartAddress = GET_NOR_BLOCK_ADDRESS (
491 Instance->RegionBaseAddress,
492 Lba,
493 Instance->BlockSize
494 );
495
496 // Put the device into Read Array mode
497 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
498
499 // Readout the data
500 CopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
501
502 return EFI_SUCCESS;
503}
504
505STATIC
507NorFlashWriteSingleBlockWithErase (
508 IN NOR_FLASH_INSTANCE *Instance,
509 IN EFI_LBA Lba,
510 IN UINTN Offset,
511 IN OUT UINTN *NumBytes,
512 IN UINT8 *Buffer
513 )
514{
515 EFI_STATUS Status;
516
517 // Read NOR Flash data into shadow buffer
518 Status = NorFlashReadBlocks (Instance, Lba, Instance->BlockSize, Instance->ShadowBuffer);
519 if (EFI_ERROR (Status)) {
520 // Return one of the pre-approved error statuses
521 return EFI_DEVICE_ERROR;
522 }
523
524 // Put the data at the appropriate location inside the buffer area
525 CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
526
527 // Write the modified buffer back to the NorFlash
528 Status = NorFlashWriteBlocks (Instance, Lba, Instance->BlockSize, Instance->ShadowBuffer);
529 if (EFI_ERROR (Status)) {
530 // Return one of the pre-approved error statuses
531 return EFI_DEVICE_ERROR;
532 }
533
534 return EFI_SUCCESS;
535}
536
537/*
538 Write a full or portion of a block. It must not span block boundaries; that is,
539 Offset + *NumBytes <= Instance->BlockSize.
540*/
542NorFlashWriteSingleBlock (
543 IN NOR_FLASH_INSTANCE *Instance,
544 IN EFI_LBA Lba,
545 IN UINTN Offset,
546 IN OUT UINTN *NumBytes,
547 IN UINT8 *Buffer
548 )
549{
550 EFI_STATUS Status;
551 UINTN CurOffset;
552 UINTN BlockSize;
553 UINTN BlockAddress;
554 UINT8 *OrigData;
555 UINTN Start, End;
556 UINT32 Index, Count;
557
558 DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));
559
560 // Check we did get some memory. Buffer is BlockSize.
561 if (Instance->ShadowBuffer == NULL) {
562 DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
563 return EFI_DEVICE_ERROR;
564 }
565
566 // Cache the block size to avoid de-referencing pointers all the time
567 BlockSize = Instance->BlockSize;
568
569 // The write must not span block boundaries.
570 // We need to check each variable individually because adding two large values together overflows.
571 if ((Offset >= BlockSize) ||
572 (*NumBytes > BlockSize) ||
573 ((Offset + *NumBytes) > BlockSize))
574 {
575 DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));
576 return EFI_BAD_BUFFER_SIZE;
577 }
578
579 // We must have some bytes to write
580 if (*NumBytes == 0) {
581 DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));
582 return EFI_BAD_BUFFER_SIZE;
583 }
584
585 // Pick 4 * P30_MAX_BUFFER_SIZE_IN_BYTES (== 512 bytes) as a good
586 // start for word operations as opposed to erasing the block and
587 // writing the data regardless if an erase is really needed.
588 //
589 // Many NV variable updates are small enough for a a single
590 // P30_MAX_BUFFER_SIZE_IN_BYTES block write. In case the update is
591 // larger than a single block, or the update crosses a
592 // P30_MAX_BUFFER_SIZE_IN_BYTES boundary (as shown in the diagram
593 // below), or both, we might have to write two or more blocks.
594 //
595 // 0 128 256
596 // [----------------|----------------]
597 // ^ ^ ^ ^
598 // | | | |
599 // | | | End, the next "word" boundary beyond
600 // | | | the (logical) update
601 // | | |
602 // | | (Offset & BOUNDARY_OF_32_WORDS) + NumBytes;
603 // | | i.e., the relative offset inside (or just past)
604 // | | the *double-word* such that it is the
605 // | | *exclusive* end of the (logical) update.
606 // | |
607 // | Offset & BOUNDARY_OF_32_WORDS; i.e., Offset within the "word";
608 // | this is where the (logical) update is supposed to start
609 // |
610 // Start = Offset & ~BOUNDARY_OF_32_WORDS; i.e., Offset truncated to "word" boundary
611
612 Start = Offset & ~BOUNDARY_OF_32_WORDS;
613 End = ALIGN_VALUE (Offset + *NumBytes, P30_MAX_BUFFER_SIZE_IN_BYTES);
614
615 if ((End - Start) <= (4 * P30_MAX_BUFFER_SIZE_IN_BYTES)) {
616 // Check to see if we need to erase before programming the data into NOR.
617 // If the destination bits are only changing from 1s to 0s we can just write.
618 // After a block is erased all bits in the block is set to 1.
619 // If any byte requires us to erase we just give up and rewrite all of it.
620
621 // Read the old version of the data into the shadow buffer
622 Status = NorFlashRead (
623 Instance,
624 Lba,
625 Start,
626 End - Start,
627 Instance->ShadowBuffer
628 );
629 if (EFI_ERROR (Status)) {
630 return EFI_DEVICE_ERROR;
631 }
632
633 // Make OrigData point to the start of the old version of the data inside
634 // the word aligned buffer
635 OrigData = Instance->ShadowBuffer + (Offset & BOUNDARY_OF_32_WORDS);
636
637 // Update the buffer containing the old version of the data with the new
638 // contents, while checking whether the old version had any bits cleared
639 // that we want to set. In that case, we will need to erase the block first.
640 for (CurOffset = 0; CurOffset < *NumBytes; CurOffset++) {
641 if (~(UINT32)OrigData[CurOffset] & (UINT32)Buffer[CurOffset]) {
642 Status = NorFlashWriteSingleBlockWithErase (
643 Instance,
644 Lba,
645 Offset,
646 NumBytes,
647 Buffer
648 );
649 return Status;
650 }
651
652 OrigData[CurOffset] = Buffer[CurOffset];
653 }
654
655 //
656 // Write the updated buffer to NOR.
657 //
658 BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize);
659
660 // Unlock the block if we have to
661 Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
662 if (EFI_ERROR (Status)) {
663 goto Exit;
664 }
665
666 Count = (End - Start) / P30_MAX_BUFFER_SIZE_IN_BYTES;
667 for (Index = 0; Index < Count; Index++) {
668 Status = NorFlashWriteBuffer (
669 Instance,
670 BlockAddress + Start + Index * P30_MAX_BUFFER_SIZE_IN_BYTES,
671 P30_MAX_BUFFER_SIZE_IN_BYTES,
672 Instance->ShadowBuffer + Index * P30_MAX_BUFFER_SIZE_IN_BYTES
673 );
674 if (EFI_ERROR (Status)) {
675 goto Exit;
676 }
677 }
678 } else {
679 Status = NorFlashWriteSingleBlockWithErase (
680 Instance,
681 Lba,
682 Offset,
683 NumBytes,
684 Buffer
685 );
686 return Status;
687 }
688
689Exit:
690 // Put device back into Read Array mode
691 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
692
693 return Status;
694}
695
697NorFlashReset (
698 IN NOR_FLASH_INSTANCE *Instance
699 )
700{
701 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
702 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
703 return EFI_SUCCESS;
704}
705
714VOID
715EFIAPI
716NorFlashVirtualNotifyEvent (
717 IN EFI_EVENT Event,
718 IN VOID *Context
719 )
720{
721 UINTN Index;
722
723 for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
724 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress);
725 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress);
726
727 // Convert Fvb
728 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
729 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
730 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
731 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
732 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read);
733 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
734 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write);
735
736 if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
737 EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowBuffer);
738 }
739 }
740
741 return;
742}
UINT64 UINTN
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
UINT32 EFIAPI MmioRead32(IN UINTN Address)
Definition: IoLib.c:262
UINT32 EFIAPI MmioWrite32(IN UINTN Address, IN UINT32 Value)
Definition: IoLib.c:309
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define ALIGN_VALUE(Value, Alignment)
Definition: Base.h:948
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
VOID EFIAPI Exit(IN EFI_STATUS Status)
UINT64 EFI_LBA
Definition: UefiBaseType.h:45
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_STATUS EFIAPI EfiConvertPointer(IN UINTN DebugDisposition, IN OUT VOID **Address)
Definition: RuntimeLib.c:561