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