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