]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
ArmPlatformPkg/NorFlashDxe: Update copyright date
[mirror_edk2.git] / ArmPlatformPkg / Drivers / NorFlashDxe / NorFlashDxe.c
CommitLineData
1d5d0ae9 1/** @file NorFlashDxe.c
2
6acb379f 3 Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
1d5d0ae9 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>
1d5d0ae9 15#include <Library/BaseMemoryLib.h>
16#include <Library/MemoryAllocationLib.h>
17#include <Library/UefiBootServicesTableLib.h>
6acb379f 18#include <Library/PcdLib.h>
1d5d0ae9 19
20#include "NorFlashDxe.h"
21
22
23//
24// Global variable declarations
25//
d5e12da4 26NOR_FLASH_INSTANCE **mNorFlashInstances;
1d5d0ae9 27
28NOR_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
d5e12da4 37 0, // StartLba
1d5d0ae9 38
39 {\r
40 EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision\r
41 NULL, // Media ... NEED TO BE FILLED\r
42 NorFlashBlockIoReset, // Reset;\r
43 NorFlashBlockIoReadBlocks, // ReadBlocks
44 NorFlashBlockIoWriteBlocks, // WriteBlocks
45 NorFlashBlockIoFlushBlocks // FlushBlocks\r
46 }, // BlockIoProtocol
47
48 {\r
49 0, // MediaId ... NEED TO BE FILLED\r
50 FALSE, // RemovableMedia\r
51 TRUE, // MediaPresent\r
52 FALSE, // LogicalPartition\r
53 FALSE, // ReadOnly\r
54 FALSE, // WriteCaching;\r
55 0, // BlockSize ... NEED TO BE FILLED\r
56 4, // IoAlign\r
57 0, // LastBlock ... NEED TO BE FILLED\r
58 0, // LowestAlignedLba\r
59 1, // LogicalBlocksPerPhysicalBlock\r
60 }, //Media;
61
62 FALSE, // SupportFvb ... NEED TO BE FILLED
63 {\r
64 FvbGetAttributes, // GetAttributes
65 FvbSetAttributes, // SetAttributes
66 FvbGetPhysicalAddress, // GetPhysicalAddress
67 FvbGetBlockSize, // GetBlockSize
68 FvbRead, // Read
69 FvbWrite, // Write
70 FvbEraseBlocks, // EraseBlocks\r
71 NULL, //ParentHandle\r
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
d5e12da4 93EFI_STATUS
94NorFlashCreateInstance (
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{
1d5d0ae9 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\r
122 CopyGuid (&Instance->DevicePath.Vendor.Guid,NorFlashGuid);\r
123
124 if (SupportFvb) {
125 Instance->SupportFvb = TRUE;
126 Instance->Initialize = NorFlashFvbInitialize;
127
128 Status = gBS->InstallMultipleProtocolInterfaces (
129 &Instance->Handle,
130 &gEfiDevicePathProtocolGuid, &Instance->DevicePath,
d5e12da4 131 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol,
1d5d0ae9 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\r
154 *NorFlashInstance = Instance;\r
155 return Status;\r
156}
157
158EFI_STATUS
159NorFlashReadCfiData (
160 IN UINTN BaseAddress,
d5e12da4 161 IN UINTN CfiOffset,
1d5d0ae9 162 IN UINT32 NumberOfBytes,
163 OUT UINT32 *Data
d5e12da4 164 )
1d5d0ae9 165{
166 UINT32 CurrentByte;
d5e12da4 167 UINTN ReadAddress;
1d5d0ae9 168 UINT32 ReadData;
169 UINT32 Byte1;
170 UINT32 Byte2;
171 UINT32 CombinedData = 0;
172 EFI_STATUS Status = EFI_SUCCESS;
173
174
d5e12da4 175 if (NumberOfBytes > 4) {
1d5d0ae9 176 // Using 32 bit variable so can only read 4 bytes
177 return EFI_INVALID_PARAMETER;
178 }
179
d5e12da4 180 // First combine the base address with the offset address to create an absolute read address.
1d5d0ae9 181 // However, because we are in little endian, read from the last address down to the first
d5e12da4 182 ReadAddress = CREATE_NOR_ADDRESS (BaseAddress, CfiOffset) + (NumberOfBytes - 1) * sizeof(UINT32);
1d5d0ae9 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.
d5e12da4 192 for (CurrentByte=0; CurrentByte<NumberOfBytes; CurrentByte++) {
1d5d0ae9 193 // Read the bytes from the two chips
d5e12da4 194 ReadData = MmioRead32(ReadAddress);
1d5d0ae9 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.
d5e12da4 200 Byte1 = GET_LOW_BYTE (ReadData);
201 Byte2 = GET_HIGH_BYTE(ReadData);
1d5d0ae9 202
d5e12da4 203 if(Byte1 != Byte2) {
1d5d0ae9 204 // The two bytes should have been identical
205 return EFI_DEVICE_ERROR;
206 } else {
1d5d0ae9 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
d5e12da4 213 ReadAddress -= sizeof(UINT32);
1d5d0ae9 214 }
215 }
216
217 *Data = CombinedData;
218
219 return Status;
220}
221
222EFI_STATUS
d5e12da4 223NorFlashReadStatusRegister (
1d5d0ae9 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
d5e12da4 237 SEND_NOR_COMMAND (SR_Address, 0, P30_CMD_READ_STATUS_REGISTER);
1d5d0ae9 238 // Snapshot the status register
239 StatusRegister = *pStatusRegister;
240 }
241 // The chip is busy while the WRITE bit is not asserted
d5e12da4 242 while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
1d5d0ae9 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 {\r
262 DEBUG((EFI_D_ERROR,"NorFlashReadStatusRegister: Error (0x%X)\n",Status));\r
263 }
264
265 // If an error is detected we must clear the Status Register
d5e12da4 266 SEND_NOR_COMMAND(SR_Address, 0, P30_CMD_CLEAR_STATUS_REGISTER);
1d5d0ae9 267 Status = EFI_DEVICE_ERROR;
268 }
269
d5e12da4 270 SEND_NOR_COMMAND(SR_Address, 0, P30_CMD_READ_ARRAY);
1d5d0ae9 271
272 return Status;
273}
274
275
276BOOLEAN
d5e12da4 277NorFlashBlockIsLocked (
1d5d0ae9 278 IN UINTN BlockAddress
279 )
280{
1d5d0ae9 281 UINT32 LockStatus;
282 BOOLEAN BlockIsLocked = TRUE;
283
1d5d0ae9 284 // Send command for reading device id
d5e12da4 285 SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
1d5d0ae9 286
287 // Read block lock status
d5e12da4 288 LockStatus = MmioRead32 (CREATE_NOR_ADDRESS( BlockAddress, 2 ));
1d5d0ae9 289
290 // Decode block lock status
291 LockStatus = FOLD_32BIT_INTO_16BIT(LockStatus);
292
d5e12da4 293 if((LockStatus & 0x2) != 0) {
1d5d0ae9 294 DEBUG((EFI_D_ERROR, "UnlockSingleBlock: WARNING: Block LOCKED DOWN\n"));
295 }
296
d5e12da4 297 if((LockStatus & 0x1) == 0) {
1d5d0ae9 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
307EFI_STATUS
d5e12da4 308NorFlashUnlockSingleBlock (
1d5d0ae9 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
d5e12da4 317 // Request a lock setup
318 SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
1d5d0ae9 319
d5e12da4 320 // Request an unlock
321 SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
1d5d0ae9 322
323 // Put device back into Read Array mode
d5e12da4 324 SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_READ_ARRAY);
1d5d0ae9 325
326 DEBUG((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x, Exit Status = \"%r\".\n", BlockAddress, Status));
327
328 return Status;
329}
330
331
332EFI_STATUS
d5e12da4 333NorFlashUnlockSingleBlockIfNecessary (
1d5d0ae9 334 IN UINTN BlockAddress
335 )
336{
337 EFI_STATUS Status = EFI_SUCCESS;
338
d5e12da4 339 if ( NorFlashBlockIsLocked(BlockAddress) == TRUE ) {
340 Status = NorFlashUnlockSingleBlock(BlockAddress);
1d5d0ae9 341 }
342
343 return Status;
344}
345
346
347/**
348 * The following function presumes that the block has already been unlocked.
349 **/
350EFI_STATUS
d5e12da4 351NorFlashEraseSingleBlock (
1d5d0ae9 352 IN UINTN BlockAddress
353 )
354{
355 EFI_STATUS Status = EFI_SUCCESS;
356
357 // Request a block erase and then confirm it
d5e12da4 358 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);
359 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);
1d5d0ae9 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 **/
372EFI_STATUS
d5e12da4 373NorFlashUnlockAndEraseSingleBlock (
1d5d0ae9 374 IN UINTN BlockAddress
375 )
376{
377 EFI_STATUS Status;
378
379 // Unlock the block if we have to
d5e12da4 380 Status = NorFlashUnlockSingleBlockIfNecessary (BlockAddress);
1d5d0ae9 381 if (!EFI_ERROR(Status)) {
d5e12da4 382 Status = NorFlashEraseSingleBlock(BlockAddress);
1d5d0ae9 383 }
384
385 return Status;
386}
387
388
389EFI_STATUS
390NorFlashWriteSingleWord (
d5e12da4 391 IN UINTN WordAddress,
392 IN UINT32 WriteData
1d5d0ae9 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 */
428EFI_STATUS
429NorFlashWriteBuffer (
d5e12da4 430 IN UINTN TargetAddress,
431 IN UINTN BufferSizeInBytes,
432 IN UINT32 *Buffer
1d5d0ae9 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
509EFI_STATUS
510NorFlashWriteSingleBlock (
d5e12da4 511 IN UINTN DeviceBaseAddress,
512 IN EFI_LBA Lba,
513 IN UINT32 *DataBuffer,
514 IN UINT32 BlockSizeInWords
1d5d0ae9 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
d5e12da4 540 if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {
1d5d0ae9 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
586EFI_STATUS
587NorFlashWriteBlocks (
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;
1d5d0ae9 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
1d5d0ae9 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
656EFI_STATUS
657NorFlashReadBlocks (
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
d5e12da4 695 StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->BaseAddress,
1d5d0ae9 696 Lba,
697 Instance->Media.BlockSize
d5e12da4 698 );
1d5d0ae9 699
700 // Put the device into Read Array mode
d5e12da4 701 SEND_NOR_COMMAND (Instance->BaseAddress, 0, P30_CMD_READ_ARRAY);
1d5d0ae9 702
703 // Readout the data
704 CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes);
705
706 return EFI_SUCCESS;
707}
708
709
710EFI_STATUS
711NorFlashReset (
712 IN NOR_FLASH_INSTANCE *Instance
713 )
714{
1d5d0ae9 715 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
d5e12da4 716 SEND_NOR_COMMAND( Instance->BaseAddress, 0, P30_CMD_READ_ARRAY);
1d5d0ae9 717 return EFI_SUCCESS;
718}
719
720
721
722EFI_STATUS
723EFIAPI
724NorFlashInitialise (
725 IN EFI_HANDLE ImageHandle,
726 IN EFI_SYSTEM_TABLE *SystemTable
727 )
728{
d5e12da4 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);
1d5d0ae9 754
d5e12da4 755 Status = NorFlashCreateInstance (
756 NorFlashDevices[Index].BaseAddress,
757 NorFlashDevices[Index].Size,
1d5d0ae9 758 Index,
d5e12da4 759 NorFlashDevices[Index].BlockSize,
760 ContainVariableStorage,
761 &NorFlashDevices[Index].Guid,
1d5d0ae9 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}