]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/ArmVExpressPkg/NorFlashDxe/NorFlashDxe.c
Add ArmPlatformPkg from ARM Ltd. patch.
[mirror_edk2.git] / ArmPlatformPkg / ArmVExpressPkg / NorFlashDxe / NorFlashDxe.c
CommitLineData
1d5d0ae9 1/** @file NorFlashDxe.c
2
3 Copyright (c) 2010, ARM Ltd. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12**/
13
14#include <Library/UefiLib.h>
15#include <Library/DebugLib.h>
16#include <Library/BaseMemoryLib.h>
17#include <Library/MemoryAllocationLib.h>
18#include <Library/UefiBootServicesTableLib.h>
19
20#include "NorFlashDxe.h"
21
22
23//
24// Global variable declarations
25//
26
27#define NOR_FLASH_LAST_DEVICE 4
28
29NOR_FLASH_DESCRIPTION mNorFlashDescription[NOR_FLASH_LAST_DEVICE] = {
30 { // BootMon
31 ARM_VE_SMB_NOR0_BASE,
32 SIZE_256KB * 255,
33 SIZE_256KB,
34 FALSE,
35 {0xE7223039, 0x5836, 0x41E1, 0xB5, 0x42, 0xD7, 0xEC, 0x73, 0x6C, 0x5E, 0x59}
36 },
37 { // BootMon non-volatile storage
38 ARM_VE_SMB_NOR0_BASE + SIZE_256KB * 255,
39 SIZE_64KB * 4,
40 SIZE_64KB,
41 FALSE,
42 {0x02118005, 0x9DA7, 0x443A, 0x92, 0xD5, 0x78, 0x1F, 0x02, 0x2A, 0xED, 0xBB}
43 },
44 { // UEFI
45 ARM_VE_SMB_NOR1_BASE,
46 SIZE_256KB * 255,
47 SIZE_256KB,
48 FALSE,
49 {0x1F15DA3C, 0x37FF, 0x4070, 0xB4, 0x71, 0xBB, 0x4A, 0xF1, 0x2A, 0x72, 0x4A}
50 },
51 { // UEFI Variable Services non-volatile storage
52 ARM_VE_SMB_NOR1_BASE + SIZE_256KB * 255,
53 SIZE_64KB * 3, //FIXME: Set 3 blocks because I did not succeed to copy 4 blocks into the ARM Versastile Express NOR Falsh in the last NOR Flash. It should be 4 blocks
54 SIZE_64KB,
55 TRUE,
56 {0xCC2CBF29, 0x1498, 0x4CDD, 0x81, 0x71, 0xF8, 0xB6, 0xB4, 0x1D, 0x09, 0x09}
57 }
58};
59
60NOR_FLASH_INSTANCE *mNorFlashInstances[ NOR_FLASH_LAST_DEVICE ];
61
62NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {
63 NOR_FLASH_SIGNATURE, // Signature
64 NULL, // Handle ... NEED TO BE FILLED
65
66 FALSE, // Initialized
67 NULL, // Initialize
68
69 0, // BaseAddress ... NEED TO BE FILLED
70 0, // Size ... NEED TO BE FILLED
71
72 {\r
73 EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision\r
74 NULL, // Media ... NEED TO BE FILLED\r
75 NorFlashBlockIoReset, // Reset;\r
76 NorFlashBlockIoReadBlocks, // ReadBlocks
77 NorFlashBlockIoWriteBlocks, // WriteBlocks
78 NorFlashBlockIoFlushBlocks // FlushBlocks\r
79 }, // BlockIoProtocol
80
81 {\r
82 0, // MediaId ... NEED TO BE FILLED\r
83 FALSE, // RemovableMedia\r
84 TRUE, // MediaPresent\r
85 FALSE, // LogicalPartition\r
86 FALSE, // ReadOnly\r
87 FALSE, // WriteCaching;\r
88 0, // BlockSize ... NEED TO BE FILLED\r
89 4, // IoAlign\r
90 0, // LastBlock ... NEED TO BE FILLED\r
91 0, // LowestAlignedLba\r
92 1, // LogicalBlocksPerPhysicalBlock\r
93 }, //Media;
94
95 FALSE, // SupportFvb ... NEED TO BE FILLED
96 {\r
97 FvbGetAttributes, // GetAttributes
98 FvbSetAttributes, // SetAttributes
99 FvbGetPhysicalAddress, // GetPhysicalAddress
100 FvbGetBlockSize, // GetBlockSize
101 FvbRead, // Read
102 FvbWrite, // Write
103 FvbEraseBlocks, // EraseBlocks\r
104 NULL, //ParentHandle\r
105 }, // FvbProtoccol;
106
107 {
108 {
109 {
110 HARDWARE_DEVICE_PATH,
111 HW_VENDOR_DP,
112 (UINT8)( sizeof(VENDOR_DEVICE_PATH) ),
113 (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
114 },
115 { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, // GUID ... NEED TO BE FILLED
116 },
117 {
118 END_DEVICE_PATH_TYPE,
119 END_ENTIRE_DEVICE_PATH_SUBTYPE,
120 sizeof (EFI_DEVICE_PATH_PROTOCOL),
121 0
122 }
123 } // DevicePath
124};
125
126EFI_STATUS NorFlashCreateInstance(
127 IN UINTN NorFlashBase,
128 IN UINTN NorFlashSize,
129 IN UINT32 MediaId,
130 IN UINT32 BlockSize,
131 IN BOOLEAN SupportFvb,
132 IN CONST GUID *NorFlashGuid,
133 OUT NOR_FLASH_INSTANCE** NorFlashInstance
134 ) {
135 EFI_STATUS Status;
136 NOR_FLASH_INSTANCE* Instance;
137
138 ASSERT(NorFlashInstance != NULL);
139
140 Instance = AllocateCopyPool (sizeof(NOR_FLASH_INSTANCE),&mNorFlashInstanceTemplate);
141 if (Instance == NULL) {
142 return EFI_OUT_OF_RESOURCES;
143 }
144
145 Instance->BaseAddress = NorFlashBase;
146 Instance->Size = NorFlashSize;
147
148 Instance->BlockIoProtocol.Media = &Instance->Media;
149 Instance->Media.MediaId = MediaId;
150 Instance->Media.BlockSize = BlockSize;
151 Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1;
152\r
153 CopyGuid (&Instance->DevicePath.Vendor.Guid,NorFlashGuid);\r
154
155 if (SupportFvb) {
156 Instance->SupportFvb = TRUE;
157 Instance->Initialize = NorFlashFvbInitialize;
158
159 Status = gBS->InstallMultipleProtocolInterfaces (
160 &Instance->Handle,
161 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
162 //&gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
163 &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol,
164 NULL
165 );
166 if (EFI_ERROR(Status)) {
167 FreePool(Instance);
168 return Status;
169 }
170 } else {
171 Instance->Initialize = NorFlashBlkIoInitialize;
172
173 Status = gBS->InstallMultipleProtocolInterfaces (
174 &Instance->Handle,
175 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
176 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
177 NULL
178 );
179 if (EFI_ERROR(Status)) {
180 FreePool(Instance);
181 return Status;
182 }
183 }
184\r
185 *NorFlashInstance = Instance;\r
186 return Status;\r
187}
188
189EFI_STATUS
190NorFlashReadCfiData (
191 IN UINTN BaseAddress,
192 IN UINTN CFI_Offset,
193 IN UINT32 NumberOfBytes,
194 OUT UINT32 *Data
195)
196{
197 UINT32 CurrentByte;
198 volatile UINTN *ReadAddress;
199 UINT32 ReadData;
200 UINT32 Byte1;
201 UINT32 Byte2;
202 UINT32 CombinedData = 0;
203 EFI_STATUS Status = EFI_SUCCESS;
204
205
206 if( NumberOfBytes > 4 ) {
207 // Using 32 bit variable so can only read 4 bytes
208 return EFI_INVALID_PARAMETER;
209 }
210
211 // First combine the base address with the offset address
212 // to create an absolute read address.
213 // However, because we are in little endian, read from the last address down to the first
214 ReadAddress = CREATE_NOR_ADDRESS( BaseAddress, CFI_Offset ) + NumberOfBytes - 1;
215
216 // Although each read returns 32 bits, because of the NOR Flash structure,
217 // each 16 bits (16 MSB and 16 LSB) come from two different chips.
218 // When in CFI mode, each chip read returns valid data in only the 8 LSBits;
219 // the 8 MSBits are invalid and can be ignored.
220 // Therefore, each read address returns one byte from each chip.
221 //
222 // Also note: As we are in little endian notation and we are reading
223 // bytes from incremental addresses, we should assemble them in little endian order.
224 for( CurrentByte=0; CurrentByte<NumberOfBytes; CurrentByte++ ) {
225
226 // Read the bytes from the two chips
227 ReadData = *ReadAddress;
228
229 // Check the data validity:
230 // The 'Dual Data' function means that
231 // each chip should return identical data.
232 // If that is not the case then we have a problem.
233 Byte1 = GET_LOW_BYTE ( ReadData );
234 Byte2 = GET_HIGH_BYTE( ReadData );
235
236 if( Byte1 != Byte2 ) {
237 // The two bytes should have been identical
238 return EFI_DEVICE_ERROR;
239 } else {
240
241 // Each successive iteration of the 'for' loop reads a lower address.
242 // As we read lower addresses and as we use little endian,
243 // we read lower significance bytes. So combine them in the correct order.
244 CombinedData = (CombinedData << 8) | Byte1;
245
246 // Decrement down to the next address
247 ReadAddress--;
248 }
249 }
250
251 *Data = CombinedData;
252
253 return Status;
254}
255
256EFI_STATUS
257NorFlashReadStatusRegister(
258 IN UINTN SR_Address
259 )
260{
261 volatile UINT32 *pStatusRegister;
262 UINT32 StatusRegister;
263 UINT32 ErrorMask;
264 EFI_STATUS Status = EFI_SUCCESS;
265
266 // Prepare the read address
267 pStatusRegister = (UINT32 *) SR_Address;
268
269 do {
270 // Prepare to read the status register
271 SEND_NOR_COMMAND( SR_Address, 0, P30_CMD_READ_STATUS_REGISTER );
272 // Snapshot the status register
273 StatusRegister = *pStatusRegister;
274 }
275 // The chip is busy while the WRITE bit is not asserted
276 while ( (StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE );
277
278
279 // Perform a full status check:
280 // Mask the relevant bits of Status Register.
281 // Everything should be zero, if not, we have a problem
282
283 // Prepare the Error Mask by setting bits 5, 4, 3, 1
284 ErrorMask = P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM | P30_SR_BIT_VPP | P30_SR_BIT_BLOCK_LOCKED ;
285
286 if ( (StatusRegister & ErrorMask) != 0 ) {
287 if ( (StatusRegister & P30_SR_BIT_VPP) != 0 ) {
288 DEBUG((EFI_D_ERROR,"NorFlashReadStatusRegister: VPP Range Error\n"));
289 } else if ( (StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM) ) != 0 ) {
290 DEBUG((EFI_D_ERROR,"NorFlashReadStatusRegister: Command Sequence Error\n"));
291 } else if ( (StatusRegister & P30_SR_BIT_PROGRAM) != 0 ) {
292 DEBUG((EFI_D_ERROR,"NorFlashReadStatusRegister: Program Error\n"));
293 } else if ( (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) != 0 ) {
294 DEBUG((EFI_D_ERROR,"NorFlashReadStatusRegister: Device Protect Error\n"));
295 } else {\r
296 DEBUG((EFI_D_ERROR,"NorFlashReadStatusRegister: Error (0x%X)\n",Status));\r
297 }
298
299 // If an error is detected we must clear the Status Register
300 SEND_NOR_COMMAND( SR_Address, 0, P30_CMD_CLEAR_STATUS_REGISTER );
301 Status = EFI_DEVICE_ERROR;
302 }
303
304 SEND_NOR_COMMAND( SR_Address, 0, P30_CMD_READ_ARRAY );
305
306 return Status;
307}
308
309
310BOOLEAN
311NorFlashBlockIsLocked(
312 IN UINTN BlockAddress
313 )
314{
315 volatile UINT32 *pReadData;
316 UINT32 LockStatus;
317 BOOLEAN BlockIsLocked = TRUE;
318
319 // Prepare the read address
320 pReadData = (UINT32 *) CREATE_NOR_ADDRESS( BlockAddress, 2 );
321
322 // Send command for reading device id
323 SEND_NOR_COMMAND( BlockAddress, 2, P30_CMD_READ_DEVICE_ID );
324
325 // Read block lock status
326 LockStatus = *pReadData;
327
328 // Decode block lock status
329 LockStatus = FOLD_32BIT_INTO_16BIT(LockStatus);
330
331 if( (LockStatus & 0x2) != 0 ) {
332 DEBUG((EFI_D_ERROR, "UnlockSingleBlock: WARNING: Block LOCKED DOWN\n"));
333 }
334
335 if( (LockStatus & 0x1) == 0 ) {
336 // This means the block is unlocked
337 DEBUG((DEBUG_BLKIO, "UnlockSingleBlock: Block 0x%08x unlocked\n", BlockAddress ));
338 BlockIsLocked = FALSE;
339 }
340
341 return BlockIsLocked;
342}
343
344
345EFI_STATUS
346NorFlashUnlockSingleBlock(
347 IN UINTN BlockAddress
348 )
349{
350 EFI_STATUS Status = EFI_SUCCESS;
351
352 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
353 // and to protect shared data structures.
354
355 //while( NorFlashBlockIsLocked( BlockAddress ) )
356 {
357 // Request a lock setup
358 SEND_NOR_COMMAND( BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP );
359
360 // Request an unlock
361 SEND_NOR_COMMAND( BlockAddress, 0, P30_CMD_UNLOCK_BLOCK );
362 }
363
364 // Put device back into Read Array mode
365 SEND_NOR_COMMAND( BlockAddress, 0, P30_CMD_READ_ARRAY );
366
367 DEBUG((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x, Exit Status = \"%r\".\n", BlockAddress, Status));
368
369 return Status;
370}
371
372
373EFI_STATUS
374NorFlashUnlockSingleBlockIfNecessary(
375 IN UINTN BlockAddress
376 )
377{
378 EFI_STATUS Status = EFI_SUCCESS;
379
380 if ( NorFlashBlockIsLocked( BlockAddress ) == TRUE ) {
381 Status = NorFlashUnlockSingleBlock( BlockAddress );
382 }
383
384 return Status;
385}
386
387
388/**
389 * The following function presumes that the block has already been unlocked.
390 **/
391EFI_STATUS
392NorFlashEraseSingleBlock(
393 IN UINTN BlockAddress
394 )
395{
396 EFI_STATUS Status = EFI_SUCCESS;
397
398 // Request a block erase and then confirm it
399 SEND_NOR_COMMAND( BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP );
400 SEND_NOR_COMMAND( BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM );
401 // Wait until the status register gives us the all clear
402 Status = NorFlashReadStatusRegister( BlockAddress );
403
404 if (EFI_ERROR(Status)) {
405 DEBUG((DEBUG_BLKIO, "EraseSingleBlock(BlockAddress=0x%08x) = '%r'\n", BlockAddress, Status));
406 }
407 return Status;
408}
409
410/**
411 * The following function presumes that the block has already been unlocked.
412 **/
413EFI_STATUS
414NorFlashUnlockAndEraseSingleBlock(
415 IN UINTN BlockAddress
416 )
417{
418 EFI_STATUS Status;
419
420 // Unlock the block if we have to
421 Status = NorFlashUnlockSingleBlockIfNecessary( BlockAddress );
422 if (!EFI_ERROR(Status)) {
423 Status = NorFlashEraseSingleBlock( BlockAddress );
424 }
425
426 return Status;
427}
428
429
430EFI_STATUS
431NorFlashWriteSingleWord (
432 IN UINTN WordAddress,
433 IN UINT32 WriteData
434 )
435{
436 EFI_STATUS Status;
437 volatile UINT32 *Data;
438
439 // Prepare the read address
440 Data = (UINT32 *)WordAddress;
441
442 // Request a write single word command
443 SEND_NOR_COMMAND( WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP );
444
445 // Store the word into NOR Flash;
446 *Data = WriteData;
447
448 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
449 Status = NorFlashReadStatusRegister( WordAddress );
450
451 return Status;
452}
453
454/*
455 * Writes data to the NOR Flash using the Buffered Programming method.
456 *
457 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
458 * Therefore this function will only handle buffers up to 32 words or 128 bytes.
459 * To deal with larger buffers, call this function again.
460 *
461 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
462 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
463 *
464 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
465 * then programming time is doubled and power consumption is increased.
466 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
467 * i.e. the last 4 bits of the target start address must be zero: 0x......00
468 */
469EFI_STATUS
470NorFlashWriteBuffer (
471 IN UINTN TargetAddress,
472 IN UINTN BufferSizeInBytes,
473 IN UINT32 *Buffer
474 )
475{
476 EFI_STATUS Status;
477 UINTN BufferSizeInWords;
478 UINTN Count;
479 volatile UINT32 *Data;
480 UINTN WaitForBuffer = MAX_BUFFERED_PROG_ITERATIONS;
481 BOOLEAN BufferAvailable = FALSE;
482
483
484 // Check that the target address does not cross a 32-word boundary.
485 if ( (TargetAddress & BOUNDARY_OF_32_WORDS) != 0 ) {
486 return EFI_INVALID_PARAMETER;
487 }
488
489 // Check there are some data to program
490 if ( BufferSizeInBytes == 0 ) {
491 return EFI_BUFFER_TOO_SMALL;
492 }
493
494 // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
495 if ( BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES ) {
496 return EFI_BAD_BUFFER_SIZE;
497 }
498
499 // Check that the buffer size is a multiple of 32-bit words
500 if ( (BufferSizeInBytes % 4) != 0 ) {
501 return EFI_BAD_BUFFER_SIZE;
502 }
503
504 // Pre-programming conditions checked, now start the algorithm.
505
506 // Prepare the data destination address
507 Data = (UINT32 *)TargetAddress;
508
509 // Check the availability of the buffer
510 do {
511 // Issue the Buffered Program Setup command
512 SEND_NOR_COMMAND( TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP );
513
514 // Read back the status register bit#7 from the same address
515 if ( ((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE ) {
516 BufferAvailable = TRUE;
517 }
518
519 // Update the loop counter
520 WaitForBuffer--;
521
522 } while (( WaitForBuffer > 0 ) && ( BufferAvailable == FALSE ));
523
524 // The buffer was not available for writing
525 if ( WaitForBuffer == 0 ) {
526 return EFI_DEVICE_ERROR;
527 }
528
529 // From now on we work in 32-bit words
530 BufferSizeInWords = BufferSizeInBytes / (UINTN)4;
531
532 // Write the word count, which is (buffer_size_in_words - 1),
533 // because word count 0 means one word.
534 SEND_NOR_COMMAND( TargetAddress, 0, (BufferSizeInWords - 1) );
535
536 // Write the data to the NOR Flash, advancing each address by 4 bytes
537 for( Count=0; Count<BufferSizeInWords; Count++, Data++, Buffer++ ) {
538 *Data = *Buffer;
539 }
540
541 // Issue the Buffered Program Confirm command, to start the programming operation
542 SEND_NOR_COMMAND( TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM );
543
544 // Wait for the write to complete and then check for any errors; i.e. check the Status Register
545 Status = NorFlashReadStatusRegister( TargetAddress );
546
547 return Status;
548}
549
550EFI_STATUS
551NorFlashWriteSingleBlock (
552 IN UINTN DeviceBaseAddress,
553 IN EFI_LBA Lba,
554 IN UINT32 *DataBuffer,
555 IN UINT32 BlockSizeInWords
556 )
557{
558 EFI_STATUS Status = EFI_SUCCESS;
559 UINTN WordAddress;
560 UINT32 WordIndex;
561 UINTN BufferIndex;
562 UINTN BlockAddress;
563 UINTN BuffersInBlock;
564 UINTN RemainingWords;
565
566 // Get the physical address of the block
567 BlockAddress = GET_NOR_BLOCK_ADDRESS(DeviceBaseAddress, Lba, BlockSizeInWords * 4);
568
569 Status = NorFlashUnlockAndEraseSingleBlock( BlockAddress );
570 if (EFI_ERROR(Status)) {
571 DEBUG((EFI_D_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));
572 return Status;
573 }
574
575 // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
576
577 // Start writing from the first address at the start of the block
578 WordAddress = BlockAddress;
579
580 // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
581 if ( (WordAddress & BOUNDARY_OF_32_WORDS) == 0x00 ) {
582
583 // First, break the entire block into buffer-sized chunks.
584 BuffersInBlock = (UINTN)BlockSizeInWords / P30_MAX_BUFFER_SIZE_IN_BYTES;
585
586 // Then feed each buffer chunk to the NOR Flash
587 for( BufferIndex=0;
588 BufferIndex < BuffersInBlock;
589 BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS
590 ) {
591 Status = NorFlashWriteBuffer ( WordAddress, P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer );
592 if (EFI_ERROR(Status)) {
593 goto EXIT;
594 }
595 }
596
597 // Finally, finish off any remaining words that are less than the maximum size of the buffer
598 RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;
599
600 if( RemainingWords != 0) {
601 Status = NorFlashWriteBuffer ( WordAddress, (RemainingWords * 4), DataBuffer );
602 if (EFI_ERROR(Status)) {
603 goto EXIT;
604 }
605 }
606
607 } else {
608 // For now, use the single word programming algorithm
609 // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
610 // i.e. which ends in the range 0x......01 - 0x......7F.
611 for( WordIndex=0; WordIndex<BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4 ) {
612 Status = NorFlashWriteSingleWord( WordAddress, *DataBuffer );
613 if (EFI_ERROR(Status)) {
614 goto EXIT;
615 }
616 }
617 }
618
619 EXIT:
620 if (EFI_ERROR(Status)) {
621 DEBUG((EFI_D_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));
622 }
623 return Status;
624}
625
626
627EFI_STATUS
628NorFlashWriteBlocks (
629 IN NOR_FLASH_INSTANCE *Instance,
630 IN EFI_LBA Lba,
631 IN UINTN BufferSizeInBytes,
632 IN VOID *Buffer
633 )
634{
635 UINT32 *pWriteBuffer;
636 EFI_STATUS Status = EFI_SUCCESS;
637 EFI_LBA CurrentBlock;
638 UINT32 BlockSizeInWords;
639 UINT32 NumBlocks;
640 UINT32 BlockCount;
641 volatile UINT32 *VersatileExpress_SYS_FLASH;
642
643 // The buffer must be valid
644 if (Buffer == NULL) {
645 return EFI_INVALID_PARAMETER;
646 }
647
648 if( Instance->Media.ReadOnly == TRUE ) {
649 return EFI_WRITE_PROTECTED;
650 }
651
652 // We must have some bytes to read
653 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes));
654 if( BufferSizeInBytes == 0 ) {
655 return EFI_BAD_BUFFER_SIZE;
656 }
657
658 // The size of the buffer must be a multiple of the block size
659 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance->Media.BlockSize ));
660 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
661 return EFI_BAD_BUFFER_SIZE;
662 }
663
664 // All blocks must be within the device
665 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
666
667 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->Media.LastBlock, Lba));
668
669 if ( ( Lba + NumBlocks ) > ( Instance->Media.LastBlock + 1 ) ) {
670 DEBUG((EFI_D_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
671 return EFI_INVALID_PARAMETER;
672 }
673
674 // Everything seems ok so far, so now we need to disable the platform-specific
675 // flash write protection for Versatile Express
676 VersatileExpress_SYS_FLASH = (UINT32 *)VE_REGISTER_SYS_FLASH_ADDR;
677 if( (*VersatileExpress_SYS_FLASH & 0x1) == 0 ) {
678 // Writing to NOR FLASH is disabled, so enable it
679 *VersatileExpress_SYS_FLASH = 0x1;
680 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: informational - Had to enable HSYS_FLASH flag.\n" ));
681 }
682
683 BlockSizeInWords = Instance->Media.BlockSize / 4;
684
685 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
686 // to a proper data type, so use *ReadBuffer
687 pWriteBuffer = (UINT32 *)Buffer;
688
689 CurrentBlock = Lba;
690 for( BlockCount=0; BlockCount<NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords ) {
691
692 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock ));
693
694 Status = NorFlashWriteSingleBlock( Instance->BaseAddress, CurrentBlock, pWriteBuffer, BlockSizeInWords );
695
696 if (EFI_ERROR(Status)) {
697 break;
698 }
699
700 }
701
702 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
703 return Status;
704}
705
706
707EFI_STATUS
708NorFlashReadBlocks (
709 IN NOR_FLASH_INSTANCE *Instance,
710 IN EFI_LBA Lba,
711 IN UINTN BufferSizeInBytes,
712 OUT VOID *Buffer
713 )
714{
715 UINT32 NumBlocks;
716 UINTN StartAddress;
717
718 // The buffer must be valid
719 if (Buffer == NULL) {
720 return EFI_INVALID_PARAMETER;
721 }
722
723 // We must have some bytes to read
724 DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BufferSize=0x%x bytes.\n", BufferSizeInBytes));
725 if( BufferSizeInBytes == 0 ) {
726 return EFI_BAD_BUFFER_SIZE;
727 }
728
729 // The size of the buffer must be a multiple of the block size
730 DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BlockSize=0x%x bytes.\n", Instance->Media.BlockSize ));
731 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {
732 return EFI_BAD_BUFFER_SIZE;
733 }
734
735 // All blocks must be within the device
736 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;
737
738 DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld\n", NumBlocks, Instance->Media.LastBlock, Lba));
739
740 if ( ( Lba + NumBlocks ) > (Instance->Media.LastBlock + 1) ) {
741 DEBUG((EFI_D_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
742 return EFI_INVALID_PARAMETER;
743 }
744
745 // Get the address to start reading from
746 StartAddress = GET_NOR_BLOCK_ADDRESS( Instance->BaseAddress,
747 Lba,
748 Instance->Media.BlockSize
749 );
750
751 // Put the device into Read Array mode
752 SEND_NOR_COMMAND( Instance->BaseAddress, 0, P30_CMD_READ_ARRAY );
753
754 // Readout the data
755 CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes);
756
757 return EFI_SUCCESS;
758}
759
760
761EFI_STATUS
762NorFlashReset (
763 IN NOR_FLASH_INSTANCE *Instance
764 )
765{
766 DEBUG((DEBUG_BLKIO, "NorFlashReset(BaseAddress=0x%08x)\n", Instance->BaseAddress));
767
768 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
769 SEND_NOR_COMMAND( Instance->BaseAddress, 0, P30_CMD_READ_ARRAY );
770
771 return EFI_SUCCESS;
772}
773
774
775
776EFI_STATUS
777EFIAPI
778NorFlashInitialise (
779 IN EFI_HANDLE ImageHandle,
780 IN EFI_SYSTEM_TABLE *SystemTable
781 )
782{
783 EFI_STATUS Status = EFI_SUCCESS;
784 UINT32 Index;
785
786 for (Index = 0; Index < NOR_FLASH_LAST_DEVICE; Index++) {
787 Status = NorFlashCreateInstance(
788 mNorFlashDescription[Index].BaseAddress,
789 mNorFlashDescription[Index].Size,
790 Index,
791 mNorFlashDescription[Index].BlockSize,
792 mNorFlashDescription[Index].SupportFvb,
793 &mNorFlashDescription[Index].Guid,
794 &mNorFlashInstances[Index]
795 );
796 if (EFI_ERROR(Status)) {
797 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index));
798 }
799 }
800
801 return Status;
802}