VirtNorFlash.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. /** @file NorFlash.c
  2. Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>
  3. Copyright (c) 2020, Linaro, Ltd. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Library/BaseMemoryLib.h>
  7. #include "VirtNorFlash.h"
  8. //
  9. // Global variable declarations
  10. //
  11. extern NOR_FLASH_INSTANCE **mNorFlashInstances;
  12. extern UINT32 mNorFlashDeviceCount;
  13. UINT32
  14. NorFlashReadStatusRegister (
  15. IN NOR_FLASH_INSTANCE *Instance,
  16. IN UINTN SR_Address
  17. )
  18. {
  19. // Prepare to read the status register
  20. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);
  21. return MmioRead32 (Instance->DeviceBaseAddress);
  22. }
  23. STATIC
  24. BOOLEAN
  25. NorFlashBlockIsLocked (
  26. IN NOR_FLASH_INSTANCE *Instance,
  27. IN UINTN BlockAddress
  28. )
  29. {
  30. UINT32 LockStatus;
  31. // Send command for reading device id
  32. SEND_NOR_COMMAND (BlockAddress, 2, P30_CMD_READ_DEVICE_ID);
  33. // Read block lock status
  34. LockStatus = MmioRead32 (CREATE_NOR_ADDRESS (BlockAddress, 2));
  35. // Decode block lock status
  36. LockStatus = FOLD_32BIT_INTO_16BIT (LockStatus);
  37. if ((LockStatus & 0x2) != 0) {
  38. DEBUG ((DEBUG_ERROR, "NorFlashBlockIsLocked: WARNING: Block LOCKED DOWN\n"));
  39. }
  40. return ((LockStatus & 0x1) != 0);
  41. }
  42. STATIC
  43. EFI_STATUS
  44. NorFlashUnlockSingleBlock (
  45. IN NOR_FLASH_INSTANCE *Instance,
  46. IN UINTN BlockAddress
  47. )
  48. {
  49. UINT32 LockStatus;
  50. // Raise the Task Priority Level to TPL_NOTIFY to serialise all its operations
  51. // and to protect shared data structures.
  52. // Request a lock setup
  53. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_LOCK_BLOCK_SETUP);
  54. // Request an unlock
  55. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_UNLOCK_BLOCK);
  56. // Wait until the status register gives us the all clear
  57. do {
  58. LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress);
  59. } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
  60. // Put device back into Read Array mode
  61. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_READ_ARRAY);
  62. DEBUG ((DEBUG_BLKIO, "UnlockSingleBlock: BlockAddress=0x%08x\n", BlockAddress));
  63. return EFI_SUCCESS;
  64. }
  65. EFI_STATUS
  66. NorFlashUnlockSingleBlockIfNecessary (
  67. IN NOR_FLASH_INSTANCE *Instance,
  68. IN UINTN BlockAddress
  69. )
  70. {
  71. EFI_STATUS Status;
  72. Status = EFI_SUCCESS;
  73. if (NorFlashBlockIsLocked (Instance, BlockAddress)) {
  74. Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
  75. }
  76. return Status;
  77. }
  78. /**
  79. * The following function presumes that the block has already been unlocked.
  80. **/
  81. EFI_STATUS
  82. NorFlashEraseSingleBlock (
  83. IN NOR_FLASH_INSTANCE *Instance,
  84. IN UINTN BlockAddress
  85. )
  86. {
  87. EFI_STATUS Status;
  88. UINT32 StatusRegister;
  89. Status = EFI_SUCCESS;
  90. // Request a block erase and then confirm it
  91. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_SETUP);
  92. SEND_NOR_COMMAND (BlockAddress, 0, P30_CMD_BLOCK_ERASE_CONFIRM);
  93. // Wait until the status register gives us the all clear
  94. do {
  95. StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress);
  96. } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
  97. if (StatusRegister & P30_SR_BIT_VPP) {
  98. DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: VPP Range Error\n", BlockAddress));
  99. Status = EFI_DEVICE_ERROR;
  100. }
  101. if ((StatusRegister & (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) == (P30_SR_BIT_ERASE | P30_SR_BIT_PROGRAM)) {
  102. DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Command Sequence Error\n", BlockAddress));
  103. Status = EFI_DEVICE_ERROR;
  104. }
  105. if (StatusRegister & P30_SR_BIT_ERASE) {
  106. DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Erase Error StatusRegister:0x%X\n", BlockAddress, StatusRegister));
  107. Status = EFI_DEVICE_ERROR;
  108. }
  109. if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
  110. // The debug level message has been reduced because a device lock might happen. In this case we just retry it ...
  111. DEBUG ((DEBUG_INFO, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error\n", BlockAddress));
  112. Status = EFI_WRITE_PROTECTED;
  113. }
  114. if (EFI_ERROR (Status)) {
  115. // Clear the Status Register
  116. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
  117. }
  118. // Put device back into Read Array mode
  119. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  120. return Status;
  121. }
  122. EFI_STATUS
  123. NorFlashWriteSingleWord (
  124. IN NOR_FLASH_INSTANCE *Instance,
  125. IN UINTN WordAddress,
  126. IN UINT32 WriteData
  127. )
  128. {
  129. EFI_STATUS Status;
  130. UINT32 StatusRegister;
  131. Status = EFI_SUCCESS;
  132. // Request a write single word command
  133. SEND_NOR_COMMAND (WordAddress, 0, P30_CMD_WORD_PROGRAM_SETUP);
  134. // Store the word into NOR Flash;
  135. MmioWrite32 (WordAddress, WriteData);
  136. // Wait for the write to complete and then check for any errors; i.e. check the Status Register
  137. do {
  138. // Prepare to read the status register
  139. StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress);
  140. // The chip is busy while the WRITE bit is not asserted
  141. } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
  142. // Perform a full status check:
  143. // Mask the relevant bits of Status Register.
  144. // Everything should be zero, if not, we have a problem
  145. if (StatusRegister & P30_SR_BIT_VPP) {
  146. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): VPP Range Error\n", WordAddress));
  147. Status = EFI_DEVICE_ERROR;
  148. }
  149. if (StatusRegister & P30_SR_BIT_PROGRAM) {
  150. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Program Error\n", WordAddress));
  151. Status = EFI_DEVICE_ERROR;
  152. }
  153. if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
  154. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleWord(WordAddress:0x%X): Device Protect Error\n", WordAddress));
  155. Status = EFI_DEVICE_ERROR;
  156. }
  157. if (!EFI_ERROR (Status)) {
  158. // Clear the Status Register
  159. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
  160. }
  161. return Status;
  162. }
  163. /*
  164. * Writes data to the NOR Flash using the Buffered Programming method.
  165. *
  166. * The maximum size of the on-chip buffer is 32-words, because of hardware restrictions.
  167. * Therefore this function will only handle buffers up to 32 words or 128 bytes.
  168. * To deal with larger buffers, call this function again.
  169. *
  170. * This function presumes that both the TargetAddress and the TargetAddress+BufferSize
  171. * exist entirely within the NOR Flash. Therefore these conditions will not be checked here.
  172. *
  173. * In buffered programming, if the target address not at the beginning of a 32-bit word boundary,
  174. * then programming time is doubled and power consumption is increased.
  175. * Therefore, it is a requirement to align buffer writes to 32-bit word boundaries.
  176. * i.e. the last 4 bits of the target start address must be zero: 0x......00
  177. */
  178. EFI_STATUS
  179. NorFlashWriteBuffer (
  180. IN NOR_FLASH_INSTANCE *Instance,
  181. IN UINTN TargetAddress,
  182. IN UINTN BufferSizeInBytes,
  183. IN UINT32 *Buffer
  184. )
  185. {
  186. EFI_STATUS Status;
  187. UINTN BufferSizeInWords;
  188. UINTN Count;
  189. volatile UINT32 *Data;
  190. UINTN WaitForBuffer;
  191. BOOLEAN BufferAvailable;
  192. UINT32 StatusRegister;
  193. WaitForBuffer = MAX_BUFFERED_PROG_ITERATIONS;
  194. BufferAvailable = FALSE;
  195. // Check that the target address does not cross a 32-word boundary.
  196. if ((TargetAddress & BOUNDARY_OF_32_WORDS) != 0) {
  197. return EFI_INVALID_PARAMETER;
  198. }
  199. // Check there are some data to program
  200. if (BufferSizeInBytes == 0) {
  201. return EFI_BUFFER_TOO_SMALL;
  202. }
  203. // Check that the buffer size does not exceed the maximum hardware buffer size on chip.
  204. if (BufferSizeInBytes > P30_MAX_BUFFER_SIZE_IN_BYTES) {
  205. return EFI_BAD_BUFFER_SIZE;
  206. }
  207. // Check that the buffer size is a multiple of 32-bit words
  208. if ((BufferSizeInBytes % 4) != 0) {
  209. return EFI_BAD_BUFFER_SIZE;
  210. }
  211. // Pre-programming conditions checked, now start the algorithm.
  212. // Prepare the data destination address
  213. Data = (UINT32 *)TargetAddress;
  214. // Check the availability of the buffer
  215. do {
  216. // Issue the Buffered Program Setup command
  217. SEND_NOR_COMMAND (TargetAddress, 0, P30_CMD_BUFFERED_PROGRAM_SETUP);
  218. // Read back the status register bit#7 from the same address
  219. if (((*Data) & P30_SR_BIT_WRITE) == P30_SR_BIT_WRITE) {
  220. BufferAvailable = TRUE;
  221. }
  222. // Update the loop counter
  223. WaitForBuffer--;
  224. } while ((WaitForBuffer > 0) && (BufferAvailable == FALSE));
  225. // The buffer was not available for writing
  226. if (WaitForBuffer == 0) {
  227. return EFI_DEVICE_ERROR;
  228. }
  229. // From now on we work in 32-bit words
  230. BufferSizeInWords = BufferSizeInBytes / (UINTN)4;
  231. // Write the word count, which is (buffer_size_in_words - 1),
  232. // because word count 0 means one word.
  233. SEND_NOR_COMMAND (TargetAddress, 0, (BufferSizeInWords - 1));
  234. // Write the data to the NOR Flash, advancing each address by 4 bytes
  235. for (Count = 0; Count < BufferSizeInWords; Count++, Data++, Buffer++) {
  236. MmioWrite32 ((UINTN)Data, *Buffer);
  237. }
  238. // Issue the Buffered Program Confirm command, to start the programming operation
  239. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
  240. // Wait for the write to complete and then check for any errors; i.e. check the Status Register
  241. do {
  242. StatusRegister = NorFlashReadStatusRegister (Instance, TargetAddress);
  243. // The chip is busy while the WRITE bit is not asserted
  244. } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
  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. Status = EFI_SUCCESS;
  249. if (StatusRegister & P30_SR_BIT_VPP) {
  250. DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): VPP Range Error\n", TargetAddress));
  251. Status = EFI_DEVICE_ERROR;
  252. }
  253. if (StatusRegister & P30_SR_BIT_PROGRAM) {
  254. DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Program Error\n", TargetAddress));
  255. Status = EFI_DEVICE_ERROR;
  256. }
  257. if (StatusRegister & P30_SR_BIT_BLOCK_LOCKED) {
  258. DEBUG ((DEBUG_ERROR, "NorFlashWriteBuffer(TargetAddress:0x%X): Device Protect Error\n", TargetAddress));
  259. Status = EFI_DEVICE_ERROR;
  260. }
  261. if (!EFI_ERROR (Status)) {
  262. // Clear the Status Register
  263. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
  264. }
  265. return Status;
  266. }
  267. EFI_STATUS
  268. NorFlashWriteBlocks (
  269. IN NOR_FLASH_INSTANCE *Instance,
  270. IN EFI_LBA Lba,
  271. IN UINTN BufferSizeInBytes,
  272. IN VOID *Buffer
  273. )
  274. {
  275. UINT32 *pWriteBuffer;
  276. EFI_STATUS Status;
  277. EFI_LBA CurrentBlock;
  278. UINT32 BlockSizeInWords;
  279. UINT32 NumBlocks;
  280. UINT32 BlockCount;
  281. Status = EFI_SUCCESS;
  282. // The buffer must be valid
  283. if (Buffer == NULL) {
  284. return EFI_INVALID_PARAMETER;
  285. }
  286. // We must have some bytes to read
  287. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", BufferSizeInBytes));
  288. if (BufferSizeInBytes == 0) {
  289. return EFI_BAD_BUFFER_SIZE;
  290. }
  291. // The size of the buffer must be a multiple of the block size
  292. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance->BlockSize));
  293. if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
  294. return EFI_BAD_BUFFER_SIZE;
  295. }
  296. // All blocks must be within the device
  297. NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
  298. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->LastBlock, Lba));
  299. if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
  300. DEBUG ((DEBUG_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
  301. return EFI_INVALID_PARAMETER;
  302. }
  303. BlockSizeInWords = Instance->BlockSize / 4;
  304. // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
  305. // to a proper data type, so use *ReadBuffer
  306. pWriteBuffer = (UINT32 *)Buffer;
  307. CurrentBlock = Lba;
  308. for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) {
  309. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock));
  310. Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, BlockSizeInWords);
  311. if (EFI_ERROR (Status)) {
  312. break;
  313. }
  314. }
  315. DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status));
  316. return Status;
  317. }
  318. EFI_STATUS
  319. NorFlashReadBlocks (
  320. IN NOR_FLASH_INSTANCE *Instance,
  321. IN EFI_LBA Lba,
  322. IN UINTN BufferSizeInBytes,
  323. OUT VOID *Buffer
  324. )
  325. {
  326. UINT32 NumBlocks;
  327. UINTN StartAddress;
  328. DEBUG ((
  329. DEBUG_BLKIO,
  330. "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
  331. BufferSizeInBytes,
  332. Instance->BlockSize,
  333. Instance->LastBlock,
  334. Lba
  335. ));
  336. // The buffer must be valid
  337. if (Buffer == NULL) {
  338. return EFI_INVALID_PARAMETER;
  339. }
  340. // Return if we have not any byte to read
  341. if (BufferSizeInBytes == 0) {
  342. return EFI_SUCCESS;
  343. }
  344. // The size of the buffer must be a multiple of the block size
  345. if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
  346. return EFI_BAD_BUFFER_SIZE;
  347. }
  348. // All blocks must be within the device
  349. NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
  350. if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
  351. DEBUG ((DEBUG_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
  352. return EFI_INVALID_PARAMETER;
  353. }
  354. // Get the address to start reading from
  355. StartAddress = GET_NOR_BLOCK_ADDRESS (
  356. Instance->RegionBaseAddress,
  357. Lba,
  358. Instance->BlockSize
  359. );
  360. // Put the device into Read Array mode
  361. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  362. // Readout the data
  363. CopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);
  364. return EFI_SUCCESS;
  365. }
  366. EFI_STATUS
  367. NorFlashRead (
  368. IN NOR_FLASH_INSTANCE *Instance,
  369. IN EFI_LBA Lba,
  370. IN UINTN Offset,
  371. IN UINTN BufferSizeInBytes,
  372. OUT VOID *Buffer
  373. )
  374. {
  375. UINTN StartAddress;
  376. // The buffer must be valid
  377. if (Buffer == NULL) {
  378. return EFI_INVALID_PARAMETER;
  379. }
  380. // Return if we have not any byte to read
  381. if (BufferSizeInBytes == 0) {
  382. return EFI_SUCCESS;
  383. }
  384. if (((Lba * Instance->BlockSize) + Offset + BufferSizeInBytes) > Instance->Size) {
  385. DEBUG ((DEBUG_ERROR, "NorFlashRead: ERROR - Read will exceed device size.\n"));
  386. return EFI_INVALID_PARAMETER;
  387. }
  388. // Get the address to start reading from
  389. StartAddress = GET_NOR_BLOCK_ADDRESS (
  390. Instance->RegionBaseAddress,
  391. Lba,
  392. Instance->BlockSize
  393. );
  394. // Put the device into Read Array mode
  395. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  396. // Readout the data
  397. CopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
  398. return EFI_SUCCESS;
  399. }
  400. /*
  401. Write a full or portion of a block. It must not span block boundaries; that is,
  402. Offset + *NumBytes <= Instance->BlockSize.
  403. */
  404. EFI_STATUS
  405. NorFlashWriteSingleBlock (
  406. IN NOR_FLASH_INSTANCE *Instance,
  407. IN EFI_LBA Lba,
  408. IN UINTN Offset,
  409. IN OUT UINTN *NumBytes,
  410. IN UINT8 *Buffer
  411. )
  412. {
  413. EFI_STATUS Status;
  414. UINTN CurOffset;
  415. UINTN BlockSize;
  416. UINTN BlockAddress;
  417. UINT8 *OrigData;
  418. DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));
  419. // Check we did get some memory. Buffer is BlockSize.
  420. if (Instance->ShadowBuffer == NULL) {
  421. DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
  422. return EFI_DEVICE_ERROR;
  423. }
  424. // Cache the block size to avoid de-referencing pointers all the time
  425. BlockSize = Instance->BlockSize;
  426. // The write must not span block boundaries.
  427. // We need to check each variable individually because adding two large values together overflows.
  428. if ((Offset >= BlockSize) ||
  429. (*NumBytes > BlockSize) ||
  430. ((Offset + *NumBytes) > BlockSize))
  431. {
  432. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));
  433. return EFI_BAD_BUFFER_SIZE;
  434. }
  435. // We must have some bytes to write
  436. if (*NumBytes == 0) {
  437. DEBUG ((DEBUG_ERROR, "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize));
  438. return EFI_BAD_BUFFER_SIZE;
  439. }
  440. // Pick P30_MAX_BUFFER_SIZE_IN_BYTES (== 128 bytes) as a good start for word
  441. // operations as opposed to erasing the block and writing the data regardless
  442. // if an erase is really needed. It looks like most individual NV variable
  443. // writes are smaller than 128 bytes.
  444. // To avoid pathological cases were a 2 byte write is disregarded because it
  445. // occurs right at a 128 byte buffered write alignment boundary, permit up to
  446. // twice the max buffer size, and perform two writes if needed.
  447. if ((*NumBytes + (Offset & BOUNDARY_OF_32_WORDS)) <= (2 * P30_MAX_BUFFER_SIZE_IN_BYTES)) {
  448. // Check to see if we need to erase before programming the data into NOR.
  449. // If the destination bits are only changing from 1s to 0s we can just write.
  450. // After a block is erased all bits in the block is set to 1.
  451. // If any byte requires us to erase we just give up and rewrite all of it.
  452. // Read the old version of the data into the shadow buffer
  453. Status = NorFlashRead (
  454. Instance,
  455. Lba,
  456. Offset & ~BOUNDARY_OF_32_WORDS,
  457. (*NumBytes | BOUNDARY_OF_32_WORDS) + 1,
  458. Instance->ShadowBuffer
  459. );
  460. if (EFI_ERROR (Status)) {
  461. return EFI_DEVICE_ERROR;
  462. }
  463. // Make OrigData point to the start of the old version of the data inside
  464. // the word aligned buffer
  465. OrigData = Instance->ShadowBuffer + (Offset & BOUNDARY_OF_32_WORDS);
  466. // Update the buffer containing the old version of the data with the new
  467. // contents, while checking whether the old version had any bits cleared
  468. // that we want to set. In that case, we will need to erase the block first.
  469. for (CurOffset = 0; CurOffset < *NumBytes; CurOffset++) {
  470. if (~OrigData[CurOffset] & Buffer[CurOffset]) {
  471. goto DoErase;
  472. }
  473. OrigData[CurOffset] = Buffer[CurOffset];
  474. }
  475. //
  476. // Write the updated buffer to NOR.
  477. //
  478. BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize);
  479. // Unlock the block if we have to
  480. Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
  481. if (EFI_ERROR (Status)) {
  482. goto Exit;
  483. }
  484. Status = NorFlashWriteBuffer (
  485. Instance,
  486. BlockAddress + (Offset & ~BOUNDARY_OF_32_WORDS),
  487. P30_MAX_BUFFER_SIZE_IN_BYTES,
  488. Instance->ShadowBuffer
  489. );
  490. if (EFI_ERROR (Status)) {
  491. goto Exit;
  492. }
  493. if ((*NumBytes + (Offset & BOUNDARY_OF_32_WORDS)) > P30_MAX_BUFFER_SIZE_IN_BYTES) {
  494. BlockAddress += P30_MAX_BUFFER_SIZE_IN_BYTES;
  495. Status = NorFlashWriteBuffer (
  496. Instance,
  497. BlockAddress + (Offset & ~BOUNDARY_OF_32_WORDS),
  498. P30_MAX_BUFFER_SIZE_IN_BYTES,
  499. Instance->ShadowBuffer + P30_MAX_BUFFER_SIZE_IN_BYTES
  500. );
  501. }
  502. Exit:
  503. // Put device back into Read Array mode
  504. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  505. return Status;
  506. }
  507. DoErase:
  508. // Read NOR Flash data into shadow buffer
  509. Status = NorFlashReadBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);
  510. if (EFI_ERROR (Status)) {
  511. // Return one of the pre-approved error statuses
  512. return EFI_DEVICE_ERROR;
  513. }
  514. // Put the data at the appropriate location inside the buffer area
  515. CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
  516. // Write the modified buffer back to the NorFlash
  517. Status = NorFlashWriteBlocks (Instance, Lba, BlockSize, Instance->ShadowBuffer);
  518. if (EFI_ERROR (Status)) {
  519. // Return one of the pre-approved error statuses
  520. return EFI_DEVICE_ERROR;
  521. }
  522. return EFI_SUCCESS;
  523. }
  524. EFI_STATUS
  525. NorFlashReset (
  526. IN NOR_FLASH_INSTANCE *Instance
  527. )
  528. {
  529. // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
  530. SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
  531. return EFI_SUCCESS;
  532. }
  533. /**
  534. Fixup internal data so that EFI can be call in virtual mode.
  535. Call the passed in Child Notify event and convert any pointers in
  536. lib to virtual mode.
  537. @param[in] Event The Event that is being processed
  538. @param[in] Context Event Context
  539. **/
  540. VOID
  541. EFIAPI
  542. NorFlashVirtualNotifyEvent (
  543. IN EFI_EVENT Event,
  544. IN VOID *Context
  545. )
  546. {
  547. UINTN Index;
  548. for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
  549. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress);
  550. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress);
  551. // Convert Fvb
  552. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
  553. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
  554. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
  555. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
  556. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read);
  557. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
  558. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write);
  559. if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
  560. EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowBuffer);
  561. }
  562. }
  563. return;
  564. }