1 /** @file NorFlashDxe.c 2 3 Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR> 4 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include <Library/UefiLib.h> 16 #include <Library/BaseMemoryLib.h> 17 #include <Library/MemoryAllocationLib.h> 18 #include <Library/UefiBootServicesTableLib.h> 19 #include <Library/PcdLib.h> 20 21 #include "NorFlashDxe.h" 22 23 STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent; 24 25 // 26 // Global variable declarations 27 // 28 NOR_FLASH_INSTANCE **mNorFlashInstances; 29 UINT32 mNorFlashDeviceCount; 30 31 NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = { 32 NOR_FLASH_SIGNATURE, // Signature 33 NULL, // Handle ... NEED TO BE FILLED 34 35 FALSE, // Initialized 36 NULL, // Initialize 37 38 0, // DeviceBaseAddress ... NEED TO BE FILLED 39 0, // RegionBaseAddress ... NEED TO BE FILLED 40 0, // Size ... NEED TO BE FILLED 41 0, // StartLba 42 43 { 44 EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision 45 NULL, // Media ... NEED TO BE FILLED 46 NorFlashBlockIoReset, // Reset; 47 NorFlashBlockIoReadBlocks, // ReadBlocks 48 NorFlashBlockIoWriteBlocks, // WriteBlocks 49 NorFlashBlockIoFlushBlocks // FlushBlocks 50 }, // BlockIoProtocol 51 52 { 53 0, // MediaId ... NEED TO BE FILLED 54 FALSE, // RemovableMedia 55 TRUE, // MediaPresent 56 FALSE, // LogicalPartition 57 FALSE, // ReadOnly 58 FALSE, // WriteCaching; 59 0, // BlockSize ... NEED TO BE FILLED 60 4, // IoAlign 61 0, // LastBlock ... NEED TO BE FILLED 62 0, // LowestAlignedLba 63 1, // LogicalBlocksPerPhysicalBlock 64 }, //Media; 65 66 { 67 EFI_DISK_IO_PROTOCOL_REVISION, // Revision 68 NorFlashDiskIoReadDisk, // ReadDisk 69 NorFlashDiskIoWriteDisk // WriteDisk 70 }, 71 72 FALSE, // SupportFvb ... NEED TO BE FILLED 73 { 74 FvbGetAttributes, // GetAttributes 75 FvbSetAttributes, // SetAttributes 76 FvbGetPhysicalAddress, // GetPhysicalAddress 77 FvbGetBlockSize, // GetBlockSize 78 FvbRead, // Read 79 FvbWrite, // Write 80 FvbEraseBlocks, // EraseBlocks 81 NULL, //ParentHandle 82 }, // FvbProtoccol; 83 NULL, // ShadowBuffer 84 { 85 { 86 { 87 HARDWARE_DEVICE_PATH, 88 HW_VENDOR_DP, 89 { (UINT8)sizeof(VENDOR_DEVICE_PATH), (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8) } 90 }, 91 { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }, // GUID ... NEED TO BE FILLED 92 }, 93 { 94 END_DEVICE_PATH_TYPE, 95 END_ENTIRE_DEVICE_PATH_SUBTYPE, 96 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } 97 } 98 } // DevicePath 99 }; 100 101 EFI_STATUS 102 NorFlashCreateInstance ( 103 IN UINTN NorFlashDeviceBase, 104 IN UINTN NorFlashRegionBase, 105 IN UINTN NorFlashSize, 106 IN UINT32 MediaId, 107 IN UINT32 BlockSize, 108 IN BOOLEAN SupportFvb, 109 IN CONST GUID *NorFlashGuid, 110 OUT NOR_FLASH_INSTANCE** NorFlashInstance 111 ) 112 { 113 EFI_STATUS Status; 114 NOR_FLASH_INSTANCE* Instance; 115 116 ASSERT(NorFlashInstance != NULL); 117 118 Instance = AllocateRuntimeCopyPool (sizeof(NOR_FLASH_INSTANCE),&mNorFlashInstanceTemplate); 119 if (Instance == NULL) { 120 return EFI_OUT_OF_RESOURCES; 121 } 122 123 Instance->DeviceBaseAddress = NorFlashDeviceBase; 124 Instance->RegionBaseAddress = NorFlashRegionBase; 125 Instance->Size = NorFlashSize; 126 127 Instance->BlockIoProtocol.Media = &Instance->Media; 128 Instance->Media.MediaId = MediaId; 129 Instance->Media.BlockSize = BlockSize; 130 Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1; 131 132 CopyGuid (&Instance->DevicePath.Vendor.Guid, NorFlashGuid); 133 134 Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);; 135 if (Instance->ShadowBuffer == NULL) { 136 return EFI_OUT_OF_RESOURCES; 137 } 138 139 if (SupportFvb) { 140 Instance->SupportFvb = TRUE; 141 Instance->Initialize = NorFlashFvbInitialize; 142 143 Status = gBS->InstallMultipleProtocolInterfaces ( 144 &Instance->Handle, 145 &gEfiDevicePathProtocolGuid, &Instance->DevicePath, 146 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol, 147 &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol, 148 NULL 149 ); 150 if (EFI_ERROR(Status)) { 151 FreePool (Instance); 152 return Status; 153 } 154 } else { 155 Instance->Initialized = TRUE; 156 157 Status = gBS->InstallMultipleProtocolInterfaces ( 158 &Instance->Handle, 159 &gEfiDevicePathProtocolGuid, &Instance->DevicePath, 160 &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol, 161 &gEfiDiskIoProtocolGuid, &Instance->DiskIoProtocol, 162 NULL 163 ); 164 if (EFI_ERROR(Status)) { 165 FreePool (Instance); 166 return Status; 167 } 168 } 169 170 *NorFlashInstance = Instance; 171 return Status; 172 } 173 174 UINT32 175 NorFlashReadStatusRegister ( 176 IN NOR_FLASH_INSTANCE *Instance, 177 IN UINTN SR_Address 178 ) 179 { 180 // Prepare to read the status register 181 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER); 182 return MmioRead32 (Instance->DeviceBaseAddress); 183 } 184 185 STATIC 186 BOOLEAN 187 NorFlashBlockIsLocked ( 188 IN NOR_FLASH_INSTANCE *Instance, 189 IN UINTN BlockAddress 190 ) 191 { 192 UINT32 LockStatus; 193 194 // Send command for reading device id 195 SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID); 196 197 // Read block lock status 198 LockStatus = MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress, 2)); 199 200 // Decode block lock status 201 LockStatus = FOLD_32BIT_INTO_16BIT(LockStatus); 202 203 if ((LockStatus & 0x2) != 0) { 204 DEBUG((EFI_D_ERROR, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n")); 205 } 206 207 return ((LockStatus & 0x1) != 0); 208 } 209 210 STATIC 211 EFI_STATUS 212 NorFlashUnlockSingleBlock ( 213 IN NOR_FLASH_INSTANCE *Instance, 214 IN UINTN BlockAddress 215 ) 216 { 217 UINT32 LockStatus; 218 219 // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations 220 // and to protect shared data structures. 221 222 if (FeaturePcdGet (PcdNorFlashCheckBlockLocked) == TRUE) { 223 do { 224 // Request a lock setup 225 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP); 226 227 // Request an unlock 228 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK); 229 230 // Send command for reading device id 231 SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID); 232 233 // Read block lock status 234 LockStatus = MmioRead32 (CREATE_NOR_ADDRESS(BlockAddress, 2)); 235 236 // Decode block lock status 237 LockStatus = FOLD_32BIT_INTO_16BIT(LockStatus); 238 } while ((LockStatus & 0x1) == 1); 239 } else { 240 // Request a lock setup 241 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP); 242 243 // Request an unlock 244 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK); 245 246 // Wait until the status register gives us the all clear 247 do { 248 LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress); 249 } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE); 250 } 251 252 // Put device back into Read Array mode 253 SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY); 254 255 DEBUG((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress)); 256 257 return EFI_SUCCESS; 258 } 259 260 STATIC 261 EFI_STATUS 262 NorFlashUnlockSingleBlockIfNecessary ( 263 IN NOR_FLASH_INSTANCE *Instance, 264 IN UINTN BlockAddress 265 ) 266 { 267 EFI_STATUS Status; 268 269 Status = EFI_SUCCESS; 270 271 if (NorFlashBlockIsLocked (Instance, BlockAddress) == TRUE) { 272 Status = NorFlashUnlockSingleBlock (Instance, BlockAddress); 273 } 274 275 return Status; 276 } 277 278 279 /** 280 * The following function presumes that the block has already been unlocked. 281 **/ 282 STATIC 283 EFI_STATUS 284 NorFlashEraseSingleBlock ( 285 IN NOR_FLASH_INSTANCE *Instance, 286 IN UINTN BlockAddress 287 ) 288 { 289 EFI_STATUS Status; 290 UINT32 StatusRegister; 291 292 Status = EFI_SUCCESS; 293 294 // Request a block erase and then confirm it 295 SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP); 296 SEND_NOR_COMMAND(BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM); 297 298 // Wait until the status register gives us the all clear 299 do { 300 StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress); 301 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE); 302 303 if (StatusRegister & P30_SR_BIT_VPP) { 304 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress)); 305 Status = EFI_DEVICE_ERROR; 306 } 307 308 if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) == (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) { 309 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress)); 310 Status = EFI_DEVICE_ERROR; 311 } 312 313 if (StatusRegister & P30_SR_BIT_ERASE) { 314 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister)); 315 Status = EFI_DEVICE_ERROR; 316 } 317 318 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) { 319 // The debug level message has been reduced because a device lock might happen. In this case we just retry it ... 320 DEBUG((EFI_D_INFO,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress)); 321 Status = EFI_WRITE_PROTECTED; 322 } 323 324 if (EFI_ERROR(Status)) { 325 // Clear the Status Register 326 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER); 327 } 328 329 // Put device back into Read Array mode 330 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY); 331 332 return Status; 333 } 334 335 /** 336 * This function unlock and erase an entire NOR Flash block. 337 **/ 338 EFI_STATUS 339 NorFlashUnlockAndEraseSingleBlock ( 340 IN NOR_FLASH_INSTANCE *Instance, 341 IN UINTN BlockAddress 342 ) 343 { 344 EFI_STATUS Status; 345 UINTN Index; 346 EFI_TPL OriginalTPL; 347 348 if (!EfiAtRuntime ()) { 349 // Raise TPL to TPL_HIGH to stop anyone from interrupting us. 350 OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); 351 } else { 352 // This initialization is only to prevent the compiler to complain about the 353 // use of uninitialized variables 354 OriginalTPL = TPL_HIGH_LEVEL; 355 } 356 357 Index = 0; 358 // The block erase might fail a first time (SW bug ?). Retry it ... 359 do { 360 // Unlock the block if we have to 361 Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress); 362 if (EFI_ERROR (Status)) { 363 break; 364 } 365 Status = NorFlashEraseSingleBlock (Instance, BlockAddress); 366 Index++; 367 } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED)); 368 369 if (Index == NOR_FLASH_ERASE_RETRY) { 370 DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress,Index)); 371 } 372 373 if (!EfiAtRuntime ()) { 374 // Interruptions can resume. 375 gBS->RestoreTPL (OriginalTPL); 376 } 377 378 return Status; 379 } 380 381 382 STATIC 383 EFI_STATUS 384 NorFlashWriteSingleWord ( 385 IN NOR_FLASH_INSTANCE *Instance, 386 IN UINTN WordAddress, 387 IN UINT32 WriteData 388 ) 389 { 390 EFI_STATUS Status; 391 UINT32 StatusRegister; 392 393 Status = EFI_SUCCESS; 394 395 // Request a write single word command 396 SEND_NOR_COMMAND(WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP); 397 398 // Store the word into NOR Flash; 399 MmioWrite32 (WordAddress, WriteData); 400 401 // Wait for the write to complete and then check for any errors; i.e. check the Status Register 402 do { 403 // Prepare to read the status register 404 StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress); 405 // The chip is busy while the WRITE bit is not asserted 406 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE); 407 408 409 // Perform a full status check: 410 // Mask the relevant bits of Status Register. 411 // Everything should be zero, if not, we have a problem 412 413 if (StatusRegister & P30_SR_BIT_VPP) { 414 DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n",WordAddress)); 415 Status = EFI_DEVICE_ERROR; 416 } 417 418 if (StatusRegister & P30_SR_BIT_PROGRAM) { 419 DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n",WordAddress)); 420 Status = EFI_DEVICE_ERROR; 421 } 422 423 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) { 424 DEBUG((EFI_D_ERROR,"NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n",WordAddress)); 425 Status = EFI_DEVICE_ERROR; 426 } 427 428 if (!EFI_ERROR(Status)) { 429 // Clear the Status Register 430 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER); 431 } 432 433 // Put device back into Read Array mode 434 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY); 435 436 return Status; 437 } 438 439 /* 440 * Writes data to the NOR Flash using the Buffered Programming method. 441 * 442 * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions. 443 * Therefore this function will only handle buffers up to 32 words or 128 bytes. 444 * To deal with larger buffers, call this function again. 445 * 446 * This function presumes that both the TargetAddress and the TargetAddress+BufferSize 447 * exist entirely within the NOR Flash. Therefore these conditions will not be checked here. 448 * 449 * In buffered programming, if the target address not at the beginning of a 32-bit word boundary, 450 * then programming time is doubled and power consumption is increased. 451 * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries. 452 * i.e. the last 4 bits of the target start address must be zero: 0x......00 453 */ 454 EFI_STATUS 455 NorFlashWriteBuffer ( 456 IN NOR_FLASH_INSTANCE *Instance, 457 IN UINTN TargetAddress, 458 IN UINTN BufferSizeInBytes, 459 IN UINT32 *Buffer 460 ) 461 { 462 EFI_STATUS Status; 463 UINTN BufferSizeInWords; 464 UINTN Count; 465 volatile UINT32 *Data; 466 UINTN WaitForBuffer; 467 BOOLEAN BufferAvailable; 468 UINT32 StatusRegister; 469 470 WaitForBuffer = MAX_BUFFERED_PROG_ITERATIONS; 471 BufferAvailable = FALSE; 472 473 // Check that the target address does not cross a 32-word boundary. 474 if ((TargetAddress & BOUNDARY_OF_32_WORDS) != 0) { 475 return EFI_INVALID_PARAMETER; 476 } 477 478 // Check there are some data to program 479 if (BufferSizeInBytes == 0) { 480 return EFI_BUFFER_TOO_SMALL; 481 } 482 483 // Check that the buffer size does not exceed the maximum hardware buffer size on chip. 484 if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) { 485 return EFI_BAD_BUFFER_SIZE; 486 } 487 488 // Check that the buffer size is a multiple of 32-bit words 489 if ((BufferSizeInBytes % 4) != 0) { 490 return EFI_BAD_BUFFER_SIZE; 491 } 492 493 // Pre-programming conditions checked, now start the algorithm. 494 495 // Prepare the data destination address 496 Data = (UINT32 *)TargetAddress; 497 498 // Check the availability of the buffer 499 do { 500 // Issue the Buffered Program Setup command 501 SEND_NOR_COMMAND(TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP); 502 503 // Read back the status register bit#7 from the same address 504 if (((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE) { 505 BufferAvailable = TRUE; 506 } 507 508 // Update the loop counter 509 WaitForBuffer--; 510 511 } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE)); 512 513 // The buffer was not available for writing 514 if (WaitForBuffer == 0) { 515 Status = EFI_DEVICE_ERROR; 516 goto EXIT; 517 } 518 519 // From now on we work in 32-bit words 520 BufferSizeInWords = BufferSizeInBytes / (UINTN)4; 521 522 // Write the word count, which is (buffer_size_in_words - 1), 523 // because word count 0 means one word. 524 SEND_NOR_COMMAND(TargetAddress, 0, (BufferSizeInWords - 1)); 525 526 // Write the data to the NOR Flash, advancing each address by 4 bytes 527 for(Count=0; Count < BufferSizeInWords; Count++, Data++, Buffer++) { 528 MmioWrite32 ((UINTN)Data, *Buffer); 529 } 530 531 // Issue the Buffered Program Confirm command, to start the programming operation 532 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM); 533 534 // Wait for the write to complete and then check for any errors; i.e. check the Status Register 535 do { 536 StatusRegister = NorFlashReadStatusRegister (Instance, TargetAddress); 537 // The chip is busy while the WRITE bit is not asserted 538 } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE); 539 540 541 // Perform a full status check: 542 // Mask the relevant bits of Status Register. 543 // Everything should be zero, if not, we have a problem 544 545 Status = EFI_SUCCESS; 546 547 if (StatusRegister & P30_SR_BIT_VPP) { 548 DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress)); 549 Status = EFI_DEVICE_ERROR; 550 } 551 552 if (StatusRegister & P30_SR_BIT_PROGRAM) { 553 DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress)); 554 Status = EFI_DEVICE_ERROR; 555 } 556 557 if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) { 558 DEBUG((EFI_D_ERROR,"NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n",TargetAddress)); 559 Status = EFI_DEVICE_ERROR; 560 } 561 562 if (!EFI_ERROR(Status)) { 563 // Clear the Status Register 564 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER); 565 } 566 567 EXIT: 568 // Put device back into Read Array mode 569 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY); 570 571 return Status; 572 } 573 574 STATIC 575 EFI_STATUS 576 NorFlashWriteFullBlock ( 577 IN NOR_FLASH_INSTANCE *Instance, 578 IN EFI_LBA Lba, 579 IN UINT32 *DataBuffer, 580 IN UINT32 BlockSizeInWords 581 ) 582 { 583 EFI_STATUS Status; 584 UINTN WordAddress; 585 UINT32 WordIndex; 586 UINTN BufferIndex; 587 UINTN BlockAddress; 588 UINTN BuffersInBlock; 589 UINTN RemainingWords; 590 EFI_TPL OriginalTPL; 591 UINTN Cnt; 592 593 Status = EFI_SUCCESS; 594 595 // Get the physical address of the block 596 BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4); 597 598 // Start writing from the first address at the start of the block 599 WordAddress = BlockAddress; 600 601 if (!EfiAtRuntime ()) { 602 // Raise TPL to TPL_HIGH to stop anyone from interrupting us. 603 OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); 604 } else { 605 // This initialization is only to prevent the compiler to complain about the 606 // use of uninitialized variables 607 OriginalTPL = TPL_HIGH_LEVEL; 608 } 609 610 Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress); 611 if (EFI_ERROR(Status)) { 612 DEBUG((EFI_D_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress)); 613 goto EXIT; 614 } 615 616 // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method. 617 618 // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero 619 if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) { 620 621 // First, break the entire block into buffer-sized chunks. 622 BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES; 623 624 // Then feed each buffer chunk to the NOR Flash 625 // If a buffer does not contain any data, don't write it. 626 for(BufferIndex=0; 627 BufferIndex < BuffersInBlock; 628 BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS 629 ) { 630 // Check the buffer to see if it contains any data (not set all 1s). 631 for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) { 632 if (~DataBuffer[Cnt] != 0 ) { 633 // Some data found, write the buffer. 634 Status = NorFlashWriteBuffer (Instance, WordAddress, P30_MAX_BUFFER_SIZE_IN_BYTES, 635 DataBuffer); 636 if (EFI_ERROR(Status)) { 637 goto EXIT; 638 } 639 break; 640 } 641 } 642 } 643 644 // Finally, finish off any remaining words that are less than the maximum size of the buffer 645 RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS; 646 647 if(RemainingWords != 0) { 648 Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer); 649 if (EFI_ERROR(Status)) { 650 goto EXIT; 651 } 652 } 653 654 } else { 655 // For now, use the single word programming algorithm 656 // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range, 657 // i.e. which ends in the range 0x......01 - 0x......7F. 658 for(WordIndex=0; WordIndex<BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) { 659 Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer); 660 if (EFI_ERROR(Status)) { 661 goto EXIT; 662 } 663 } 664 } 665 666 EXIT: 667 if (!EfiAtRuntime ()) { 668 // Interruptions can resume. 669 gBS->RestoreTPL (OriginalTPL); 670 } 671 672 if (EFI_ERROR(Status)) { 673 DEBUG((EFI_D_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status)); 674 } 675 return Status; 676 } 677 678 679 EFI_STATUS 680 NorFlashWriteBlocks ( 681 IN NOR_FLASH_INSTANCE *Instance, 682 IN EFI_LBA Lba, 683 IN UINTN BufferSizeInBytes, 684 IN VOID *Buffer 685 ) 686 { 687 UINT32 *pWriteBuffer; 688 EFI_STATUS Status = EFI_SUCCESS; 689 EFI_LBA CurrentBlock; 690 UINT32 BlockSizeInWords; 691 UINT32 NumBlocks; 692 UINT32 BlockCount; 693 694 // The buffer must be valid 695 if (Buffer == NULL) { 696 return EFI_INVALID_PARAMETER; 697 } 698 699 if(Instance->Media.ReadOnly == TRUE) { 700 return EFI_WRITE_PROTECTED; 701 } 702 703 // We must have some bytes to read 704 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes)); 705 if(BufferSizeInBytes == 0) { 706 return EFI_BAD_BUFFER_SIZE; 707 } 708 709 // The size of the buffer must be a multiple of the block size 710 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance->Media.BlockSize)); 711 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) { 712 return EFI_BAD_BUFFER_SIZE; 713 } 714 715 // All blocks must be within the device 716 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ; 717 718 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->Media.LastBlock, Lba)); 719 720 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) { 721 DEBUG((EFI_D_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n")); 722 return EFI_INVALID_PARAMETER; 723 } 724 725 BlockSizeInWords = Instance->Media.BlockSize / 4; 726 727 // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer 728 // to a proper data type, so use *ReadBuffer 729 pWriteBuffer = (UINT32 *)Buffer; 730 731 CurrentBlock = Lba; 732 for (BlockCount=0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) { 733 734 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock)); 735 736 Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, BlockSizeInWords); 737 738 if (EFI_ERROR(Status)) { 739 break; 740 } 741 } 742 743 DEBUG((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status)); 744 return Status; 745 } 746 747 EFI_STATUS 748 NorFlashReadBlocks ( 749 IN NOR_FLASH_INSTANCE *Instance, 750 IN EFI_LBA Lba, 751 IN UINTN BufferSizeInBytes, 752 OUT VOID *Buffer 753 ) 754 { 755 UINT32 NumBlocks; 756 UINTN StartAddress; 757 758 DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n", 759 BufferSizeInBytes, Instance->Media.BlockSize, Instance->Media.LastBlock, Lba)); 760 761 // The buffer must be valid 762 if (Buffer == NULL) { 763 return EFI_INVALID_PARAMETER; 764 } 765 766 // Return if we have not any byte to read 767 if (BufferSizeInBytes == 0) { 768 return EFI_SUCCESS; 769 } 770 771 // The size of the buffer must be a multiple of the block size 772 if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) { 773 return EFI_BAD_BUFFER_SIZE; 774 } 775 776 // All blocks must be within the device 777 NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ; 778 779 if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) { 780 DEBUG((EFI_D_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n")); 781 return EFI_INVALID_PARAMETER; 782 } 783 784 // Get the address to start reading from 785 StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, 786 Lba, 787 Instance->Media.BlockSize 788 ); 789 790 // Put the device into Read Array mode 791 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY); 792 793 // Readout the data 794 CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes); 795 796 return EFI_SUCCESS; 797 } 798 799 EFI_STATUS 800 NorFlashRead ( 801 IN NOR_FLASH_INSTANCE *Instance, 802 IN EFI_LBA Lba, 803 IN UINTN Offset, 804 IN UINTN BufferSizeInBytes, 805 OUT VOID *Buffer 806 ) 807 { 808 UINTN StartAddress; 809 810 // The buffer must be valid 811 if (Buffer == NULL) { 812 return EFI_INVALID_PARAMETER; 813 } 814 815 // Return if we have not any byte to read 816 if (BufferSizeInBytes == 0) { 817 return EFI_SUCCESS; 818 } 819 820 if (((Lba * Instance->Media.BlockSize) + Offset + BufferSizeInBytes) > Instance->Size) { 821 DEBUG ((EFI_D_ERROR, "NorFlashRead: ERROR - Read will exceed device size.\n")); 822 return EFI_INVALID_PARAMETER; 823 } 824 825 // Get the address to start reading from 826 StartAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, 827 Lba, 828 Instance->Media.BlockSize 829 ); 830 831 // Put the device into Read Array mode 832 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY); 833 834 // Readout the data 835 CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes); 836 837 return EFI_SUCCESS; 838 } 839 840 /* 841 Write a full or portion of a block. It must not span block boundaries; that is, 842 Offset + *NumBytes <= Instance->Media.BlockSize. 843 */ 844 EFI_STATUS 845 NorFlashWriteSingleBlock ( 846 IN NOR_FLASH_INSTANCE *Instance, 847 IN EFI_LBA Lba, 848 IN UINTN Offset, 849 IN OUT UINTN *NumBytes, 850 IN UINT8 *Buffer 851 ) 852 { 853 EFI_STATUS TempStatus; 854 UINT32 Tmp; 855 UINT32 TmpBuf; 856 UINT32 WordToWrite; 857 UINT32 Mask; 858 BOOLEAN DoErase; 859 UINTN BytesToWrite; 860 UINTN CurOffset; 861 UINTN WordAddr; 862 UINTN BlockSize; 863 UINTN BlockAddress; 864 UINTN PrevBlockAddress; 865 866 PrevBlockAddress = 0; 867 868 if (!Instance->Initialized && Instance->Initialize) { 869 Instance->Initialize(Instance); 870 } 871 872 DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer)); 873 874 // Detect WriteDisabled state 875 if (Instance->Media.ReadOnly == TRUE) { 876 DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - Can not write: Device is in WriteDisabled state.\n")); 877 // It is in WriteDisabled state, return an error right away 878 return EFI_ACCESS_DENIED; 879 } 880 881 // Cache the block size to avoid de-referencing pointers all the time 882 BlockSize = Instance->Media.BlockSize; 883 884 // The write must not span block boundaries. 885 // We need to check each variable individually because adding two large values together overflows. 886 if ( ( Offset >= BlockSize ) || 887 ( *NumBytes > BlockSize ) || 888 ( (Offset + *NumBytes) > BlockSize ) ) { 889 DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); 890 return EFI_BAD_BUFFER_SIZE; 891 } 892 893 // We must have some bytes to write 894 if (*NumBytes == 0) { 895 DEBUG ((EFI_D_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); 896 return EFI_BAD_BUFFER_SIZE; 897 } 898 899 // Pick 128bytes as a good start for word operations as opposed to erasing the 900 // block and writing the data regardless if an erase is really needed. 901 // It looks like most individual NV variable writes are smaller than 128bytes. 902 if (*NumBytes <= 128) { 903 // Check to see if we need to erase before programming the data into NOR. 904 // If the destination bits are only changing from 1s to 0s we can just write. 905 // After a block is erased all bits in the block is set to 1. 906 // If any byte requires us to erase we just give up and rewrite all of it. 907 DoErase = FALSE; 908 BytesToWrite = *NumBytes; 909 CurOffset = Offset; 910 911 while (BytesToWrite > 0) { 912 // Read full word from NOR, splice as required. A word is the smallest 913 // unit we can write. 914 TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof(Tmp), &Tmp); 915 if (EFI_ERROR (TempStatus)) { 916 return EFI_DEVICE_ERROR; 917 } 918 919 // Physical address of word in NOR to write. 920 WordAddr = (CurOffset & ~(0x3)) + GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, 921 Lba, BlockSize); 922 // The word of data that is to be written. 923 TmpBuf = *((UINT32*)(Buffer + (*NumBytes - BytesToWrite))); 924 925 // First do word aligned chunks. 926 if ((CurOffset & 0x3) == 0) { 927 if (BytesToWrite >= 4) { 928 // Is the destination still in 'erased' state? 929 if (~Tmp != 0) { 930 // Check to see if we are only changing bits to zero. 931 if ((Tmp ^ TmpBuf) & TmpBuf) { 932 DoErase = TRUE; 933 break; 934 } 935 } 936 // Write this word to NOR 937 WordToWrite = TmpBuf; 938 CurOffset += sizeof(TmpBuf); 939 BytesToWrite -= sizeof(TmpBuf); 940 } else { 941 // BytesToWrite < 4. Do small writes and left-overs 942 Mask = ~((~0) << (BytesToWrite * 8)); 943 // Mask out the bytes we want. 944 TmpBuf &= Mask; 945 // Is the destination still in 'erased' state? 946 if ((Tmp & Mask) != Mask) { 947 // Check to see if we are only changing bits to zero. 948 if ((Tmp ^ TmpBuf) & TmpBuf) { 949 DoErase = TRUE; 950 break; 951 } 952 } 953 // Merge old and new data. Write merged word to NOR 954 WordToWrite = (Tmp & ~Mask) | TmpBuf; 955 CurOffset += BytesToWrite; 956 BytesToWrite = 0; 957 } 958 } else { 959 // Do multiple words, but starting unaligned. 960 if (BytesToWrite > (4 - (CurOffset & 0x3))) { 961 Mask = ((~0) << ((CurOffset & 0x3) * 8)); 962 // Mask out the bytes we want. 963 TmpBuf &= Mask; 964 // Is the destination still in 'erased' state? 965 if ((Tmp & Mask) != Mask) { 966 // Check to see if we are only changing bits to zero. 967 if ((Tmp ^ TmpBuf) & TmpBuf) { 968 DoErase = TRUE; 969 break; 970 } 971 } 972 // Merge old and new data. Write merged word to NOR 973 WordToWrite = (Tmp & ~Mask) | TmpBuf; 974 BytesToWrite -= (4 - (CurOffset & 0x3)); 975 CurOffset += (4 - (CurOffset & 0x3)); 976 } else { 977 // Unaligned and fits in one word. 978 Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8); 979 // Mask out the bytes we want. 980 TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask; 981 // Is the destination still in 'erased' state? 982 if ((Tmp & Mask) != Mask) { 983 // Check to see if we are only changing bits to zero. 984 if ((Tmp ^ TmpBuf) & TmpBuf) { 985 DoErase = TRUE; 986 break; 987 } 988 } 989 // Merge old and new data. Write merged word to NOR 990 WordToWrite = (Tmp & ~Mask) | TmpBuf; 991 CurOffset += BytesToWrite; 992 BytesToWrite = 0; 993 } 994 } 995 996 // 997 // Write the word to NOR. 998 // 999 1000 BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize); 1001 if (BlockAddress != PrevBlockAddress) { 1002 TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress); 1003 if (EFI_ERROR (TempStatus)) { 1004 return EFI_DEVICE_ERROR; 1005 } 1006 PrevBlockAddress = BlockAddress; 1007 } 1008 TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite); 1009 if (EFI_ERROR (TempStatus)) { 1010 return EFI_DEVICE_ERROR; 1011 } 1012 } 1013 // Exit if we got here and could write all the data. Otherwise do the 1014 // Erase-Write cycle. 1015 if (!DoErase) { 1016 return EFI_SUCCESS; 1017 } 1018 } 1019 1020 // Check we did get some memory. Buffer is BlockSize. 1021 if (Instance->ShadowBuffer == NULL) { 1022 DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - Buffer not ready\n")); 1023 return EFI_DEVICE_ERROR; 1024 } 1025 1026 // Read NOR Flash data into shadow buffer 1027 TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer); 1028 if (EFI_ERROR (TempStatus)) { 1029 // Return one of the pre-approved error statuses 1030 return EFI_DEVICE_ERROR; 1031 } 1032 1033 // Put the data at the appropriate location inside the buffer area 1034 CopyMem ((VOID*)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes); 1035 1036 // Write the modified buffer back to the NorFlash 1037 TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer); 1038 if (EFI_ERROR (TempStatus)) { 1039 // Return one of the pre-approved error statuses 1040 return EFI_DEVICE_ERROR; 1041 } 1042 1043 return EFI_SUCCESS; 1044 } 1045 1046 /* 1047 Although DiskIoDxe will automatically install the DiskIO protocol whenever 1048 we install the BlockIO protocol, its implementation is sub-optimal as it reads 1049 and writes entire blocks using the BlockIO protocol. In fact we can access 1050 NOR flash with a finer granularity than that, so we can improve performance 1051 by directly producing the DiskIO protocol. 1052 */ 1053 1054 /** 1055 Read BufferSize bytes from Offset into Buffer. 1056 1057 @param This Protocol instance pointer. 1058 @param MediaId Id of the media, changes every time the media is replaced. 1059 @param Offset The starting byte offset to read from 1060 @param BufferSize Size of Buffer 1061 @param Buffer Buffer containing read data 1062 1063 @retval EFI_SUCCESS The data was read correctly from the device. 1064 @retval EFI_DEVICE_ERROR The device reported an error while performing the read. 1065 @retval EFI_NO_MEDIA There is no media in the device. 1066 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. 1067 @retval EFI_INVALID_PARAMETER The read request contains device addresses that are not 1068 valid for the device. 1069 1070 **/ 1071 EFI_STATUS 1072 EFIAPI 1073 NorFlashDiskIoReadDisk ( 1074 IN EFI_DISK_IO_PROTOCOL *This, 1075 IN UINT32 MediaId, 1076 IN UINT64 DiskOffset, 1077 IN UINTN BufferSize, 1078 OUT VOID *Buffer 1079 ) 1080 { 1081 NOR_FLASH_INSTANCE *Instance; 1082 UINT32 BlockSize; 1083 UINT32 BlockOffset; 1084 EFI_LBA Lba; 1085 1086 Instance = INSTANCE_FROM_DISKIO_THIS(This); 1087 1088 if (MediaId != Instance->Media.MediaId) { 1089 return EFI_MEDIA_CHANGED; 1090 } 1091 1092 BlockSize = Instance->Media.BlockSize; 1093 Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset); 1094 1095 return NorFlashRead (Instance, Lba, BlockOffset, BufferSize, Buffer); 1096 } 1097 1098 /** 1099 Writes a specified number of bytes to a device. 1100 1101 @param This Indicates a pointer to the calling context. 1102 @param MediaId ID of the medium to be written. 1103 @param Offset The starting byte offset on the logical block I/O device to write. 1104 @param BufferSize The size in bytes of Buffer. The number of bytes to write to the device. 1105 @param Buffer A pointer to the buffer containing the data to be written. 1106 1107 @retval EFI_SUCCESS The data was written correctly to the device. 1108 @retval EFI_WRITE_PROTECTED The device can not be written to. 1109 @retval EFI_DEVICE_ERROR The device reported an error while performing the write. 1110 @retval EFI_NO_MEDIA There is no media in the device. 1111 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device. 1112 @retval EFI_INVALID_PARAMETER The write request contains device addresses that are not 1113 valid for the device. 1114 1115 **/ 1116 EFI_STATUS 1117 EFIAPI 1118 NorFlashDiskIoWriteDisk ( 1119 IN EFI_DISK_IO_PROTOCOL *This, 1120 IN UINT32 MediaId, 1121 IN UINT64 DiskOffset, 1122 IN UINTN BufferSize, 1123 IN VOID *Buffer 1124 ) 1125 { 1126 NOR_FLASH_INSTANCE *Instance; 1127 UINT32 BlockSize; 1128 UINT32 BlockOffset; 1129 EFI_LBA Lba; 1130 UINTN RemainingBytes; 1131 UINTN WriteSize; 1132 EFI_STATUS Status; 1133 1134 Instance = INSTANCE_FROM_DISKIO_THIS(This); 1135 1136 if (MediaId != Instance->Media.MediaId) { 1137 return EFI_MEDIA_CHANGED; 1138 } 1139 1140 BlockSize = Instance->Media.BlockSize; 1141 Lba = (EFI_LBA) DivU64x32Remainder (DiskOffset, BlockSize, &BlockOffset); 1142 1143 RemainingBytes = BufferSize; 1144 1145 // Write either all the remaining bytes, or the number of bytes that bring 1146 // us up to a block boundary, whichever is less. 1147 // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next 1148 // block boundary (even if it is already on one). 1149 WriteSize = MIN (RemainingBytes, ((DiskOffset | (BlockSize - 1)) + 1) - DiskOffset); 1150 1151 do { 1152 if (WriteSize == BlockSize) { 1153 // Write a full block 1154 Status = NorFlashWriteFullBlock (Instance, Lba, Buffer, BlockSize / sizeof (UINT32)); 1155 } else { 1156 // Write a partial block 1157 Status = NorFlashWriteSingleBlock (Instance, Lba, BlockOffset, &WriteSize, Buffer); 1158 } 1159 if (EFI_ERROR (Status)) { 1160 return Status; 1161 } 1162 // Now continue writing either all the remaining bytes or single blocks. 1163 RemainingBytes -= WriteSize; 1164 Buffer = (UINT8 *) Buffer + WriteSize; 1165 Lba++; 1166 BlockOffset = 0; 1167 WriteSize = MIN (RemainingBytes, BlockSize); 1168 } while (RemainingBytes); 1169 1170 return Status; 1171 } 1172 1173 EFI_STATUS 1174 NorFlashReset ( 1175 IN NOR_FLASH_INSTANCE *Instance 1176 ) 1177 { 1178 // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode 1179 SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY); 1180 return EFI_SUCCESS; 1181 } 1182 1183 /** 1184 Fixup internal data so that EFI can be call in virtual mode. 1185 Call the passed in Child Notify event and convert any pointers in 1186 lib to virtual mode. 1187 1188 @param[in] Event The Event that is being processed 1189 @param[in] Context Event Context 1190 **/ 1191 VOID 1192 EFIAPI 1193 NorFlashVirtualNotifyEvent ( 1194 IN EFI_EVENT Event, 1195 IN VOID *Context 1196 ) 1197 { 1198 UINTN Index; 1199 1200 for (Index = 0; Index < mNorFlashDeviceCount; Index++) { 1201 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->DeviceBaseAddress); 1202 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->RegionBaseAddress); 1203 1204 // Convert BlockIo protocol 1205 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks); 1206 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks); 1207 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.Reset); 1208 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks); 1209 1210 // Convert Fvb 1211 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks); 1212 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes); 1213 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize); 1214 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress); 1215 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Read); 1216 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes); 1217 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Write); 1218 1219 if (mNorFlashInstances[Index]->ShadowBuffer != NULL) { 1220 EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->ShadowBuffer); 1221 } 1222 } 1223 1224 return; 1225 } 1226 1227 EFI_STATUS 1228 EFIAPI 1229 NorFlashInitialise ( 1230 IN EFI_HANDLE ImageHandle, 1231 IN EFI_SYSTEM_TABLE *SystemTable 1232 ) 1233 { 1234 EFI_STATUS Status; 1235 UINT32 Index; 1236 NOR_FLASH_DESCRIPTION* NorFlashDevices; 1237 BOOLEAN ContainVariableStorage; 1238 1239 Status = NorFlashPlatformInitialization (); 1240 if (EFI_ERROR(Status)) { 1241 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to initialize Nor Flash devices\n")); 1242 return Status; 1243 } 1244 1245 Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount); 1246 if (EFI_ERROR(Status)) { 1247 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to get Nor Flash devices\n")); 1248 return Status; 1249 } 1250 1251 mNorFlashInstances = AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE*) * mNorFlashDeviceCount); 1252 1253 for (Index = 0; Index < mNorFlashDeviceCount; Index++) { 1254 // Check if this NOR Flash device contain the variable storage region 1255 ContainVariableStorage = 1256 (NorFlashDevices[Index].RegionBaseAddress <= PcdGet32 (PcdFlashNvStorageVariableBase)) && 1257 (PcdGet32 (PcdFlashNvStorageVariableBase) + PcdGet32 (PcdFlashNvStorageVariableSize) <= NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size); 1258 1259 Status = NorFlashCreateInstance ( 1260 NorFlashDevices[Index].DeviceBaseAddress, 1261 NorFlashDevices[Index].RegionBaseAddress, 1262 NorFlashDevices[Index].Size, 1263 Index, 1264 NorFlashDevices[Index].BlockSize, 1265 ContainVariableStorage, 1266 &NorFlashDevices[Index].Guid, 1267 &mNorFlashInstances[Index] 1268 ); 1269 if (EFI_ERROR(Status)) { 1270 DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to create instance for NorFlash[%d]\n",Index)); 1271 } 1272 } 1273 1274 // 1275 // Register for the virtual address change event 1276 // 1277 Status = gBS->CreateEventEx ( 1278 EVT_NOTIFY_SIGNAL, 1279 TPL_NOTIFY, 1280 NorFlashVirtualNotifyEvent, 1281 NULL, 1282 &gEfiEventVirtualAddressChangeGuid, 1283 &mNorFlashVirtualAddrChangeEvent 1284 ); 1285 ASSERT_EFI_ERROR (Status); 1286 1287 return Status; 1288 } 1289