]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
ArmPlatformPkg: Fix various typos
[mirror_edk2.git] / ArmPlatformPkg / Drivers / NorFlashDxe / NorFlashDxe.c
1 /** @file NorFlashDxe.c
2
3 Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Library/UefiLib.h>
10 #include <Library/BaseMemoryLib.h>
11 #include <Library/MemoryAllocationLib.h>
12 #include <Library/UefiBootServicesTableLib.h>
13 #include <Library/PcdLib.h>
14
15 #include "NorFlashDxe.h"
16
17 STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent;
18
19 //
20 // Global variable declarations
21 //
22 NOR_FLASH_INSTANCE **mNorFlashInstances;
23 UINT32 mNorFlashDeviceCount;
24
25 NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {
26 NOR_FLASH_SIGNATURE, // Signature
27 NULL, // Handle ... NEED TO BE FILLED
28
29 0, // DeviceBaseAddress ... NEED TO BE FILLED
30 0, // RegionBaseAddress ... NEED TO BE FILLED
31 0, // Size ... NEED TO BE FILLED
32 0, // StartLba
33
34 {
35 EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision
36 NULL, // Media ... NEED TO BE FILLED
37 NorFlashBlockIoReset, // Reset;
38 NorFlashBlockIoReadBlocks, // ReadBlocks
39 NorFlashBlockIoWriteBlocks, // WriteBlocks
40 NorFlashBlockIoFlushBlocks // FlushBlocks
41 }, // BlockIoProtocol
42
43 {
44 0, // MediaId ... NEED TO BE FILLED
45 FALSE, // RemovableMedia
46 TRUE, // MediaPresent
47 FALSE, // LogicalPartition
48 FALSE, // ReadOnly
49 FALSE, // WriteCaching;
50 0, // BlockSize ... NEED TO BE FILLED
51 4, // IoAlign
52 0, // LastBlock ... NEED TO BE FILLED
53 0, // LowestAlignedLba
54 1, // LogicalBlocksPerPhysicalBlock
55 }, //Media;
56
57 {
58 EFI_DISK_IO_PROTOCOL_REVISION, // Revision
59 NorFlashDiskIoReadDisk, // ReadDisk
60 NorFlashDiskIoWriteDisk // WriteDisk
61 },
62
63 {
64 FvbGetAttributes, // GetAttributes
65 FvbSetAttributes, // SetAttributes
66 FvbGetPhysicalAddress, // GetPhysicalAddress
67 FvbGetBlockSize, // GetBlockSize
68 FvbRead, // Read
69 FvbWrite, // Write
70 FvbEraseBlocks, // EraseBlocks
71 NULL, //ParentHandle
72 }, // FvbProtoccol;
73 NULL, // ShadowBuffer
74 {
75 {
76 {
77 HARDWARE_DEVICE_PATH,
78 HW_VENDOR_DP,
79 {
80 (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),
81 (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)
82 }
83 },
84 { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }, // GUID ... NEED TO BE FILLED
85 },
86 0, // Index
87 {
88 END_DEVICE_PATH_TYPE,
89 END_ENTIRE_DEVICE_PATH_SUBTYPE,
90 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
91 }
92 } // DevicePath
93 };
94
95 EFI_STATUS
96 NorFlashCreateInstance (
97 IN UINTN NorFlashDeviceBase,
98 IN UINTN NorFlashRegionBase,
99 IN UINTN NorFlashSize,
100 IN UINT32 Index,
101 IN UINT32 BlockSize,
102 IN BOOLEAN SupportFvb,
103 OUT NOR_FLASH_INSTANCE** NorFlashInstance
104 )
105 {
106 EFI_STATUS Status;
107 NOR_FLASH_INSTANCE* Instance;
108
109 ASSERT(NorFlashInstance != NULL);
110
111 Instance = AllocateRuntimeCopyPool (sizeof(NOR_FLASH_INSTANCE),&mNorFlashInstanceTemplate);
112 if (Instance == NULL) {
113 return EFI_OUT_OF_RESOURCES;
114 }
115
116 Instance->DeviceBaseAddress = NorFlashDeviceBase;
117 Instance->RegionBaseAddress = NorFlashRegionBase;
118 Instance->Size = NorFlashSize;
119
120 Instance->BlockIoProtocol.Media = &Instance->Media;
121 Instance->Media.MediaId = Index;
122 Instance->Media.BlockSize = BlockSize;
123 Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1;
124
125 CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);
126 Instance->DevicePath.Index = (UINT8)Index;
127
128 Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);;
129 if (Instance->ShadowBuffer == NULL) {
130 return EFI_OUT_OF_RESOURCES;
131 }
132
133 if (SupportFvb) {
134 NorFlashFvbInitialize (Instance);
135
136 Status = gBS->InstallMultipleProtocolInterfaces (
137 &Instance->Handle,
138 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
139 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
140 &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol,
141 NULL
142 );
143 if (EFI_ERROR(Status)) {
144 FreePool (Instance);
145 return Status;
146 }
147 } else {
148 Status = gBS->InstallMultipleProtocolInterfaces (
149 &Instance->Handle,
150 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
151 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
152 &gEfiDiskIoProtocolGuid, &Instance->DiskIoProtocol,
153 NULL
154 );
155 if (EFI_ERROR(Status)) {
156 FreePool (Instance);
157 return Status;
158 }
159 }
160
161 *NorFlashInstance = Instance;
162 return Status;
163 }
164
165 UINT32
166 NorFlashReadStatusRegister (
167 IN NOR_FLASH_INSTANCE *Instance,
168 IN UINTN SR_Address
169 )
170 {
171 // Prepare to read the status register
172 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);
173 return MmioRead32 (Instance->DeviceBaseAddress);
174 }
175
176 STATIC
177 BOOLEAN
178 NorFlashBlockIsLocked (
179 IN NOR_FLASH_INSTANCE *Instance,
180 IN UINTN BlockAddress
181 )
182 {
183 UINT32 LockStatus;
184
185 // Send command for reading device id
186 SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
187
188 // Read block lock status
189 LockStatus = MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress, 2));
190
191 // Decode block lock status
192 LockStatus = FOLD_32BIT_INTO_16BIT(LockStatus);
193
194 if ((LockStatus & 0x2) != 0) {
195 DEBUG((EFI_D_ERROR, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
196 }
197
198 return ((LockStatus & 0x1) != 0);
199 }
200
201 STATIC
202 EFI_STATUS
203 NorFlashUnlockSingleBlock (
204 IN NOR_FLASH_INSTANCE *Instance,
205 IN UINTN BlockAddress
206 )
207 {
208 UINT32 LockStatus;
209
210 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
211 // and to protect shared data structures.
212
213 if (FeaturePcdGet (PcdNorFlashCheckBlockLocked) == TRUE) {
214 do {
215 // Request a lock setup
216 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
217
218 // Request an unlock
219 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
220
221 // Send command for reading device id
222 SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
223
224 // Read block lock status
225 LockStatus = MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress, 2));
226
227 // Decode block lock status
228 LockStatus = FOLD_32BIT_INTO_16BIT(LockStatus);
229 } while ((LockStatus & 0x1) == 1);
230 } else {
231 // Request a lock setup
232 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
233
234 // Request an unlock
235 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
236
237 // Wait until the status register gives us the all clear
238 do {
239 LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress);
240 } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
241 }
242
243 // Put device back into Read Array mode
244 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);
245
246 DEBUG((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress));
247
248 return EFI_SUCCESS;
249 }
250
251 STATIC
252 EFI_STATUS
253 NorFlashUnlockSingleBlockIfNecessary (
254 IN NOR_FLASH_INSTANCE *Instance,
255 IN UINTN BlockAddress
256 )
257 {
258 EFI_STATUS Status;
259
260 Status = EFI_SUCCESS;
261
262 if (NorFlashBlockIsLocked (Instance, BlockAddress) == TRUE) {
263 Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
264 }
265
266 return Status;
267 }
268
269
270 /**
271 * The following function presumes that the block has already been unlocked.
272 **/
273 STATIC
274 EFI_STATUS
275 NorFlashEraseSingleBlock (
276 IN NOR_FLASH_INSTANCE *Instance,
277 IN UINTN BlockAddress
278 )
279 {
280 EFI_STATUS Status;
281 UINT32 StatusRegister;
282
283 Status = EFI_SUCCESS;
284
285 // Request a block erase and then confirm it
286 SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);
287 SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);
288
289 // Wait until the status register gives us the all clear
290 do {
291 StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress);
292 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
293
294 if (StatusRegister & P30_SR_BIT_VPP) {
295 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress));
296 Status = EFI_DEVICE_ERROR;
297 }
298
299 if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) == (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) {
300 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress));
301 Status = EFI_DEVICE_ERROR;
302 }
303
304 if (StatusRegister & P30_SR_BIT_ERASE) {
305 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister));
306 Status = EFI_DEVICE_ERROR;
307 }
308
309 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
310 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
311 DEBUG((EFI_D_INFO,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress));
312 Status = EFI_WRITE_PROTECTED;
313 }
314
315 if (EFI_ERROR(Status)) {
316 // Clear the Status Register
317 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
318 }
319
320 // Put device back into Read Array mode
321 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
322
323 return Status;
324 }
325
326 /**
327 * This function unlock and erase an entire NOR Flash block.
328 **/
329 EFI_STATUS
330 NorFlashUnlockAndEraseSingleBlock (
331 IN NOR_FLASH_INSTANCE *Instance,
332 IN UINTN BlockAddress
333 )
334 {
335 EFI_STATUS Status;
336 UINTN Index;
337 EFI_TPL OriginalTPL;
338
339 if (!EfiAtRuntime ()) {
340 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
341 OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
342 } else {
343 // This initialization is only to prevent the compiler to complain about the
344 // use of uninitialized variables
345 OriginalTPL = TPL_HIGH_LEVEL;
346 }
347
348 Index = 0;
349 // The block erase might fail a first time (SW bug ?). Retry it ...
350 do {
351 // Unlock the block if we have to
352 Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
353 if (EFI_ERROR (Status)) {
354 break;
355 }
356 Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
357 Index++;
358 } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
359
360 if (Index == NOR_FLASH_ERASE_RETRY) {
361 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress,Index));
362 }
363
364 if (!EfiAtRuntime ()) {
365 // Interruptions can resume.
366 gBS->RestoreTPL (OriginalTPL);
367 }
368
369 return Status;
370 }
371
372
373 STATIC
374 EFI_STATUS
375 NorFlashWriteSingleWord (
376 IN NOR_FLASH_INSTANCE *Instance,
377 IN UINTN WordAddress,
378 IN UINT32 WriteData
379 )
380 {
381 EFI_STATUS Status;
382 UINT32 StatusRegister;
383
384 Status = EFI_SUCCESS;
385
386 // Request a write single word command
387 SEND_NOR_COMMAND(WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);
388
389 // Store the word into NOR Flash;
390 MmioWrite32 (WordAddress, WriteData);
391
392 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
393 do {
394 // Prepare to read the status register
395 StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress);
396 // The chip is busy while the WRITE bit is not asserted
397 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
398
399
400 // Perform a full status check:
401 // Mask the relevant bits of Status Register.
402 // Everything should be zero, if not, we have a problem
403
404 if (StatusRegister & P30_SR_BIT_VPP) {
405 DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n",WordAddress));
406 Status = EFI_DEVICE_ERROR;
407 }
408
409 if (StatusRegister & P30_SR_BIT_PROGRAM) {
410 DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n",WordAddress));
411 Status = EFI_DEVICE_ERROR;
412 }
413
414 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
415 DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n",WordAddress));
416 Status = EFI_DEVICE_ERROR;
417 }
418
419 if (!EFI_ERROR(Status)) {
420 // Clear the Status Register
421 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
422 }
423
424 // Put device back into Read Array mode
425 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
426
427 return Status;
428 }
429
430 /*
431 * Writes data to the NOR Flash using the Buffered Programming method.
432 *
433 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
434 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
435 * To deal with larger buffers, call this function again.
436 *
437 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
438 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
439 *
440 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
441 * then programming time is doubled and power consumption is increased.
442 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
443 * i.e. the last 4 bits of the target start address must be zero: 0x......00
444 */
445 EFI_STATUS
446 NorFlashWriteBuffer (
447 IN NOR_FLASH_INSTANCE *Instance,
448 IN UINTN TargetAddress,
449 IN UINTN BufferSizeInBytes,
450 IN UINT32 *Buffer
451 )
452 {
453 EFI_STATUS Status;
454 UINTN BufferSizeInWords;
455 UINTN Count;
456 volatile UINT32 *Data;
457 UINTN WaitForBuffer;
458 BOOLEAN BufferAvailable;
459 UINT32 StatusRegister;
460
461 WaitForBuffer = MAX_BUFFERED_PROG_ITERATIONS;
462 BufferAvailable = FALSE;
463
464 // Check that the target address does not cross a 32-word boundary.
465 if ((TargetAddress & BOUNDARY_OF_32_WORDS) != 0) {
466 return EFI_INVALID_PARAMETER;
467 }
468
469 // Check there are some data to program
470 if (BufferSizeInBytes == 0) {
471 return EFI_BUFFER_TOO_SMALL;
472 }
473
474 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
475 if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) {
476 return EFI_BAD_BUFFER_SIZE;
477 }
478
479 // Check that the buffer size is a multiple of 32-bit words
480 if ((BufferSizeInBytes % 4) != 0) {
481 return EFI_BAD_BUFFER_SIZE;
482 }
483
484 // Pre-programming conditions checked, now start the algorithm.
485
486 // Prepare the data destination address
487 Data = (UINT32 *)TargetAddress;
488
489 // Check the availability of the buffer
490 do {
491 // Issue the Buffered Program Setup command
492 SEND_NOR_COMMAND(TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);
493
494 // Read back the status register bit#7 from the same address
495 if (((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE) {
496 BufferAvailable = TRUE;
497 }
498
499 // Update the loop counter
500 WaitForBuffer--;
501
502 } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE));
503
504 // The buffer was not available for writing
505 if (WaitForBuffer == 0) {
506 Status = EFI_DEVICE_ERROR;
507 goto EXIT;
508 }
509
510 // From now on we work in 32-bit words
511 BufferSizeInWords = BufferSizeInBytes / (UINTN)4;
512
513 // Write the word count, which is (buffer_size_in_words - 1),
514 // because word count 0 means one word.
515 SEND_NOR_COMMAND(TargetAddress, 0, (BufferSizeInWords - 1));
516
517 // Write the data to the NOR Flash, advancing each address by 4 bytes
518 for(Count=0; Count < BufferSizeInWords; Count++, Data++, Buffer++) {
519 MmioWrite32 ((UINTN)Data, *Buffer);
520 }
521
522 // Issue the Buffered Program Confirm command, to start the programming operation
523 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
524
525 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
526 do {
527 StatusRegister = NorFlashReadStatusRegister (Instance, TargetAddress);
528 // The chip is busy while the WRITE bit is not asserted
529 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
530
531
532 // Perform a full status check:
533 // Mask the relevant bits of Status Register.
534 // Everything should be zero, if not, we have a problem
535
536 Status = EFI_SUCCESS;
537
538 if (StatusRegister & P30_SR_BIT_VPP) {
539 DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress));
540 Status = EFI_DEVICE_ERROR;
541 }
542
543 if (StatusRegister & P30_SR_BIT_PROGRAM) {
544 DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress));
545 Status = EFI_DEVICE_ERROR;
546 }
547
548 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
549 DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n",TargetAddress));
550 Status = EFI_DEVICE_ERROR;
551 }
552
553 if (!EFI_ERROR(Status)) {
554 // Clear the Status Register
555 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
556 }
557
558 EXIT:
559 // Put device back into Read Array mode
560 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
561
562 return Status;
563 }
564
565 STATIC
566 EFI_STATUS
567 NorFlashWriteFullBlock (
568 IN NOR_FLASH_INSTANCE *Instance,
569 IN EFI_LBA Lba,
570 IN UINT32 *DataBuffer,
571 IN UINT32 BlockSizeInWords
572 )
573 {
574 EFI_STATUS Status;
575 UINTN WordAddress;
576 UINT32 WordIndex;
577 UINTN BufferIndex;
578 UINTN BlockAddress;
579 UINTN BuffersInBlock;
580 UINTN RemainingWords;
581 EFI_TPL OriginalTPL;
582 UINTN Cnt;
583
584 Status = EFI_SUCCESS;
585
586 // Get the physical address of the block
587 BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4);
588
589 // Start writing from the first address at the start of the block
590 WordAddress = BlockAddress;
591
592 if (!EfiAtRuntime ()) {
593 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
594 OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
595 } else {
596 // This initialization is only to prevent the compiler to complain about the
597 // use of uninitialized variables
598 OriginalTPL = TPL_HIGH_LEVEL;
599 }
600
601 Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
602 if (EFI_ERROR(Status)) {
603 DEBUG((EFI_D_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));
604 goto EXIT;
605 }
606
607 // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
608
609 // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
610 if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {
611
612 // First, break the entire block into buffer-sized chunks.
613 BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;
614
615 // Then feed each buffer chunk to the NOR Flash
616 // If a buffer does not contain any data, don't write it.
617 for(BufferIndex=0;
618 BufferIndex < BuffersInBlock;
619 BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS
620 ) {
621 // Check the buffer to see if it contains any data (not set all 1s).
622 for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {
623 if (~DataBuffer[Cnt] != 0 ) {
624 // Some data found, write the buffer.
625 Status = NorFlashWriteBuffer (Instance, WordAddress, P30_MAX_BUFFER_SIZE_IN_BYTES,
626 DataBuffer);
627 if (EFI_ERROR(Status)) {
628 goto EXIT;
629 }
630 break;
631 }
632 }
633 }
634
635 // Finally, finish off any remaining words that are less than the maximum size of the buffer
636 RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;
637
638 if(RemainingWords != 0) {
639 Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer);
640 if (EFI_ERROR(Status)) {
641 goto EXIT;
642 }
643 }
644
645 } else {
646 // For now, use the single word programming algorithm
647 // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
648 // i.e. which ends in the range 0x......01 - 0x......7F.
649 for(WordIndex=0; WordIndex<BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {
650 Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
651 if (EFI_ERROR(Status)) {
652 goto EXIT;
653 }
654 }
655 }
656
657 EXIT:
658 if (!EfiAtRuntime ()) {
659 // Interruptions can resume.
660 gBS->RestoreTPL (OriginalTPL);
661 }
662
663 if (EFI_ERROR(Status)) {
664 DEBUG((EFI_D_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));
665 }
666 return Status;
667 }
668
669
670 EFI_STATUS
671 NorFlashWriteBlocks (
672 IN NOR_FLASH_INSTANCE *Instance,
673 IN EFI_LBA Lba,
674 IN UINTN BufferSizeInBytes,
675 IN VOID *Buffer
676 )
677 {
678 UINT32 *pWriteBuffer;
679 EFI_STATUS Status = EFI_SUCCESS;
680 EFI_LBA CurrentBlock;
681 UINT32 BlockSizeInWords;
682 UINT32 NumBlocks;
683 UINT32 BlockCount;
684
685 // The buffer must be valid
686 if (Buffer == NULL) {
687 return EFI_INVALID_PARAMETER;
688 }
689
690 if(Instance->Media.ReadOnly == TRUE) {
691 return EFI_WRITE_PROTECTED;
692 }
693
694 // We must have some bytes to read
695 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes));
696 if(BufferSizeInBytes == 0) {
697 return EFI_BAD_BUFFER_SIZE;
698 }
699
700 // The size of the buffer must be a multiple of the block size
701 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance->Media.BlockSize));
702 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
703 return EFI_BAD_BUFFER_SIZE;
704 }
705
706 // All blocks must be within the device
707 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
708
709 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->Media.LastBlock, Lba));
710
711 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
712 DEBUG((EFI_D_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
713 return EFI_INVALID_PARAMETER;
714 }
715
716 BlockSizeInWords = Instance->Media.BlockSize / 4;
717
718 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
719 // to a proper data type, so use *ReadBuffer
720 pWriteBuffer = (UINT32 *)Buffer;
721
722 CurrentBlock = Lba;
723 for (BlockCount=0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) {
724
725 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock));
726
727 Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, BlockSizeInWords);
728
729 if (EFI_ERROR(Status)) {
730 break;
731 }
732 }
733
734 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
735 return Status;
736 }
737
738 #define BOTH_ALIGNED(a, b, align) ((((UINTN)(a) | (UINTN)(b)) & ((align) - 1)) == 0)
739
740 /**
741 Copy Length bytes from Source to Destination, using aligned accesses only.
742 Note that this implementation uses memcpy() semantics rather then memmove()
743 semantics, i.e., SourceBuffer and DestinationBuffer should not overlap.
744
745 @param DestinationBuffer The target of the copy request.
746 @param SourceBuffer The place to copy from.
747 @param Length The number of bytes to copy.
748
749 @return Destination
750
751 **/
752 STATIC
753 VOID *
754 AlignedCopyMem (
755 OUT VOID *DestinationBuffer,
756 IN CONST VOID *SourceBuffer,
757 IN UINTN Length
758 )
759 {
760 UINT8 *Destination8;
761 CONST UINT8 *Source8;
762 UINT32 *Destination32;
763 CONST UINT32 *Source32;
764 UINT64 *Destination64;
765 CONST UINT64 *Source64;
766
767 if (BOTH_ALIGNED(DestinationBuffer, SourceBuffer, 8) && Length >= 8) {
768 Destination64 = DestinationBuffer;
769 Source64 = SourceBuffer;
770 while (Length >= 8) {
771 *Destination64++ = *Source64++;
772 Length -= 8;
773 }
774
775 Destination8 = (UINT8 *)Destination64;
776 Source8 = (CONST UINT8 *)Source64;
777 } else if (BOTH_ALIGNED(DestinationBuffer, SourceBuffer, 4) && Length >= 4) {
778 Destination32 = DestinationBuffer;
779 Source32 = SourceBuffer;
780 while (Length >= 4) {
781 *Destination32++ = *Source32++;
782 Length -= 4;
783 }
784
785 Destination8 = (UINT8 *)Destination32;
786 Source8 = (CONST UINT8 *)Source32;
787 } else {
788 Destination8 = DestinationBuffer;
789 Source8 = SourceBuffer;
790 }
791 while (Length-- != 0) {
792 *Destination8++ = *Source8++;
793 }
794 return DestinationBuffer;
795 }
796
797 EFI_STATUS
798 NorFlashReadBlocks (
799 IN NOR_FLASH_INSTANCE *Instance,
800 IN EFI_LBA Lba,
801 IN UINTN BufferSizeInBytes,
802 OUT VOID *Buffer
803 )
804 {
805 UINT32 NumBlocks;
806 UINTN StartAddress;
807
808 DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
809 BufferSizeInBytes, Instance->Media.BlockSize, Instance->Media.LastBlock, Lba));
810
811 // The buffer must be valid
812 if (Buffer == NULL) {
813 return EFI_INVALID_PARAMETER;
814 }
815
816 // Return if we have not any byte to read
817 if (BufferSizeInBytes == 0) {
818 return EFI_SUCCESS;
819 }
820
821 // The size of the buffer must be a multiple of the block size
822 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
823 return EFI_BAD_BUFFER_SIZE;
824 }
825
826 // All blocks must be within the device
827 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
828
829 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
830 DEBUG((EFI_D_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
831 return EFI_INVALID_PARAMETER;
832 }
833
834 // Get the address to start reading from
835 StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress,
836 Lba,
837 Instance->Media.BlockSize
838 );
839
840 // Put the device into Read Array mode
841 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
842
843 // Readout the data
844 AlignedCopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);
845
846 return EFI_SUCCESS;
847 }
848
849 EFI_STATUS
850 NorFlashRead (
851 IN NOR_FLASH_INSTANCE *Instance,
852 IN EFI_LBA Lba,
853 IN UINTN Offset,
854 IN UINTN BufferSizeInBytes,
855 OUT VOID *Buffer
856 )
857 {
858 UINTN StartAddress;
859
860 // The buffer must be valid
861 if (Buffer == NULL) {
862 return EFI_INVALID_PARAMETER;
863 }
864
865 // Return if we have not any byte to read
866 if (BufferSizeInBytes == 0) {
867 return EFI_SUCCESS;
868 }
869
870 if (((Lba * Instance->Media.BlockSize) + Offset + BufferSizeInBytes) > Instance->Size) {
871 DEBUG ((EFI_D_ERROR, "NorFlashRead: ERROR - Read will exceed device size.\n"));
872 return EFI_INVALID_PARAMETER;
873 }
874
875 // Get the address to start reading from
876 StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress,
877 Lba,
878 Instance->Media.BlockSize
879 );
880
881 // Put the device into Read Array mode
882 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
883
884 // Readout the data
885 AlignedCopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
886
887 return EFI_SUCCESS;
888 }
889
890 /*
891 Write a full or portion of a block. It must not span block boundaries; that is,
892 Offset + *NumBytes <= Instance->Media.BlockSize.
893 */
894 EFI_STATUS
895 NorFlashWriteSingleBlock (
896 IN NOR_FLASH_INSTANCE *Instance,
897 IN EFI_LBA Lba,
898 IN UINTN Offset,
899 IN OUT UINTN *NumBytes,
900 IN UINT8 *Buffer
901 )
902 {
903 EFI_STATUS TempStatus;
904 UINT32 Tmp;
905 UINT32 TmpBuf;
906 UINT32 WordToWrite;
907 UINT32 Mask;
908 BOOLEAN DoErase;
909 UINTN BytesToWrite;
910 UINTN CurOffset;
911 UINTN WordAddr;
912 UINTN BlockSize;
913 UINTN BlockAddress;
914 UINTN PrevBlockAddress;
915
916 PrevBlockAddress = 0;
917
918 DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));
919
920 // Detect WriteDisabled state
921 if (Instance->Media.ReadOnly == TRUE) {
922 DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n"));
923 // It is in WriteDisabled state, return an error right away
924 return EFI_ACCESS_DENIED;
925 }
926
927 // Cache the block size to avoid de-referencing pointers all the time
928 BlockSize = Instance->Media.BlockSize;
929
930 // The write must not span block boundaries.
931 // We need to check each variable individually because adding two large values together overflows.
932 if ( ( Offset >= BlockSize ) ||
933 ( *NumBytes > BlockSize ) ||
934 ( (Offset + *NumBytes) > BlockSize ) ) {
935 DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
936 return EFI_BAD_BUFFER_SIZE;
937 }
938
939 // We must have some bytes to write
940 if (*NumBytes == 0) {
941 DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));
942 return EFI_BAD_BUFFER_SIZE;
943 }
944
945 // Pick 128bytes as a good start for word operations as opposed to erasing the
946 // block and writing the data regardless if an erase is really needed.
947 // It looks like most individual NV variable writes are smaller than 128bytes.
948 if (*NumBytes <= 128) {
949 // Check to see if we need to erase before programming the data into NOR.
950 // If the destination bits are only changing from 1s to 0s we can just write.
951 // After a block is erased all bits in the block is set to 1.
952 // If any byte requires us to erase we just give up and rewrite all of it.
953 DoErase = FALSE;
954 BytesToWrite = *NumBytes;
955 CurOffset = Offset;
956
957 while (BytesToWrite > 0) {
958 // Read full word from NOR, splice as required. A word is the smallest
959 // unit we can write.
960 TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof(Tmp), &Tmp);
961 if (EFI_ERROR (TempStatus)) {
962 return EFI_DEVICE_ERROR;
963 }
964
965 // Physical address of word in NOR to write.
966 WordAddr = (CurOffset & ~(0x3)) + GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress,
967 Lba, BlockSize);
968 // The word of data that is to be written.
969 TmpBuf = *((UINT32*)(Buffer + (*NumBytes - BytesToWrite)));
970
971 // First do word aligned chunks.
972 if ((CurOffset & 0x3) == 0) {
973 if (BytesToWrite >= 4) {
974 // Is the destination still in 'erased' state?
975 if (~Tmp != 0) {
976 // Check to see if we are only changing bits to zero.
977 if ((Tmp ^ TmpBuf) & TmpBuf) {
978 DoErase = TRUE;
979 break;
980 }
981 }
982 // Write this word to NOR
983 WordToWrite = TmpBuf;
984 CurOffset += sizeof(TmpBuf);
985 BytesToWrite -= sizeof(TmpBuf);
986 } else {
987 // BytesToWrite < 4. Do small writes and left-overs
988 Mask = ~((~0) << (BytesToWrite * 8));
989 // Mask out the bytes we want.
990 TmpBuf &= Mask;
991 // Is the destination still in 'erased' state?
992 if ((Tmp & Mask) != Mask) {
993 // Check to see if we are only changing bits to zero.
994 if ((Tmp ^ TmpBuf) & TmpBuf) {
995 DoErase = TRUE;
996 break;
997 }
998 }
999 // Merge old and new data. Write merged word to NOR
1000 WordToWrite = (Tmp & ~Mask) | TmpBuf;
1001 CurOffset += BytesToWrite;
1002 BytesToWrite = 0;
1003 }
1004 } else {
1005 // Do multiple words, but starting unaligned.
1006 if (BytesToWrite > (4 - (CurOffset & 0x3))) {
1007 Mask = ((~0) << ((CurOffset & 0x3) * 8));
1008 // Mask out the bytes we want.
1009 TmpBuf &= Mask;
1010 // Is the destination still in 'erased' state?
1011 if ((Tmp & Mask) != Mask) {
1012 // Check to see if we are only changing bits to zero.
1013 if ((Tmp ^ TmpBuf) & TmpBuf) {
1014 DoErase = TRUE;
1015 break;
1016 }
1017 }
1018 // Merge old and new data. Write merged word to NOR
1019 WordToWrite = (Tmp & ~Mask) | TmpBuf;
1020 BytesToWrite -= (4 - (CurOffset & 0x3));
1021 CurOffset += (4 - (CurOffset & 0x3));
1022 } else {
1023 // Unaligned and fits in one word.
1024 Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8);
1025 // Mask out the bytes we want.
1026 TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask;
1027 // Is the destination still in 'erased' state?
1028 if ((Tmp & Mask) != Mask) {
1029 // Check to see if we are only changing bits to zero.
1030 if ((Tmp ^ TmpBuf) & TmpBuf) {
1031 DoErase = TRUE;
1032 break;
1033 }
1034 }
1035 // Merge old and new data. Write merged word to NOR
1036 WordToWrite = (Tmp & ~Mask) | TmpBuf;
1037 CurOffset += BytesToWrite;
1038 BytesToWrite = 0;
1039 }
1040 }
1041
1042 //
1043 // Write the word to NOR.
1044 //
1045
1046 BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize);
1047 if (BlockAddress != PrevBlockAddress) {
1048 TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
1049 if (EFI_ERROR (TempStatus)) {
1050 return EFI_DEVICE_ERROR;
1051 }
1052 PrevBlockAddress = BlockAddress;
1053 }
1054 TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite);
1055 if (EFI_ERROR (TempStatus)) {
1056 return EFI_DEVICE_ERROR;
1057 }
1058 }
1059 // Exit if we got here and could write all the data. Otherwise do the
1060 // Erase-Write cycle.
1061 if (!DoErase) {
1062 return EFI_SUCCESS;
1063 }
1064 }
1065
1066 // Check we did get some memory. Buffer is BlockSize.
1067 if (Instance->ShadowBuffer == NULL) {
1068 DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
1069 return EFI_DEVICE_ERROR;
1070 }
1071
1072 // Read NOR Flash data into shadow buffer
1073 TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);
1074 if (EFI_ERROR (TempStatus)) {
1075 // Return one of the pre-approved error statuses
1076 return EFI_DEVICE_ERROR;
1077 }
1078
1079 // Put the data at the appropriate location inside the buffer area
1080 CopyMem ((VOID*)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
1081
1082 // Write the modified buffer back to the NorFlash
1083 TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);
1084 if (EFI_ERROR (TempStatus)) {
1085 // Return one of the pre-approved error statuses
1086 return EFI_DEVICE_ERROR;
1087 }
1088
1089 return EFI_SUCCESS;
1090 }
1091
1092 /*
1093 Although DiskIoDxe will automatically install the DiskIO protocol whenever
1094 we install the BlockIO protocol, its implementation is sub-optimal as it reads
1095 and writes entire blocks using the BlockIO protocol. In fact we can access
1096 NOR flash with a finer granularity than that, so we can improve performance
1097 by directly producing the DiskIO protocol.
1098 */
1099
1100 /**
1101 Read BufferSize bytes from Offset into Buffer.
1102
1103 @param This Protocol instance pointer.
1104 @param MediaId Id of the media, changes every time the media is replaced.
1105 @param Offset The starting byte offset to read from
1106 @param BufferSize Size of Buffer
1107 @param Buffer Buffer containing read data
1108
1109 @retval EFI_SUCCESS The data was read correctly from the device.
1110 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
1111 @retval EFI_NO_MEDIA There is no media in the device.
1112 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
1113 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not
1114 valid for the device.
1115
1116 **/
1117 EFI_STATUS
1118 EFIAPI
1119 NorFlashDiskIoReadDisk (
1120 IN EFI_DISK_IO_PROTOCOL *This,
1121 IN UINT32 MediaId,
1122 IN UINT64 DiskOffset,
1123 IN UINTN BufferSize,
1124 OUT VOID *Buffer
1125 )
1126 {
1127 NOR_FLASH_INSTANCE *Instance;
1128 UINT32 BlockSize;
1129 UINT32 BlockOffset;
1130 EFI_LBA Lba;
1131
1132 Instance = INSTANCE_FROM_DISKIO_THIS(This);
1133
1134 if (MediaId != Instance->Media.MediaId) {
1135 return EFI_MEDIA_CHANGED;
1136 }
1137
1138 BlockSize = Instance->Media.BlockSize;
1139 Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
1140
1141 return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer);
1142 }
1143
1144 /**
1145 Writes a specified number of bytes to a device.
1146
1147 @param This Indicates a pointer to the calling context.
1148 @param MediaId ID of the medium to be written.
1149 @param Offset The starting byte offset on the logical block I/O device to write.
1150 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device.
1151 @param Buffer A pointer to the buffer containing the data to be written.
1152
1153 @retval EFI_SUCCESS The data was written correctly to the device.
1154 @retval EFI_WRITE_PROTECTED The device can not be written to.
1155 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
1156 @retval EFI_NO_MEDIA There is no media in the device.
1157 @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.
1158 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not
1159 valid for the device.
1160
1161 **/
1162 EFI_STATUS
1163 EFIAPI
1164 NorFlashDiskIoWriteDisk (
1165 IN EFI_DISK_IO_PROTOCOL *This,
1166 IN UINT32 MediaId,
1167 IN UINT64 DiskOffset,
1168 IN UINTN BufferSize,
1169 IN VOID *Buffer
1170 )
1171 {
1172 NOR_FLASH_INSTANCE *Instance;
1173 UINT32 BlockSize;
1174 UINT32 BlockOffset;
1175 EFI_LBA Lba;
1176 UINTN RemainingBytes;
1177 UINTN WriteSize;
1178 EFI_STATUS Status;
1179
1180 Instance = INSTANCE_FROM_DISKIO_THIS(This);
1181
1182 if (MediaId != Instance->Media.MediaId) {
1183 return EFI_MEDIA_CHANGED;
1184 }
1185
1186 BlockSize = Instance->Media.BlockSize;
1187 Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset);
1188
1189 RemainingBytes = BufferSize;
1190
1191 // Write either all the remaining bytes, or the number of bytes that bring
1192 // us up to a block boundary, whichever is less.
1193 // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next
1194 // block boundary (even if it is already on one).
1195 WriteSize = MIN (RemainingBytes, ((DiskOffset | (BlockSize - 1)) + 1) - DiskOffset);
1196
1197 do {
1198 if (WriteSize == BlockSize) {
1199 // Write a full block
1200 Status = NorFlashWriteFullBlock (Instance, Lba, Buffer, BlockSize / sizeof (UINT32));
1201 } else {
1202 // Write a partial block
1203 Status = NorFlashWriteSingleBlock (Instance, Lba, BlockOffset, &WriteSize, Buffer);
1204 }
1205 if (EFI_ERROR (Status)) {
1206 return Status;
1207 }
1208 // Now continue writing either all the remaining bytes or single blocks.
1209 RemainingBytes -= WriteSize;
1210 Buffer = (UINT8 *) Buffer + WriteSize;
1211 Lba++;
1212 BlockOffset = 0;
1213 WriteSize = MIN (RemainingBytes, BlockSize);
1214 } while (RemainingBytes);
1215
1216 return Status;
1217 }
1218
1219 EFI_STATUS
1220 NorFlashReset (
1221 IN NOR_FLASH_INSTANCE *Instance
1222 )
1223 {
1224 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
1225 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
1226 return EFI_SUCCESS;
1227 }
1228
1229 /**
1230 Fixup internal data so that EFI can be call in virtual mode.
1231 Call the passed in Child Notify event and convert any pointers in
1232 lib to virtual mode.
1233
1234 @param[in] Event The Event that is being processed
1235 @param[in] Context Event Context
1236 **/
1237 VOID
1238 EFIAPI
1239 NorFlashVirtualNotifyEvent (
1240 IN EFI_EVENT Event,
1241 IN VOID *Context
1242 )
1243 {
1244 UINTN Index;
1245
1246 for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
1247 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->DeviceBaseAddress);
1248 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->RegionBaseAddress);
1249
1250 // Convert BlockIo protocol
1251 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks);
1252 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks);
1253 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.Reset);
1254 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks);
1255
1256 // Convert Fvb
1257 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
1258 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
1259 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
1260 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
1261 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Read);
1262 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
1263 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Write);
1264
1265 if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
1266 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->ShadowBuffer);
1267 }
1268 }
1269
1270 return;
1271 }
1272
1273 EFI_STATUS
1274 EFIAPI
1275 NorFlashInitialise (
1276 IN EFI_HANDLE ImageHandle,
1277 IN EFI_SYSTEM_TABLE *SystemTable
1278 )
1279 {
1280 EFI_STATUS Status;
1281 UINT32 Index;
1282 NOR_FLASH_DESCRIPTION* NorFlashDevices;
1283 BOOLEAN ContainVariableStorage;
1284
1285 Status = NorFlashPlatformInitialization ();
1286 if (EFI_ERROR(Status)) {
1287 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to initialize Nor Flash devices\n"));
1288 return Status;
1289 }
1290
1291 Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);
1292 if (EFI_ERROR(Status)) {
1293 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to get Nor Flash devices\n"));
1294 return Status;
1295 }
1296
1297 mNorFlashInstances = AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE*) * mNorFlashDeviceCount);
1298
1299 for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
1300 // Check if this NOR Flash device contain the variable storage region
1301 ContainVariableStorage =
1302 (NorFlashDevices[Index].RegionBaseAddress <= PcdGet32 (PcdFlashNvStorageVariableBase)) &&
1303 (PcdGet32 (PcdFlashNvStorageVariableBase) + PcdGet32 (PcdFlashNvStorageVariableSize) <= NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
1304
1305 Status = NorFlashCreateInstance (
1306 NorFlashDevices[Index].DeviceBaseAddress,
1307 NorFlashDevices[Index].RegionBaseAddress,
1308 NorFlashDevices[Index].Size,
1309 Index,
1310 NorFlashDevices[Index].BlockSize,
1311 ContainVariableStorage,
1312 &mNorFlashInstances[Index]
1313 );
1314 if (EFI_ERROR(Status)) {
1315 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index));
1316 }
1317 }
1318
1319 //
1320 // Register for the virtual address change event
1321 //
1322 Status = gBS->CreateEventEx (
1323 EVT_NOTIFY_SIGNAL,
1324 TPL_NOTIFY,
1325 NorFlashVirtualNotifyEvent,
1326 NULL,
1327 &gEfiEventVirtualAddressChangeGuid,
1328 &mNorFlashVirtualAddrChangeEvent
1329 );
1330 ASSERT_EFI_ERROR (Status);
1331
1332 return Status;
1333 }