]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
ARM Packages: Fixed line endings
[mirror_edk2.git] / ArmPlatformPkg / Drivers / NorFlashDxe / NorFlashDxe.c
1 /** @file NorFlashDxe.c
2
3 Copyright (c) 2011-2012, 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
24 //
25 // Global variable declarations
26 //
27 NOR_FLASH_INSTANCE **mNorFlashInstances;
28
29 NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {
30 NOR_FLASH_SIGNATURE, // Signature
31 NULL, // Handle ... NEED TO BE FILLED
32
33 FALSE, // Initialized
34 NULL, // Initialize
35
36 0, // DeviceBaseAddress ... NEED TO BE FILLED
37 0, // RegionBaseAddress ... NEED TO BE FILLED
38 0, // Size ... NEED TO BE FILLED
39 0, // StartLba
40
41 {
42 EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision
43 NULL, // Media ... NEED TO BE FILLED
44 NorFlashBlockIoReset, // Reset;
45 NorFlashBlockIoReadBlocks, // ReadBlocks
46 NorFlashBlockIoWriteBlocks, // WriteBlocks
47 NorFlashBlockIoFlushBlocks // FlushBlocks
48 }, // BlockIoProtocol
49
50 {
51 0, // MediaId ... NEED TO BE FILLED
52 FALSE, // RemovableMedia
53 TRUE, // MediaPresent
54 FALSE, // LogicalPartition
55 FALSE, // ReadOnly
56 FALSE, // WriteCaching;
57 0, // BlockSize ... NEED TO BE FILLED
58 4, // IoAlign
59 0, // LastBlock ... NEED TO BE FILLED
60 0, // LowestAlignedLba
61 1, // LogicalBlocksPerPhysicalBlock
62 }, //Media;
63
64 FALSE, // SupportFvb ... NEED TO BE FILLED
65 {
66 FvbGetAttributes, // GetAttributes
67 FvbSetAttributes, // SetAttributes
68 FvbGetPhysicalAddress, // GetPhysicalAddress
69 FvbGetBlockSize, // GetBlockSize
70 FvbRead, // Read
71 FvbWrite, // Write
72 FvbEraseBlocks, // EraseBlocks
73 NULL, //ParentHandle
74 }, // FvbProtoccol;
75
76 {
77 {
78 {
79 HARDWARE_DEVICE_PATH,
80 HW_VENDOR_DP,
81 (UINT8)( sizeof(VENDOR_DEVICE_PATH) ),
82 (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
83 },
84 { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, // GUID ... NEED TO BE FILLED
85 },
86 {
87 END_DEVICE_PATH_TYPE,
88 END_ENTIRE_DEVICE_PATH_SUBTYPE,
89 sizeof (EFI_DEVICE_PATH_PROTOCOL),
90 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 MediaId,
101 IN UINT32 BlockSize,
102 IN BOOLEAN SupportFvb,
103 IN CONST GUID *NorFlashGuid,
104 OUT NOR_FLASH_INSTANCE** NorFlashInstance
105 )
106 {
107 EFI_STATUS Status;
108 NOR_FLASH_INSTANCE* Instance;
109
110 ASSERT(NorFlashInstance != NULL);
111
112 Instance = AllocateCopyPool (sizeof(NOR_FLASH_INSTANCE),&mNorFlashInstanceTemplate);
113 if (Instance == NULL) {
114 return EFI_OUT_OF_RESOURCES;
115 }
116
117 Instance->DeviceBaseAddress = NorFlashDeviceBase;
118 Instance->RegionBaseAddress = NorFlashRegionBase;
119 Instance->Size = NorFlashSize;
120
121 Instance->BlockIoProtocol.Media = &Instance->Media;
122 Instance->Media.MediaId = MediaId;
123 Instance->Media.BlockSize = BlockSize;
124 Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1;
125
126 CopyGuid (&Instance->DevicePath.Vendor.Guid,NorFlashGuid);
127
128 if (SupportFvb) {
129 Instance->SupportFvb = TRUE;
130 Instance->Initialize = NorFlashFvbInitialize;
131
132 Status = gBS->InstallMultipleProtocolInterfaces (
133 &Instance->Handle,
134 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
135 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
136 &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol,
137 NULL
138 );
139 if (EFI_ERROR(Status)) {
140 FreePool(Instance);
141 return Status;
142 }
143 } else {
144 Instance->Initialized = TRUE;
145
146 Status = gBS->InstallMultipleProtocolInterfaces (
147 &Instance->Handle,
148 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
149 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
150 NULL
151 );
152 if (EFI_ERROR(Status)) {
153 FreePool(Instance);
154 return Status;
155 }
156 }
157
158 *NorFlashInstance = Instance;
159 return Status;
160 }
161
162 UINT32
163 NorFlashReadStatusRegister (
164 IN NOR_FLASH_INSTANCE *Instance,
165 IN UINTN SR_Address
166 )
167 {
168 // Prepare to read the status register
169 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);
170 return MmioRead32 (Instance->DeviceBaseAddress);
171 }
172
173
174 BOOLEAN
175 NorFlashBlockIsLocked (
176 IN NOR_FLASH_INSTANCE *Instance,
177 IN UINTN BlockAddress
178 )
179 {
180 UINT32 LockStatus;
181 BOOLEAN BlockIsLocked;
182
183 BlockIsLocked = TRUE;
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 if ((LockStatus & 0x1) == 0) {
199 // This means the block is unlocked
200 DEBUG((DEBUG_BLKIO, "UnlockSingleBlock: Block 0x%08x unlocked\n", BlockAddress));
201 BlockIsLocked = FALSE;
202 }
203
204 return BlockIsLocked;
205 }
206
207
208 EFI_STATUS
209 NorFlashUnlockSingleBlock (
210 IN NOR_FLASH_INSTANCE *Instance,
211 IN UINTN BlockAddress
212 )
213 {
214 EFI_STATUS Status = EFI_SUCCESS;
215 UINT32 LockStatus;
216
217 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
218 // and to protect shared data structures.
219
220 if (FeaturePcdGet (PcdNorFlashCheckBlockLocked) == TRUE) {
221 do {
222 // Request a lock setup
223 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
224
225 // Request an unlock
226 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
227
228 // Send command for reading device id
229 SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
230
231 // Read block lock status
232 LockStatus = MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress, 2));
233
234 // Decode block lock status
235 LockStatus = FOLD_32BIT_INTO_16BIT(LockStatus);
236 } while ((LockStatus & 0x1) == 1);
237 } else {
238 // Request a lock setup
239 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
240
241 // Request an unlock
242 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
243
244 // Wait until the status register gives us the all clear
245 do {
246 LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress);
247 } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
248 }
249
250 // Put device back into Read Array mode
251 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);
252
253 DEBUG((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x, Exit Status = \"%r\".\n", BlockAddress, Status));
254
255 return Status;
256 }
257
258
259 EFI_STATUS
260 NorFlashUnlockSingleBlockIfNecessary (
261 IN NOR_FLASH_INSTANCE *Instance,
262 IN UINTN BlockAddress
263 )
264 {
265 EFI_STATUS Status = EFI_SUCCESS;
266
267 if (NorFlashBlockIsLocked (Instance, BlockAddress) == TRUE) {
268 Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
269 }
270
271 return Status;
272 }
273
274
275 /**
276 * The following function presumes that the block has already been unlocked.
277 **/
278 EFI_STATUS
279 NorFlashEraseSingleBlock (
280 IN NOR_FLASH_INSTANCE *Instance,
281 IN UINTN BlockAddress
282 )
283 {
284 EFI_STATUS Status;
285 UINT32 StatusRegister;
286
287 Status = EFI_SUCCESS;
288
289 // Request a block erase and then confirm it
290 SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);
291 SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);
292
293 // Wait until the status register gives us the all clear
294 do {
295 StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress);
296 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
297
298 if (StatusRegister & P30_SR_BIT_VPP) {
299 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress));
300 Status = EFI_DEVICE_ERROR;
301 }
302
303 if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) == (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) {
304 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress));
305 Status = EFI_DEVICE_ERROR;
306 }
307
308 if (StatusRegister & P30_SR_BIT_ERASE) {
309 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister));
310 Status = EFI_DEVICE_ERROR;
311 }
312
313 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
314 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
315 DEBUG((EFI_D_INFO,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress));
316 Status = EFI_WRITE_PROTECTED;
317 }
318
319 if (EFI_ERROR(Status)) {
320 // Clear the Status Register
321 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
322 }
323
324 // Put device back into Read Array mode
325 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
326
327 return Status;
328 }
329
330 /**
331 * The following function presumes that the block has already been unlocked.
332 **/
333 EFI_STATUS
334 NorFlashUnlockAndEraseSingleBlock (
335 IN NOR_FLASH_INSTANCE *Instance,
336 IN UINTN BlockAddress
337 )
338 {
339 EFI_STATUS Status;
340 UINTN Index;
341 EFI_TPL OriginalTPL;
342
343 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
344 OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
345
346 Index = 0;
347 // The block erase might fail a first time (SW bug ?). Retry it ...
348 do {
349 // Unlock the block if we have to
350 Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
351 if (!EFI_ERROR(Status)) {
352 Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
353 }
354 Index++;
355 } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
356
357 if (Index == NOR_FLASH_ERASE_RETRY) {
358 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress,Index));
359 }
360
361 // Interruptions can resume.
362 gBS->RestoreTPL (OriginalTPL);
363
364 return Status;
365 }
366
367
368 EFI_STATUS
369 NorFlashWriteSingleWord (
370 IN NOR_FLASH_INSTANCE *Instance,
371 IN UINTN WordAddress,
372 IN UINT32 WriteData
373 )
374 {
375 EFI_STATUS Status;
376 UINT32 StatusRegister;
377
378 Status = EFI_SUCCESS;
379
380 // Request a write single word command
381 SEND_NOR_COMMAND(WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);
382
383 // Store the word into NOR Flash;
384 MmioWrite32 (WordAddress, WriteData);
385
386 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
387 do {
388 // Prepare to read the status register
389 StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress);
390 // The chip is busy while the WRITE bit is not asserted
391 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
392
393
394 // Perform a full status check:
395 // Mask the relevant bits of Status Register.
396 // Everything should be zero, if not, we have a problem
397
398 if (StatusRegister & P30_SR_BIT_VPP) {
399 DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n",WordAddress));
400 Status = EFI_DEVICE_ERROR;
401 }
402
403 if (StatusRegister & P30_SR_BIT_PROGRAM) {
404 DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n",WordAddress));
405 Status = EFI_DEVICE_ERROR;
406 }
407
408 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
409 DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n",WordAddress));
410 Status = EFI_DEVICE_ERROR;
411 }
412
413 if (!EFI_ERROR(Status)) {
414 // Clear the Status Register
415 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
416 }
417
418 // Put device back into Read Array mode
419 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
420
421 return Status;
422 }
423
424 /*
425 * Writes data to the NOR Flash using the Buffered Programming method.
426 *
427 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
428 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
429 * To deal with larger buffers, call this function again.
430 *
431 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
432 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
433 *
434 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
435 * then programming time is doubled and power consumption is increased.
436 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
437 * i.e. the last 4 bits of the target start address must be zero: 0x......00
438 */
439 EFI_STATUS
440 NorFlashWriteBuffer (
441 IN NOR_FLASH_INSTANCE *Instance,
442 IN UINTN TargetAddress,
443 IN UINTN BufferSizeInBytes,
444 IN UINT32 *Buffer
445 )
446 {
447 EFI_STATUS Status;
448 UINTN BufferSizeInWords;
449 UINTN Count;
450 volatile UINT32 *Data;
451 UINTN WaitForBuffer;
452 BOOLEAN BufferAvailable;
453 UINT32 StatusRegister;
454
455 WaitForBuffer = MAX_BUFFERED_PROG_ITERATIONS;
456 BufferAvailable = FALSE;
457
458 // Check that the target address does not cross a 32-word boundary.
459 if ((TargetAddress & BOUNDARY_OF_32_WORDS) != 0) {
460 return EFI_INVALID_PARAMETER;
461 }
462
463 // Check there are some data to program
464 if (BufferSizeInBytes == 0) {
465 return EFI_BUFFER_TOO_SMALL;
466 }
467
468 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
469 if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) {
470 return EFI_BAD_BUFFER_SIZE;
471 }
472
473 // Check that the buffer size is a multiple of 32-bit words
474 if ((BufferSizeInBytes % 4) != 0) {
475 return EFI_BAD_BUFFER_SIZE;
476 }
477
478 // Pre-programming conditions checked, now start the algorithm.
479
480 // Prepare the data destination address
481 Data = (UINT32 *)TargetAddress;
482
483 // Check the availability of the buffer
484 do {
485 // Issue the Buffered Program Setup command
486 SEND_NOR_COMMAND(TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);
487
488 // Read back the status register bit#7 from the same address
489 if (((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE) {
490 BufferAvailable = TRUE;
491 }
492
493 // Update the loop counter
494 WaitForBuffer--;
495
496 } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE));
497
498 // The buffer was not available for writing
499 if (WaitForBuffer == 0) {
500 Status = EFI_DEVICE_ERROR;
501 goto EXIT;
502 }
503
504 // From now on we work in 32-bit words
505 BufferSizeInWords = BufferSizeInBytes / (UINTN)4;
506
507 // Write the word count, which is (buffer_size_in_words - 1),
508 // because word count 0 means one word.
509 SEND_NOR_COMMAND(TargetAddress, 0, (BufferSizeInWords - 1));
510
511 // Write the data to the NOR Flash, advancing each address by 4 bytes
512 for(Count=0; Count < BufferSizeInWords; Count++, Data++, Buffer++) {
513 *Data = *Buffer;
514 }
515
516 // Issue the Buffered Program Confirm command, to start the programming operation
517 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
518
519 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
520 do {
521 StatusRegister = NorFlashReadStatusRegister (Instance, TargetAddress);
522 // The chip is busy while the WRITE bit is not asserted
523 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
524
525
526 // Perform a full status check:
527 // Mask the relevant bits of Status Register.
528 // Everything should be zero, if not, we have a problem
529
530 Status = EFI_SUCCESS;
531
532 if (StatusRegister & P30_SR_BIT_VPP) {
533 DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress));
534 Status = EFI_DEVICE_ERROR;
535 }
536
537 if (StatusRegister & P30_SR_BIT_PROGRAM) {
538 DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress));
539 Status = EFI_DEVICE_ERROR;
540 }
541
542 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
543 DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n",TargetAddress));
544 Status = EFI_DEVICE_ERROR;
545 }
546
547 if (!EFI_ERROR(Status)) {
548 // Clear the Status Register
549 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
550 }
551
552 EXIT:
553 // Put device back into Read Array mode
554 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
555
556 return Status;
557 }
558
559 EFI_STATUS
560 NorFlashWriteSingleBlock (
561 IN NOR_FLASH_INSTANCE *Instance,
562 IN EFI_LBA Lba,
563 IN UINT32 *DataBuffer,
564 IN UINT32 BlockSizeInWords
565 )
566 {
567 EFI_STATUS Status;
568 UINTN WordAddress;
569 UINT32 WordIndex;
570 UINTN BufferIndex;
571 UINTN BlockAddress;
572 UINTN BuffersInBlock;
573 UINTN RemainingWords;
574 EFI_TPL OriginalTPL;
575
576 Status = EFI_SUCCESS;
577
578 // Get the physical address of the block
579 BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4);
580
581 // Start writing from the first address at the start of the block
582 WordAddress = BlockAddress;
583
584 // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
585 OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
586
587 Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
588 if (EFI_ERROR(Status)) {
589 DEBUG((EFI_D_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));
590 goto EXIT;
591 }
592
593 // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
594
595 // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
596 if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {
597
598 // First, break the entire block into buffer-sized chunks.
599 BuffersInBlock = (UINTN)BlockSizeInWords / P30_MAX_BUFFER_SIZE_IN_BYTES;
600
601 // Then feed each buffer chunk to the NOR Flash
602 for(BufferIndex=0;
603 BufferIndex < BuffersInBlock;
604 BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS
605 ) {
606 Status = NorFlashWriteBuffer (Instance, WordAddress, P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer);
607 if (EFI_ERROR(Status)) {
608 goto EXIT;
609 }
610 }
611
612 // Finally, finish off any remaining words that are less than the maximum size of the buffer
613 RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;
614
615 if(RemainingWords != 0) {
616 Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer);
617 if (EFI_ERROR(Status)) {
618 goto EXIT;
619 }
620 }
621
622 } else {
623 // For now, use the single word programming algorithm
624 // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
625 // i.e. which ends in the range 0x......01 - 0x......7F.
626 for(WordIndex=0; WordIndex<BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {
627 Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
628 if (EFI_ERROR(Status)) {
629 goto EXIT;
630 }
631 }
632 }
633
634 EXIT:
635 // Interruptions can resume.
636 gBS->RestoreTPL (OriginalTPL);
637
638 if (EFI_ERROR(Status)) {
639 DEBUG((EFI_D_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));
640 }
641 return Status;
642 }
643
644
645 EFI_STATUS
646 NorFlashWriteBlocks (
647 IN NOR_FLASH_INSTANCE *Instance,
648 IN EFI_LBA Lba,
649 IN UINTN BufferSizeInBytes,
650 IN VOID *Buffer
651 )
652 {
653 UINT32 *pWriteBuffer;
654 EFI_STATUS Status = EFI_SUCCESS;
655 EFI_LBA CurrentBlock;
656 UINT32 BlockSizeInWords;
657 UINT32 NumBlocks;
658 UINT32 BlockCount;
659
660 // The buffer must be valid
661 if (Buffer == NULL) {
662 return EFI_INVALID_PARAMETER;
663 }
664
665 if(Instance->Media.ReadOnly == TRUE) {
666 return EFI_WRITE_PROTECTED;
667 }
668
669 // We must have some bytes to read
670 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes));
671 if(BufferSizeInBytes == 0) {
672 return EFI_BAD_BUFFER_SIZE;
673 }
674
675 // The size of the buffer must be a multiple of the block size
676 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance->Media.BlockSize));
677 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
678 return EFI_BAD_BUFFER_SIZE;
679 }
680
681 // All blocks must be within the device
682 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
683
684 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->Media.LastBlock, Lba));
685
686 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
687 DEBUG((EFI_D_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
688 return EFI_INVALID_PARAMETER;
689 }
690
691 BlockSizeInWords = Instance->Media.BlockSize / 4;
692
693 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
694 // to a proper data type, so use *ReadBuffer
695 pWriteBuffer = (UINT32 *)Buffer;
696
697 CurrentBlock = Lba;
698 for (BlockCount=0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) {
699
700 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock));
701
702 Status = NorFlashWriteSingleBlock (Instance, CurrentBlock, pWriteBuffer, BlockSizeInWords);
703
704 if (EFI_ERROR(Status)) {
705 break;
706 }
707 }
708
709 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
710 return Status;
711 }
712
713 EFI_STATUS
714 NorFlashReadBlocks (
715 IN NOR_FLASH_INSTANCE *Instance,
716 IN EFI_LBA Lba,
717 IN UINTN BufferSizeInBytes,
718 OUT VOID *Buffer
719 )
720 {
721 UINT32 NumBlocks;
722 UINTN StartAddress;
723
724 // The buffer must be valid
725 if (Buffer == NULL) {
726 return EFI_INVALID_PARAMETER;
727 }
728
729 // We must have some bytes to read
730 DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BufferSize=0x%x bytes.\n", BufferSizeInBytes));
731 if(BufferSizeInBytes == 0) {
732 return EFI_BAD_BUFFER_SIZE;
733 }
734
735 // The size of the buffer must be a multiple of the block size
736 DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BlockSize=0x%x bytes.\n", Instance->Media.BlockSize));
737 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
738 return EFI_BAD_BUFFER_SIZE;
739 }
740
741 // All blocks must be within the device
742 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
743
744 DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld\n", NumBlocks, Instance->Media.LastBlock, Lba));
745
746 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {
747 DEBUG((EFI_D_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
748 return EFI_INVALID_PARAMETER;
749 }
750
751 // Get the address to start reading from
752 StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress,
753 Lba,
754 Instance->Media.BlockSize
755 );
756
757 // Put the device into Read Array mode
758 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
759
760 // Readout the data
761 CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes);
762
763 return EFI_SUCCESS;
764 }
765
766 EFI_STATUS
767 NorFlashReset (
768 IN NOR_FLASH_INSTANCE *Instance
769 )
770 {
771 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
772 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
773 return EFI_SUCCESS;
774 }
775
776 EFI_STATUS
777 EFIAPI
778 NorFlashInitialise (
779 IN EFI_HANDLE ImageHandle,
780 IN EFI_SYSTEM_TABLE *SystemTable
781 )
782 {
783 EFI_STATUS Status;
784 UINT32 Index;
785 NOR_FLASH_DESCRIPTION* NorFlashDevices;
786 UINT32 NorFlashDeviceCount;
787 BOOLEAN ContainVariableStorage;
788
789 Status = NorFlashPlatformInitialization ();
790 if (EFI_ERROR(Status)) {
791 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to initialize Nor Flash devices\n"));
792 return Status;
793 }
794
795 Status = NorFlashPlatformGetDevices (&NorFlashDevices,&NorFlashDeviceCount);
796 if (EFI_ERROR(Status)) {
797 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to get Nor Flash devices\n"));
798 return Status;
799 }
800
801 mNorFlashInstances = AllocatePool (sizeof(NOR_FLASH_INSTANCE*) * NorFlashDeviceCount);
802
803 for (Index = 0; Index < NorFlashDeviceCount; Index++) {
804 // Check if this NOR Flash device contain the variable storage region
805 ContainVariableStorage =
806 (NorFlashDevices[Index].RegionBaseAddress <= PcdGet32 (PcdFlashNvStorageVariableBase)) &&
807 (PcdGet32 (PcdFlashNvStorageVariableBase) + PcdGet32 (PcdFlashNvStorageVariableSize) <= NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);
808
809 Status = NorFlashCreateInstance (
810 NorFlashDevices[Index].DeviceBaseAddress,
811 NorFlashDevices[Index].RegionBaseAddress,
812 NorFlashDevices[Index].Size,
813 Index,
814 NorFlashDevices[Index].BlockSize,
815 ContainVariableStorage,
816 &NorFlashDevices[Index].Guid,
817 &mNorFlashInstances[Index]
818 );
819 if (EFI_ERROR(Status)) {
820 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index));
821 }
822 }
823
824 return Status;
825 }