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