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